got-portable-0.119/0000775000175000017500000000000015066537276007707 5got-portable-0.119/gotctl/0000775000175000017500000000000015066537274011201 5got-portable-0.119/gotctl/gotctl.80000664000175000017500000000461615066535721012510 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTCTL 8 .Os .Sh NAME .Nm gotctl .Nd control the Game of Trees Daemon .Sh SYNOPSIS .Nm .Op Fl hV .Op Fl f Ar path .Ar command .Op Ar arg ... .Sh DESCRIPTION .Nm controls the .Xr gotd 8 daemon. .Pp The options for .Nm are as follows: .Bl -tag -width Ds .It Fl h Display usage information and exit immediately. .It Fl f Ar path Set the .Ar path to the unix socket which .Xr gotd 8 is listening on. If not specified, the default path .Pa /var/run/gotd.sock will be used. .It Fl V , -version Display program version and exit immediately. .El .Pp The commands for .Nm are as follows: .Bl -tag -width Ds .It Cm info Display information about a running .Xr gotd 8 instance. This operation requires root privileges. .It Cm stop Stop a running .Xr gotd 8 instance. This operation requires root privileges. .It Cm reload Oo Fl c Ar config-file Oc Oo Fl n Oc Oo Fl s Ar secrets Oc Reload a running .Xr gotd 8 instance. .Xr gotd 8 will relaunch with an updated configuration read from the provided configuration files. The previous instance of .Xr gotd 8 will continue to serve existing client connections and then exit. .Pp This operation requires root privileges. .Pp The options for .Cm gotctl reload are as follows: .Bl -tag -width Ds .It Fl f Ar config-file Set the path to the configuration file. If not specified, the file .Pa /etc/gotd.conf will be used. .It Fl n Only check the configuration files for validity. .It Fl s Ar secrets Set the path to the secrets file. If not specified, the file .Pa /etc/gotd-secrets.conf will be used if it exists. .El .Sh SEE ALSO .Xr got 1 , .Xr gotd 8 .Sh AUTHORS .An Stefan Sperling Aq Mt stsp@openbsd.org got-portable-0.119/gotctl/Makefile.am0000664000175000017500000000160115066536113013142 bin_PROGRAMS = gotctl include $(top_builddir)/Makefile.common AM_CPPFLAGS += -I$(top_builddir)/gotd gotctl_SOURCES = gotctl.c \ $(top_srcdir)/gotd/imsg.c \ $(top_srcdir)/gotd/parse.y \ $(top_srcdir)/gotd/secrets.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotd_imsg.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/reference_parse.c gotctl_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotctl.8 man8_MANS = gotctl.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/gotd -lopenbsd-compat -lm LDADD += $(libutil_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ $(libevent_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libutil_CFLAGS) \ $(libbsd_CFLAGS) \ $(zlib_CFLAGS) \ $(libevent_CFLAGS) got-portable-0.119/gotctl/gotctl.c0000664000175000017500000003522515066536113012557 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_version.h" #include "got_path.h" #include "got_lib_gitproto.h" #include "gotd.h" #include "secrets.h" #include "log.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #define GOTCTL_CMD_INFO "info" #define GOTCTL_CMD_STOP "stop" struct gotctl_cmd { const char *cmd_name; const struct got_error *(*cmd_main)(int, char *[], int); void (*cmd_usage)(void); }; __dead static void usage(int, int); __dead static void usage_info(void); __dead static void usage_stop(void); __dead static void usage_reload(void); static const struct got_error* cmd_info(int, char *[], int); static const struct got_error* cmd_stop(int, char *[], int); static const struct got_error* cmd_reload(int, char *[], int); static const struct gotctl_cmd gotctl_commands[] = { { "info", cmd_info, usage_info }, { "stop", cmd_stop, usage_stop }, { "reload", cmd_reload, usage_reload }, }; __dead static void usage_info(void) { fprintf(stderr, "usage: %s info\n", getprogname()); exit(1); } static const struct got_error * show_info(struct imsg *imsg) { struct gotd_imsg_info info; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(info)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&info, imsg->data, sizeof(info)); printf("gotd PID: %d\n", info.pid); printf("verbosity: %d\n", info.verbosity); printf("number of repositories: %d\n", info.nrepos); printf("number of connected clients: %d\n", info.nclients); return NULL; } static const struct got_error * show_repo_info(struct imsg *imsg) { struct gotd_imsg_info_repo info; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(info)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&info, imsg->data, sizeof(info)); printf("repository \"%s\", path %s\n", info.repo_name, info.repo_path); return NULL; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = localtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * show_client_info(struct imsg *imsg) { struct gotd_imsg_info_client info; size_t datalen; char *datestr; char datebuf[26]; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(info)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&info, imsg->data, sizeof(info)); datestr = get_datestr(&info.time_connected, datebuf); printf("client UID %d, GID %d, ", info.euid, info.egid); if (info.session_child_pid) printf("session PID %ld, ", (long)info.session_child_pid); if (info.repo_child_pid) printf("repo PID %ld, ", (long)info.repo_child_pid); if (info.is_writing) { printf("writing to repository \"%s\"%s%s\n", info.repo_name, datestr ? " since " : "", datestr ? datestr : ""); } else { printf("reading from repository \"%s\"%s%s\n", info.repo_name, datestr ? " since " : "", datestr ? datestr : ""); } return NULL; } static const struct got_error * cmd_info(int argc, char *argv[], int gotd_sock) { const struct got_error *err; struct imsgbuf ibuf; struct imsg imsg; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); #ifndef PROFILE if (pledge("stdio", NULL) == -1) return got_error_from_errno("pledge"); #endif if (imsgbuf_init(&ibuf, gotd_sock) == -1) return got_error_from_errno("imsgbuf_init"); if (imsg_compose(&ibuf, GOTD_IMSG_INFO, 0, 0, -1, NULL, 0) == -1) { imsgbuf_clear(&ibuf); return got_error_from_errno("imsg_compose INFO"); } err = gotd_imsg_flush(&ibuf); while (err == NULL) { err = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_EOF) err = NULL; break; } switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_INFO: err = show_info(&imsg); break; case GOTD_IMSG_INFO_REPO: err = show_repo_info(&imsg); break; case GOTD_IMSG_INFO_CLIENT: err = show_client_info(&imsg); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } imsgbuf_clear(&ibuf); return err; } __dead static void usage_stop(void) { fprintf(stderr, "usage: %s stop\n", getprogname()); exit(1); } static const struct got_error * cmd_stop(int argc, char *argv[], int gotd_sock) { const struct got_error *err; struct imsgbuf ibuf; struct imsg imsg; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); #ifndef PROFILE if (pledge("stdio", NULL) == -1) return got_error_from_errno("pledge"); #endif if (imsgbuf_init(&ibuf, gotd_sock) == -1) return got_error_from_errno("imsgbuf_init"); if (imsg_compose(&ibuf, GOTD_IMSG_STOP, 0, 0, -1, NULL, 0) == -1) { imsgbuf_clear(&ibuf); return got_error_from_errno("imsg_compose STOP"); } err = gotd_imsg_flush(&ibuf); while (err == NULL) { err = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_EOF) err = NULL; break; } switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } imsgbuf_clear(&ibuf); return err; } __dead static void usage_reload(void) { fprintf(stderr, "usage: %s reload [-c config-file] [-s secrets]\n", getprogname()); exit(1); } static const struct got_error * check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) return got_error_from_errno2("stat", fname); if (st.st_uid != 0) { return got_error_fmt(GOT_ERR_UID, "secrets file %s must be owned by root", fname); } if (st.st_gid != 0) { return got_error_fmt(GOT_ERR_GID, "secrets file %s must be owned by group wheel/root", fname); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { return got_error_fmt(GOT_ERR_GID, "secrets file %s must not be group writable or world " "readable/writable", fname); } return NULL; } static const struct got_error * cmd_reload(int argc, char *argv[], int gotd_sock) { const struct got_error *err = NULL; struct imsgbuf ibuf; struct gotd gotd; struct gotd_secrets *secrets = NULL; struct imsg imsg; char *confpath = NULL, *secretspath = NULL; int ch, conf_fd = -1, secrets_fd = -1; int no_action = 0; log_init(1, LOG_DAEMON); /* log to stderr . */ #ifndef PROFILE if (pledge("stdio rpath sendfd unveil", NULL) == -1) return got_error_from_errno("pledge"); #endif while ((ch = getopt(argc, argv, "c:ns:")) != -1) { switch (ch) { case 'c': if (unveil(optarg, "r") != 0) return got_error_from_errno("unveil"); confpath = realpath(optarg, NULL); if (confpath == NULL) { return got_error_from_errno2("realpath", optarg); } break; case 'n': no_action = 1; break; case 's': if (unveil(optarg, "r") != 0) return got_error_from_errno("unveil"); secretspath = realpath(optarg, NULL); if (secretspath == NULL) { return got_error_from_errno2("realpath", optarg); } break; default: usage_reload(); /* NOTREACHED */ } } if (confpath == NULL) { confpath = strdup(GOTD_CONF_PATH); if (confpath == NULL) return got_error_from_errno("strdup"); } if (unveil(confpath, "r") != 0) return got_error_from_errno("unveil"); if (unveil(secretspath ? secretspath : GOTD_SECRETS_PATH, "r") != 0) return got_error_from_errno("unveil"); if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); secrets_fd = open(secretspath ? secretspath : GOTD_SECRETS_PATH, O_RDONLY | O_NOFOLLOW); if (secrets_fd == -1) { if (secretspath != NULL || errno != ENOENT) { return got_error_from_errno2("open", secretspath ? secretspath : GOTD_SECRETS_PATH); } } else if (secretspath == NULL) { secretspath = strdup(GOTD_SECRETS_PATH); if (secretspath == NULL) return got_error_from_errno("strdup"); } conf_fd = open(confpath, O_RDONLY | O_NOFOLLOW); if (conf_fd == -1) return got_error_from_errno2("open", confpath); if (secrets_fd != -1) { int fd; FILE *fp; err = check_file_secrecy(secrets_fd, secretspath); if (err) goto done; fd = dup(secrets_fd); if (fd == -1) { err = got_error_from_errno("dup"); goto done; } fp = fdopen(fd, "r"); if (fp == NULL) { err = got_error_from_errno2("fdopen", secretspath); close(fd); goto done; } err = gotd_secrets_parse(secretspath, fp, &secrets); fclose(fp); if (err) { err = got_error_fmt(GOT_ERR_PARSE_CONFIG, "failed to parse secrets file %s: %s", secretspath, err->msg); goto done; } } if (gotd_parse_config(confpath, conf_fd, GOTD_PROC_GOTCTL, secrets, &gotd) != 0) { /* Errors were already printed. Silence this one. */ err = got_error_msg(GOT_ERR_PARSE_CONFIG, ""); goto done; } if (no_action) { fprintf(stderr, "configuration OK\n"); goto done; } #ifndef PROFILE if (pledge("stdio sendfd", NULL) == -1) { err = got_error_from_errno("pledge"); goto done; } #endif if (secrets_fd != -1 && lseek(secrets_fd, 0L, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", secretspath); goto done; } if (lseek(conf_fd, 0L, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", confpath); goto done; } if (imsgbuf_init(&ibuf, gotd_sock) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&ibuf); if (secrets_fd != -1) { if (imsg_compose(&ibuf, GOTD_IMSG_RELOAD_SECRETS, 0, 0, secrets_fd, secretspath ? secretspath : GOTD_SECRETS_PATH, secretspath ? strlen(secretspath) : strlen(GOTD_SECRETS_PATH)) == -1) { err = got_error_from_errno("imsg_compose " "RELOAD_SECRETS"); imsgbuf_clear(&ibuf); goto done; } secrets_fd = -1; } else { if (imsg_compose(&ibuf, GOTD_IMSG_RELOAD_SECRETS, 0, 0, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg_compose " "RELOAD_SECRETS"); imsgbuf_clear(&ibuf); goto done; } } if (imsg_compose(&ibuf, GOTD_IMSG_RELOAD, 0, 0, conf_fd, confpath, strlen(confpath)) == -1) { err = got_error_from_errno("imsg_compose RELOAD"); imsgbuf_clear(&ibuf); goto done; } conf_fd = -1; err = gotd_imsg_flush(&ibuf); if (err) goto done; #ifndef PROFILE if (pledge("stdio", NULL) == -1) { err = got_error_from_errno("pledge"); goto done; } #endif while (err == NULL) { err = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_EOF) err = NULL; break; } switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } imsgbuf_clear(&ibuf); done: free(confpath); free(secretspath); if (conf_fd != -1 && close(conf_fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (secrets_fd != -1 && close(secrets_fd) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(gotctl_commands); i++) { const struct gotctl_cmd *cmd = &gotctl_commands[i]; fprintf(fp, " %s", cmd->cmd_name); } fputc('\n', fp); } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] [-f path] command [arg ...]\n", getprogname()); if (hflag) list_commands(fp); exit(status); } static int connect_gotd(const char *socket_path) { int gotd_sock = -1; struct sockaddr_un sun; if (unveil(socket_path, "w") != 0) err(1, "unveil %s", socket_path); if ((gotd_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; if (strlcpy(sun.sun_path, socket_path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) errx(1, "gotd socket path too long"); if (connect(gotd_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) err(1, "connect: %s", socket_path); #ifndef PROFILE if (pledge("stdio rpath sendfd unveil", NULL) == -1) err(1, "pledge"); #endif return gotd_sock; } int main(int argc, char *argv[]) { const struct gotctl_cmd *cmd; int gotd_sock = -1, i; int ch; int hflag = 0, Vflag = 0; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; const char *socket_path = GOTD_UNIX_SOCKET; setlocale(LC_CTYPE, ""); #ifndef PROFILE if (pledge("stdio rpath unix sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt_long(argc, argv, "+hf:V", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'f': socket_path = optarg; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc <= 0) usage(hflag, hflag ? 0 : 1); for (i = 0; i < nitems(gotctl_commands); i++) { const struct got_error *error; cmd = &gotctl_commands[i]; if (strncmp(cmd->cmd_name, argv[0], strlen(argv[0])) != 0) continue; if (hflag) cmd->cmd_usage(); #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) err(1, "unveil", "gmon.out"); #endif gotd_sock = connect_gotd(socket_path); if (gotd_sock == -1) return 1; error = cmd->cmd_main(argc, argv, gotd_sock); close(gotd_sock); if (error && error->msg[0] != '\0') { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]); list_commands(stderr); return 1; } got-portable-0.119/gotctl/Makefile.in0000664000175000017500000007131015066537207013164 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = gotctl$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotctl ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man8dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gotctl_OBJECTS = gotctl.$(OBJEXT) \ $(top_builddir)/gotd/imsg.$(OBJEXT) \ $(top_builddir)/gotd/parse.$(OBJEXT) \ $(top_builddir)/gotd/secrets.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gotd_imsg.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) gotctl_OBJECTS = $(am_gotctl_OBJECTS) gotctl_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/gotd/$(DEPDIR)/imsg.Po \ $(top_builddir)/gotd/$(DEPDIR)/parse.Po \ $(top_builddir)/gotd/$(DEPDIR)/secrets.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ ./$(DEPDIR)/gotctl.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gotctl_SOURCES) DIST_SOURCES = $(gotctl_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man8_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap $(top_srcdir)/gotd/parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_builddir)/gotd $(libutil_CFLAGS) \ $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libevent_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ gotctl_SOURCES = gotctl.c \ $(top_srcdir)/gotd/imsg.c \ $(top_srcdir)/gotd/parse.y \ $(top_srcdir)/gotd/secrets.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotd_imsg.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/reference_parse.c gotctl_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotctl.8 man8_MANS = gotctl.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/gotd \ -lopenbsd-compat -lm $(libutil_LIBS) $(zlib_LIBS) \ $(libbsd_LIBS) $(libevent_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotctl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotctl/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: -$(am__rm_f) $(bin_PROGRAMS) $(top_builddir)/gotd/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd @: >>$(top_builddir)/gotd/$(am__dirstamp) $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd/$(DEPDIR) @: >>$(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/gotd/imsg.$(OBJEXT): \ $(top_builddir)/gotd/$(am__dirstamp) \ $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/gotd/parse.$(OBJEXT): \ $(top_builddir)/gotd/$(am__dirstamp) \ $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/gotd/secrets.$(OBJEXT): \ $(top_builddir)/gotd/$(am__dirstamp) \ $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotd_imsg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gotctl$(EXEEXT): $(gotctl_OBJECTS) $(gotctl_DEPENDENCIES) $(EXTRA_gotctl_DEPENDENCIES) @rm -f gotctl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotctl_OBJECTS) $(gotctl_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/gotd/*.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/gotd/$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/gotd/$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/gotd/$(DEPDIR)/secrets.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotctl.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/gotd/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -$(am__rm_f) $(top_srcdir)/gotd/parse.c clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/imsg.Po -rm -f $(top_builddir)/gotd/$(DEPDIR)/parse.Po -rm -f $(top_builddir)/gotd/$(DEPDIR)/secrets.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/gotctl.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/imsg.Po -rm -f $(top_builddir)/gotd/$(DEPDIR)/parse.Po -rm -f $(top_builddir)/gotd/$(DEPDIR)/secrets.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/gotctl.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man8 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man8 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man8 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotsh/0000775000175000017500000000000015066537274011031 5got-portable-0.119/gotsh/Makefile.am0000664000175000017500000000221715066536113012776 bin_PROGRAMS = gotsh include $(top_builddir)/Makefile.common AM_CPPFLAGS += -I$(top_builddir)/gotd AM_CPPFLAGS += -I$(top_builddir)/gotwebd gotsh_SOURCES = gotsh.c \ $(top_srcdir)/gotd/imsg.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/gotd_imsg.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/serve.c gotsh_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotsh.1 man1_MANS = gotsh.1 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/gotd -lopenbsd-compat -lm LDADD += $(libutil_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ $(libevent_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libutil_CFLAGS) \ $(libbsd_CFLAGS) \ $(zlib_CFLAGS) \ $(libevent_CFLAGS) # Disable for now (per upstream)... # #install-exec-hook: # ln -sf $(prefix)/bin/gotsh $(prefix)/bin/git-receive-pack # ln -sf $(prefix)/bin/gotsh $(prefix)/bin/git-upload-pack got-portable-0.119/gotsh/gotsh.c0000664000175000017500000001764715066536113012247 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_serve.h" #include "got_path.h" #include "got_reference.h" #include "got_lib_dial.h" #include "got_lib_poll.h" #include "gotd.h" #include "gotwebd.h" static int chattygot; __dead static void usage(void) { fprintf(stderr, "usage: %s -c '%s|%s repository-path'\n", getprogname(), GOT_DIAL_CMD_SEND, GOT_DIAL_CMD_FETCH); fprintf(stderr, " %s -c 'weblogin [hostname]'\n", getprogname()); exit(1); } static const struct got_error * apply_unveil(const char *unix_socket_path) { #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (unveil(unix_socket_path, "w") != 0) return got_error_from_errno2("unveil", unix_socket_path); if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } /* Read session URL from gotwebd's auth socket and send it to the client. */ static const struct got_error * weblogin(FILE *out, int sock, const char *hostname) { const struct got_error *err = NULL; FILE *fp; int ret; char *line = NULL; size_t linesize; ssize_t linelen; fp = fdopen(sock, "w+"); if (fp == NULL) return got_error_from_errno("fdopen"); ret = fprintf(fp, "login%s%s\n", hostname != NULL ? " " : "", hostname != NULL ? hostname : ""); if (ret < 0) { err = got_error_from_errno("fprintf"); goto done; } /* * gotwebd will return "ok URL", likewise terminated by \n, * or might return an arbitrary error message + \n. * We don't know how long this line will be, so keep reading * in chunks until we have read all of it. * For forward compatibilty, ignore any trailing lines received. */ linelen = getline(&line, &linesize, fp); if (linelen == -1) { err = got_error(GOT_ERR_EOF); if (ferror(fp)) err = got_error_from_errno("getline"); goto done; } if (strncmp(line, "ok ", 3) == 0) { fprintf(out, "Login successful. Please visit the following " "URL within the next %d minutes: %s\n", GOTWEBD_LOGIN_TIMEOUT / 60, line + 3); goto done; } if (strncmp(line, "err ", 4) == 0) { err = got_error_fmt(GOT_ERR_LOGIN_FAILED, "%s", line + 4); goto done; } err = got_error(GOT_ERR_UNKNOWN_COMMAND); done: if (line != NULL) free(line); if (fp != NULL && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * parse_weblogin_command(char **hostname, char *cmd) { size_t len, cmdlen; *hostname = NULL; len = strlen(cmd); while (len > 0 && isspace(cmd[len - 1])) cmd[--len] = '\0'; if (len == 0) return got_error(GOT_ERR_BAD_PACKET); if (len >= strlen(GOTWEBD_LOGIN_CMD) && strncmp(cmd, GOTWEBD_LOGIN_CMD, strlen(GOTWEBD_LOGIN_CMD)) == 0) cmdlen = strlen(GOTWEBD_LOGIN_CMD); else return got_error(GOT_ERR_BAD_PACKET); /* The hostname parameter is optional. */ if (len == cmdlen) return NULL; if (len <= cmdlen + 1 || cmd[cmdlen] != ' ') return got_error(GOT_ERR_BAD_PACKET); if (memchr(&cmd[cmdlen + 1], '\0', len - cmdlen) == NULL) return got_error(GOT_ERR_BAD_PACKET); /* Forbid linefeeds in hostnames. We use \n as internal terminator. */ if (memchr(&cmd[cmdlen + 1], '\n', len - cmdlen) != NULL) return got_error(GOT_ERR_BAD_PACKET); *hostname = strdup(&cmd[cmdlen + 1]); if (*hostname == NULL) return got_error_from_errno("strdup"); /* Deny an empty hostname. */ if ((*hostname)[0] == '\0') { free(*hostname); *hostname = NULL; return got_error(GOT_ERR_BAD_PACKET); } /* Deny overlong hostnames ,*/ if (len - cmdlen > _POSIX_HOST_NAME_MAX) return got_error_fmt(GOT_ERR_NO_SPACE, "hostname length exceeds %d bytes", _POSIX_HOST_NAME_MAX); /* * TODO: More hostname verification? In any case, the provided * value will have to match a string obtained from gotwebd.conf. */ return NULL; } int main(int argc, char *argv[]) { const struct got_error *error; const char *unix_socket_path; int sock = -1; struct sockaddr_un sun; char *gitcmd = NULL, *command = NULL, *repo_path = NULL; char *hostname = NULL; int do_weblogin = 0; #ifndef PROFILE if (pledge("stdio recvfd unix unveil", NULL) == -1) err(1, "pledge"); #endif if (strcmp(argv[0], GOTWEBD_LOGIN_CMD) == 0) { if (argc != 1 && argc != 2) usage(); unix_socket_path = getenv("GOTWEBD_LOGIN_SOCKET"); if (unix_socket_path == NULL) unix_socket_path = GOTWEBD_LOGIN_SOCKET; error = apply_unveil(unix_socket_path); if (error) goto done; if (argc == 2) { hostname = strdup(argv[1]); if (hostname == NULL) { error = got_error_from_errno("strdup"); goto done; } } do_weblogin = 1; } else if (strcmp(argv[0], GOT_DIAL_CMD_SEND) == 0 || strcmp(argv[0], GOT_DIAL_CMD_FETCH) == 0) { if (argc != 2) usage(); unix_socket_path = getenv("GOTD_UNIX_SOCKET"); if (unix_socket_path == NULL) unix_socket_path = GOTD_UNIX_SOCKET; error = apply_unveil(unix_socket_path); if (error) goto done; if (asprintf(&gitcmd, "%s %s", argv[0], argv[1]) == -1) err(1, "asprintf"); error = got_dial_parse_command(&command, &repo_path, gitcmd); if (error) { if (error->code == GOT_ERR_BAD_PACKET) usage(); goto done; } } else if (argc == 3 && strcmp(argv[1], "-c") == 0) { if (strncmp(argv[2], GOTWEBD_LOGIN_CMD, strlen(GOTWEBD_LOGIN_CMD)) == 0) { unix_socket_path = getenv("GOTWEBD_LOGIN_SOCKET"); if (unix_socket_path == NULL) unix_socket_path = GOTWEBD_LOGIN_SOCKET; error = apply_unveil(unix_socket_path); if (error) goto done; error = parse_weblogin_command(&hostname, argv[2]); if (error) { if (error->code == GOT_ERR_BAD_PACKET) usage(); goto done; } do_weblogin = 1; } else { unix_socket_path = getenv("GOTD_UNIX_SOCKET"); if (unix_socket_path == NULL) unix_socket_path = GOTD_UNIX_SOCKET; error = apply_unveil(unix_socket_path); if (error) goto done; error = got_dial_parse_command(&command, &repo_path, argv[2]); if (error) { if (error->code == GOT_ERR_BAD_PACKET) usage(); goto done; } } } else usage(); if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket"); memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; if (strlcpy(sun.sun_path, unix_socket_path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) errx(1, "gotd socket path too long"); if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) err(1, "connect: %s", unix_socket_path); if (do_weblogin) { #ifndef PROFILE if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif error = weblogin(stdout, sock, hostname); } else { #ifndef PROFILE if (pledge("stdio recvfd", NULL) == -1) err(1, "pledge"); #endif error = got_serve(STDIN_FILENO, STDOUT_FILENO, command, repo_path, sock, chattygot); } done: free(gitcmd); free(command); free(repo_path); free(hostname); if (sock != -1) close(sock); if (error) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } got-portable-0.119/gotsh/gotsh.10000664000175000017500000001217515066535721012160 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTSH 1 .Os .Sh NAME .Nm gotsh .Nd Game of Trees Shell .Sh SYNOPSIS .Nm Fl c Sq Cm git-receive-pack Ar repository-path .Nm Fl c Sq Cm git-upload-pack Ar repository-path .Nm Fl c Sq Cm weblogin Oo Ar hostname Oc .Sh DESCRIPTION .Nm is the network-facing interface to .Xr gotd 8 . It implements the server-side part of the Git network protocol used by .Xr git 1 and .Xr got 1 . .Pp .Nm is not an interactive shell. .Nm is intended to be configured as the login shell of Git repository user accounts on servers running .Xr gotd 8 . If users require a different login shell, .Nm can be installed in the command search path under the names .Cm git-receive-pack and .Cm git-upload-pack , or .Xr gitwrapper 1 can be used to select the appropriate command to run automatically. .Pp The users can then interact with .Xr gotd 8 over the network. When users invoke commands such as .Cm got send and .Cm got fetch on client machines, .Xr got 1 will connect to the server with .Xr ssh 1 . .Nm will facilitate communication between .Xr gotd 8 running on the server machine and the .Xr got 1 or .Xr git 1 program running on the client machine. .Pp Users running .Nm should not have access to Git repositories by means other than accessing the unix socket of .Xr gotd 8 via .Nm . .Pp The .Cm weblogin command provides user authentication for .Xr gotwebd 8 . .Nm will connect to .Xr gotwebd 8 and obtain a login URL which allows browsing private repositories the user has been granted read access to in .Xr gotwebd.conf 5 . If multiple servers are declared in .Xr gotwebd.conf 5 the .Ar hostname parameter is required and indicates the desired virtual host to use in the URL. If no .Ar hostname is specified and only one server is declared in .Xr gotwebd.conf 5 then the name of this server will be used in the URL. .Pp It is recommended to restrict .Xr ssh 1 features available to users of .Nm . See the .Sx EXAMPLES section for details. .Sh ENVIRONMENT .Bl -tag -width GOTD_UNIX_SOCKET .It Ev GOTD_UNIX_SOCKET Set the path to the unix socket which .Xr gotd 8 is listening on. If not specified, the default path .Pa /var/run/gotd.sock will be used. .El .Sh EXAMPLES .Xr sshd_config 5 directives such as the following are recommended to protect the server machine and any systems reachable from it, especially if anonymous users are allowed to connect: .Bd -literal -offset indent Match User developer DisableForwarding yes PermitTTY no .Ed .Pp It can be convenient to add all relevant users to a common group, such as .Dq developers , and then use this group as the Match criteria: .Bd -literal -offset indent Match Group developers DisableForwarding yes PermitTTY no .Ed .Pp Anonymous users can be given public read-only access by using a .Xr gotd.conf 5 access rule such as the following: .Bd -literal -offset indent repository "public" { path "/var/git/public.git" permit ro anonymous } .Ed .Pp The anonymous user account should have a publicly known password, or can be set up with an empty password in which case the user's .Xr vipw 8 entry would look similar to this example: .Bd -literal anonymous::1002:1002::0:0:Anonymous:/home/anonymous:/usr/local/bin/gotsh .Ed .Pp Use of an empty password must be explicitly allowed in .Xr sshd_config 5 : .Bd -literal -offset indent Match User anonymous PasswordAuthentication yes PermitEmptyPasswords yes DisableForwarding yes PermitTTY no .Ed .Pp Obtain a .Xr gotwebd 8 login URL for got.example.com: .Bd -literal -offset indent $ ssh got.example.com weblogin .Ed .Pp If the web server at got.example.com serves virtual hosts then two hostnames must be provided. One for .Xr ssh 1 to connect to, and another to identify the virtual host served by .Xr gotwebd 8 : .Bd -literal -offset indent $ ssh got.example.com weblogin got.example.com .Ed .Pp In practice both hostnames will often be the same, but this is not guaranteed. There is no reliable way determine the desired virtual host automatically. An .Xr ssh_config 5 entry like the following can save some typing: .Bd -literal -offset indent Host weblogin Hostname got.example.com RemoteCommand weblogin %h .Ed .Pp The following command is now equivalent to the above: .Bd -literal -offset indent $ ssh weblogin .Ed .Ed .Sh SEE ALSO .Xr gitwrapper 1 , .Xr got 1 , .Xr ssh 1 , .Xr gotd.conf 5 , .Xr gotwebd.conf 5 , .Xr sshd_config 5 , .Xr gotd 8 , .Xr gotwebd 8 .Sh AUTHORS .An Stefan Sperling Aq Mt stsp@openbsd.org got-portable-0.119/gotsh/Makefile.in0000664000175000017500000007227015066537207013022 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = gotsh$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotsh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gotsh_OBJECTS = gotsh.$(OBJEXT) $(top_builddir)/gotd/imsg.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitproto.$(OBJEXT) \ $(top_builddir)/lib/gotd_imsg.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/serve.$(OBJEXT) gotsh_OBJECTS = $(am_gotsh_OBJECTS) gotsh_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/gotd/$(DEPDIR)/imsg.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitproto.Po \ $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/serve.Po ./$(DEPDIR)/gotsh.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(gotsh_SOURCES) DIST_SOURCES = $(gotsh_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_builddir)/gotd \ -I$(top_builddir)/gotwebd $(libutil_CFLAGS) $(libbsd_CFLAGS) \ $(zlib_CFLAGS) $(libevent_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ gotsh_SOURCES = gotsh.c \ $(top_srcdir)/gotd/imsg.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/gotd_imsg.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/serve.c gotsh_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotsh.1 man1_MANS = gotsh.1 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/gotd \ -lopenbsd-compat -lm $(libutil_LIBS) $(zlib_LIBS) \ $(libbsd_LIBS) $(libevent_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotsh/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotsh/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: -$(am__rm_f) $(bin_PROGRAMS) $(top_builddir)/gotd/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd @: >>$(top_builddir)/gotd/$(am__dirstamp) $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/gotd/$(DEPDIR) @: >>$(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/gotd/imsg.$(OBJEXT): \ $(top_builddir)/gotd/$(am__dirstamp) \ $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitproto.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotd_imsg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/serve.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gotsh$(EXEEXT): $(gotsh_OBJECTS) $(gotsh_DEPENDENCIES) $(EXTRA_gotsh_DEPENDENCIES) @rm -f gotsh$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotsh_OBJECTS) $(gotsh_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/gotd/*.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/gotd/$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitproto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/serve.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotsh.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/gotd/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/gotd/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/serve.Po -rm -f ./$(DEPDIR)/gotsh.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/gotd/$(DEPDIR)/imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/serve.Po -rm -f ./$(DEPDIR)/gotsh.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Disable for now (per upstream)... # #install-exec-hook: # ln -sf $(prefix)/bin/gotsh $(prefix)/bin/git-receive-pack # ln -sf $(prefix)/bin/gotsh $(prefix)/bin/git-upload-pack # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/Makefile.common.in0000664000175000017500000000147415066536113013156 AM_CFLAGS += \ @AM_CFLAGS@ \ -Wunused-variable \ -Wwrite-strings \ -Wno-pointer-sign # Ideally, we should be enabling further flags, but this requires upstream # changes. Leaving these here for now. # # -g -Wall -Wno-long-long -W -Wformat=2 -Wmissing-prototypes \ # -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings \ # -Wshadow -Wpointer-arith -Wno-sign-compare -Wundef \ # -Wbad-function-cast -Winline -Wcast-align \ # -Wdeclaration-after-statement -Wno-pointer-sign \ # -Wno-attributes -Wno-unused-result AM_CPPFLAGS += \ @AM_CPPFLAGS@ \ -DGOT_LIBEXECDIR="$(libexecdir)" \ -I$(top_srcdir) \ -I$(top_srcdir)/compat \ -I$(top_srcdir)/lib \ -I$(top_srcdir)/include \ -I$(top_srcdir)/template \ -I$(top_srcdir)/gotd \ got-portable-0.119/README0000664000175000017500000001717415066535721010512 Game of Trees (Got) is a version control system which prioritizes ease of use and simplicity over flexibility (https://gameoftrees.org) Got is still under development; it is being developed exclusively on OpenBSD and its target audience are OpenBSD developers. Got is ISC-licensed and was designed with pledge(2) and unveil(2) in mind. Got uses Git repositories to store versioned data. Git can be used for any functionality which has not yet been implemented in Got. It will always remain possible to work with both Got and Git on the same repository. A Got release tarball will install files under /usr/local by default. This default can be changed by passing PREFIX=/some/path to make. A build started in Got's Git repository will install files under ~/bin, which may have to be added to $PATH and be created first: $ mkdir ~/bin To compile the Got client tool suite on OpenBSD, run: $ make obj $ make $ make install This will install the following commands: got, the command line interface tog, an ncurses-based interactive Git repository browser several helper programs from the libexec directory man pages (only installed if building sources from a Got release tarball) Tests will pass only after 'make install' because they rely on installed binaries in $PATH. Any tests written as shell scripts also depend on git(1). Tests which use the got clone, fetch, and send commands will fail if 'ssh 127.0.0.1' does not succeed non-interactively. Tests for HTTP protocol support rely on the HTTP::Daemon Perl module. $ doas pkg_add git p5-http-daemon $ make regress To test with packed repositories, run: $ make regress GOT_TEST_PACK=1 To test with packed repositories using the ref-delta representation for deltified objects, run: $ make regress GOT_TEST_PACK=ref-delta To test with sha256 object IDs instead of sha1, run: $ make regress GOT_TEST_ALGO=sha256 The GOT_TEST_PACK and GOT_TEST_ALGO flags can be combined to test packed repositories with sha256 object IDs. Because got unveils the /tmp directory by default using the /tmp directory for test data can hide bugs. However, /tmp remains the default because there is no better alternative that works out of the box. In order to store test data in a directory other than /tmp, such as ~/got-test, run: $ mkdir ~/got-test $ make regress GOT_TEST_ROOT=~/got-test The tog automated test suite is also run with 'make regress'. Like Got, however, individual tests or the entire suite can be run: $ cd regress/tog $ make # run all tests $ ./log.sh # run log view tests Man page files in the Got source tree can be viewed with 'man -l': $ man -l got/got.1 $ man -l got/git-repository.5 $ man -l got/got-worktree.5 $ man -l tog/tog.1 EXAMPLES in got.1 contains a quick-start guide for OpenBSD developers. To compile the Got server tool suite on OpenBSD, run: $ make obj $ make server $ make server-install This will install the following commands: gotd, the repository server program gotctl, the server control utility gotsh, the login shell for users accessing the server via the network gitwrapper, like mailwrapper(8) but for git-upload-pack and git-receive-pack See the following manual page files for information about server setup: $ man -l gotd/gotd.8 $ man -l gotd/gotd.conf.5 $ man -l gotctl/gotctl.8 $ man -l gotsh/gotsh.1 $ man -l gitwrapper/gitwrapper.1 See regress/gotd/README for information about running the server test suite. Game of Trees Web Daemon (gotwebd) is a FastCGI program which displays repository data and is designed to work with httpd(8). To compile gotwebd on OpenBSD, run: $ make webd # make webd-install This will create the following files: the daemon program /usr/local/sbin/gotwebd css and image files in /var/www/htdocs/gotwebd the gotwebd init script in /etc/rc.d man pages (only installed if building sources from a Got release tarball) Documentation is available in manual pages: $ man -l gotwebd/gotwebd.8 $ man -l gotwebd/gotwebd.conf.5 The gotwebd test suite must be started as root in order to start and stop the gotwebd daemon. With the gotwebd binary installed, the test suite can be run from the top-level directory: $ doas make webd-regress The test suite switches to non-root users as appropriate. gotsysd(8) is a daemon which can be used to manage a gotd(8) server by committing a configuration file to the special "gotsys.git" repository. To compile gotsysd on OpenBSD, run: $ make sysd # make sysd-install This will create the following files: the daemon program /usr/local/sbin/gotsysd the control program /usr/local/sbin/gotsysctl man pages (only installed if building sources from a Got release tarball) Related documentation is available in manual pages: $ man -l gotsys/gotsys.conf.5 $ man -l gotsys/gotsys.1 $ man -l gotsysd/gotsysd.8 $ man -l gotsysd/gotsysd.conf.5 $ man -l gotsysctl/gotsysctl.8 See regress/gotsysd/README for information about the gotsysd test suite. Got can be built with profiling enabled to debug performance issues. Note that profiled builds cannot make use of pledge(2). Profiling should only be enabled for one program at a time. Otherwise, multiple programs will attempt to write to the 'gmon.out' file in the current working directory. For example, to compile got-read-pack with profiling enabled: $ cd libexec/got-read-pack $ make clean $ make PROFILE=1 $ make install Running any Got command which ends up using got-read-pack should now produce the file 'gmon.out' in the current working directory. The gprof2dot program can be used to generate a profile graph: $ doas pkg_add gprof2dot graphviz $ gprof ~/bin/got-read-pack gmon.out | gprof2dot | dot -T png > profile.png Guidelines for reporting problems: All problem/bug reports should include a reproduction recipe in form of a shell script which starts out with an empty repository and runs a series of Got and/or Git commands to trigger the problem, be it a crash or some other undesirable behaviour. The regress/cmdline directory contains plenty of example scripts. An ideal reproduction recipe is written as an xfail ("expected failure") regression test. For a real-world example of an xfail test, see commits 4866d0842a2b34812818685aaa31d3e0a966412d and 2b496619daecc1f25b1bc0c53e01685030dc2c74 in Got's history. Please take this request very seriously; Ask for help with writing your regression test before asking for your problem to be fixed. Time invested in writing a regression test saves time wasted on back-and-forth discussion about how the problem can be reproduced. A regression test will need to be written in any case to verify a fix and prevent the problem from resurfacing. It is also possible to write test cases in C. Various examples of this exist in the regress/ directory. Most such tests are unit tests; it is unlikely that a problem found during regular usage will require a test to be written in C. Please always try to find a way to trigger your problem via the command line interface before reporting a problem without a written test case included. If writing an automated test really turns out to be impossible, please explain in very clear terms how the problem can be reproduced. Mail problem reports to: gameoftrees@openbsd.org Guidelines for submitting patches: Mail patches to: gameoftrees@openbsd.org Pull requests via any Git hosting sites will likely be overlooked. Please keep the intended target audience in mind when contributing to Got. Subscribing to the gameoftrees@openbsd.org mailing list: The mailing list is used for patch reviews, bug reports, and user questions. To subscribe, send mail to majordomo@openbsd.org with a message body of: subscribe gameoftrees See https://www.openbsd.org/mail.html for more information. got-portable-0.119/compat/0000775000175000017500000000000015066537273011167 5got-portable-0.119/compat/siphash.c0000664000175000017500000001204115066536113012700 /* $OpenBSD: siphash.c,v 1.8 2019/01/20 03:53:47 bcook Exp $ */ /*- * Copyright (c) 2013 Andre Oppermann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d * are the number of compression rounds and the number of finalization rounds. * A compression round is identical to a finalization round and this round * function is called SipRound. Given a 128-bit key k and a (possibly empty) * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m). * * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18, * by Jean-Philippe Aumasson and Daniel J. Bernstein, * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa * https://131002.net/siphash/siphash.pdf * https://131002.net/siphash/ */ #include #include #include "siphash.h" #include "got_compat.h" static void SipHash_CRounds(SIPHASH_CTX *, int); static void SipHash_Rounds(SIPHASH_CTX *, int); void SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key) { uint64_t k0, k1; k0 = le64toh(key->k0); k1 = le64toh(key->k1); ctx->v[0] = 0x736f6d6570736575ULL ^ k0; ctx->v[1] = 0x646f72616e646f6dULL ^ k1; ctx->v[2] = 0x6c7967656e657261ULL ^ k0; ctx->v[3] = 0x7465646279746573ULL ^ k1; memset(ctx->buf, 0, sizeof(ctx->buf)); ctx->bytes = 0; } void SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, const void *src, size_t len) { const uint8_t *ptr = src; size_t left, used; if (len == 0) return; used = ctx->bytes % sizeof(ctx->buf); ctx->bytes += len; if (used > 0) { left = sizeof(ctx->buf) - used; if (len >= left) { memcpy(&ctx->buf[used], ptr, left); SipHash_CRounds(ctx, rc); len -= left; ptr += left; } else { memcpy(&ctx->buf[used], ptr, len); return; } } while (len >= sizeof(ctx->buf)) { memcpy(ctx->buf, ptr, sizeof(ctx->buf)); SipHash_CRounds(ctx, rc); len -= sizeof(ctx->buf); ptr += sizeof(ctx->buf); } if (len > 0) memcpy(ctx->buf, ptr, len); } void SipHash_Final(void *dst, SIPHASH_CTX *ctx, int rc, int rf) { uint64_t r; r = htole64(SipHash_End(ctx, rc, rf)); memcpy(dst, &r, sizeof r); } uint64_t SipHash_End(SIPHASH_CTX *ctx, int rc, int rf) { uint64_t r; size_t left, used; used = ctx->bytes % sizeof(ctx->buf); left = sizeof(ctx->buf) - used; memset(&ctx->buf[used], 0, left - 1); ctx->buf[7] = ctx->bytes; SipHash_CRounds(ctx, rc); ctx->v[2] ^= 0xff; SipHash_Rounds(ctx, rf); r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]); #ifdef __APPLE__ memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); #elif defined(__NetBSD__) explicit_memset(ctx, sizeof(*ctx), 0); #else explicit_bzero(ctx, sizeof(*ctx)); #endif return (r); } uint64_t SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len) { SIPHASH_CTX ctx; SipHash_Init(&ctx, key); SipHash_Update(&ctx, rc, rf, src, len); return (SipHash_End(&ctx, rc, rf)); } #define SIP_ROTL(x, b) ((x) << (b)) | ( (x) >> (64 - (b))) static void SipHash_Rounds(SIPHASH_CTX *ctx, int rounds) { while (rounds--) { ctx->v[0] += ctx->v[1]; ctx->v[2] += ctx->v[3]; ctx->v[1] = SIP_ROTL(ctx->v[1], 13); ctx->v[3] = SIP_ROTL(ctx->v[3], 16); ctx->v[1] ^= ctx->v[0]; ctx->v[3] ^= ctx->v[2]; ctx->v[0] = SIP_ROTL(ctx->v[0], 32); ctx->v[2] += ctx->v[1]; ctx->v[0] += ctx->v[3]; ctx->v[1] = SIP_ROTL(ctx->v[1], 17); ctx->v[3] = SIP_ROTL(ctx->v[3], 21); ctx->v[1] ^= ctx->v[2]; ctx->v[3] ^= ctx->v[0]; ctx->v[2] = SIP_ROTL(ctx->v[2], 32); } } static void SipHash_CRounds(SIPHASH_CTX *ctx, int rounds) { uint64_t m = le64toh(*(uint64_t *)ctx->buf); ctx->v[3] ^= m; SipHash_Rounds(ctx, rounds); ctx->v[0] ^= m; } got-portable-0.119/compat/strnlen.c0000664000175000017500000000206415066536113012732 /* $OpenBSD: strnlen.c,v 1.8 2016/10/16 17:37:39 dtucker Exp $ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include size_t strnlen(const char *str, size_t maxlen) { const char *cp; for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--) ; return (size_t)(cp - str); } got-portable-0.119/compat/strtonum.c0000664000175000017500000000335115066536113013140 /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; char *ep; int error = 0; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) error = INVALID; else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } got-portable-0.119/compat/err.c0000664000175000017500000000335115066536113012035 /* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include static void vwarn_impl(const char*, va_list); static void vwarnx_impl(const char*, va_list); static void vwarn_impl(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); } static void vwarnx_impl(const char *fmt, va_list ap) { fprintf(stderr, "%s: ", getprogname()); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); } void err(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn_impl(fmt, ap); va_end(ap); exit(ret); } void errx(int ret, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx_impl(fmt, ap); va_end(ap); exit(ret); } void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarn_impl(fmt, ap); va_end(ap); } void warnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vwarnx_impl(fmt, ap); va_end(ap); } got-portable-0.119/compat/getopt.c0000664000175000017500000000716515066536113012556 /* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ #include "got_compat.h" #include #include #include int BSDopterr = 1, /* if error message should be printed */ BSDoptind = 1, /* index into parent argv vector */ BSDoptopt, /* character checked for validity */ BSDoptreset; /* reset getopt */ char *BSDoptarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int BSDgetopt(int nargc, char *const *nargv, const char *ostr) { static const char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (ostr == NULL) return (-1); if (BSDoptreset || !*place) { /* update scanning pointer */ BSDoptreset = 0; if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ if (place[1]) return (BADCH); ++BSDoptind; place = EMSG; return (-1); } } /* option letter okay? */ if ((BSDoptopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, BSDoptopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (BSDoptopt == (int)'-') return (-1); if (!*place) ++BSDoptind; if (BSDopterr && *ostr != ':') (void)fprintf(stderr, "%s: unknown option -- %c\n", getprogname(), BSDoptopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ BSDoptarg = NULL; if (!*place) ++BSDoptind; } else { /* need an argument */ if (*place) /* no white space */ BSDoptarg = (char *)place; else if (nargc <= ++BSDoptind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (BSDopterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", getprogname(), BSDoptopt); return (BADCH); } else /* white space */ BSDoptarg = nargv[BSDoptind]; place = EMSG; ++BSDoptind; } return (BSDoptopt); /* dump back option letter */ } got-portable-0.119/compat/strsep.c0000664000175000017500000000472315066536113012571 /* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include /* * Get next token from string *stringp, where tokens are possibly-empty * strings separated by characters from delim. * * Writes NULs into the string at *stringp to end tokens. * delim need not remain constant from call to call. * On return, *stringp points past the last NUL written (if there might * be further tokens), or is NULL (if there are definitely no more tokens). * * If *stringp is NULL, strsep returns NULL. */ char * strsep(char **stringp, const char *delim) { char *s; const char *spanp; int c, sc; char *tok; if ((s = *stringp) == NULL) return (NULL); for (tok = s;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *stringp = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } got-portable-0.119/compat/sha2.h0000664000175000017500000001670215066536113012113 /* $OpenBSD: sha2.h,v 1.10 2016/09/03 17:00:29 tedu Exp $ */ /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ /* OPENBSD ORIGINAL: include/sha2.h */ #ifndef _SSHSHA2_H #define _SSHSHA2_H #if !defined(HAVE_SHA256UPDATE) /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA224_BLOCK_LENGTH 64 #define SHA224_DIGEST_LENGTH 28 #define SHA224_DIGEST_STRING_LENGTH (SHA224_DIGEST_LENGTH * 2 + 1) #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) #define SHA512_256_BLOCK_LENGTH 128 #define SHA512_256_DIGEST_LENGTH 32 #define SHA512_256_DIGEST_STRING_LENGTH (SHA512_256_DIGEST_LENGTH * 2 + 1) /*** SHA-224/256/384/512 Context Structure *******************************/ typedef struct _SHA2_CTX { union { u_int32_t st32[8]; u_int64_t st64[8]; } state; u_int64_t bitcount[2]; u_int8_t buffer[SHA512_BLOCK_LENGTH]; } SHA2_CTX; #if 0 __BEGIN_DECLS void SHA224Init(SHA2_CTX *); void SHA224Transform(u_int32_t state[8], const u_int8_t [SHA224_BLOCK_LENGTH]); void SHA224Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA224Pad(SHA2_CTX *); void SHA224Final(u_int8_t [SHA224_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA224_DIGEST_LENGTH))); char *SHA224End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA224_DIGEST_STRING_LENGTH))); char *SHA224Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA224_DIGEST_STRING_LENGTH))); #endif /* 0 */ #ifndef HAVE_SHA256UPDATE void SHA256Init(SHA2_CTX *); void SHA256Transform(u_int32_t state[8], const u_int8_t [SHA256_BLOCK_LENGTH]); void SHA256Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA256Pad(SHA2_CTX *); void SHA256Final(u_int8_t [SHA256_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH))); char *SHA256End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH))); char *SHA256Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA256_DIGEST_STRING_LENGTH))); #endif /* HAVE_SHA256UPDATE */ #if 0 void SHA384Init(SHA2_CTX *); void SHA384Transform(u_int64_t state[8], const u_int8_t [SHA384_BLOCK_LENGTH]); void SHA384Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA384Pad(SHA2_CTX *); void SHA384Final(u_int8_t [SHA384_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH))); char *SHA384End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH))); char *SHA384Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA384_DIGEST_STRING_LENGTH))); void SHA512Init(SHA2_CTX *); void SHA512Transform(u_int64_t state[8], const u_int8_t [SHA512_BLOCK_LENGTH]); void SHA512Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA512Pad(SHA2_CTX *); void SHA512Final(u_int8_t [SHA512_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH))); char *SHA512End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH))); char *SHA512Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA512_DIGEST_STRING_LENGTH))); void SHA512_256Init(SHA2_CTX *); void SHA512_256Transform(u_int64_t state[8], const u_int8_t [SHA512_256_BLOCK_LENGTH]); void SHA512_256Update(SHA2_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA512_256Pad(SHA2_CTX *); void SHA512_256Final(u_int8_t [SHA512_256_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA512_256_DIGEST_LENGTH))); char *SHA512_256End(SHA2_CTX *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256File(const char *, char *) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256FileChunk(const char *, char *, off_t, off_t) __attribute__((__bounded__(__minbytes__,2,SHA512_256_DIGEST_STRING_LENGTH))); char *SHA512_256Data(const u_int8_t *, size_t, char *) __attribute__((__bounded__(__string__,1,2))) __attribute__((__bounded__(__minbytes__,3,SHA512_256_DIGEST_STRING_LENGTH))); __END_DECLS #endif /* 0 */ #endif /* HAVE_SHA256UPDATE */ #endif /* _SSHSHA2_H */ got-portable-0.119/compat/closefrom.c0000664000175000017500000000550315066536113013237 /* * Copyright (c) 2004-2005 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef HAVE_CLOSEFROM #include #include #include #include #ifdef HAVE_FCNTL_H # include #endif #include #include #include #include #include #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif #endif #ifndef OPEN_MAX # define OPEN_MAX 256 #endif #if 0 __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; #endif /* lint */ /* * Close all file descriptors greater than or equal to lowfd. */ #ifdef HAVE_FCNTL_CLOSEM void closefrom(int lowfd) { (void) fcntl(lowfd, F_CLOSEM, 0); } #else void closefrom(int lowfd) { long fd, maxfd; #if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) char fdpath[PATH_MAX], *endp; struct dirent *dent; DIR *dirp; int len; /* Check for a /proc/$$/fd directory. */ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { while ((dent = readdir(dirp)) != NULL) { fd = strtol(dent->d_name, &endp, 10); if (dent->d_name != endp && *endp == '\0' && fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) (void) close((int) fd); } (void) closedir(dirp); } else #endif { /* * Fall back on sysconf() or getdtablesize(). We avoid checking * resource limits since it is possible to open a file descriptor * and then drop the rlimit such that it is below the open fd. */ #ifdef HAVE_SYSCONF maxfd = sysconf(_SC_OPEN_MAX); #else maxfd = getdtablesize(); #endif /* HAVE_SYSCONF */ if (maxfd < 0) maxfd = OPEN_MAX; for (fd = lowfd; fd < maxfd; fd++) (void) close((int) fd); } } #endif /* !HAVE_FCNTL_CLOSEM */ #endif /* HAVE_CLOSEFROM */ got-portable-0.119/compat/getdtablecount.c0000664000175000017500000000242515066536113014252 /* * Copyright (c) 2017 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include void fatal(const char *, ...); void fatalx(const char *, ...); #ifdef HAVE_PROC_PID int getdtablecount(void) { char path[PATH_MAX]; glob_t g; int n = 0; if (snprintf(path, sizeof path, "/proc/%ld/fd/*", (long)getpid()) < 0) { fprintf(stderr, "snprintf overflow"); exit (1); } if (glob(path, 0, NULL, &g) == 0) n = g.gl_pathc; globfree(&g); return (n); } #else int getdtablecount(void) { return (0); } #endif got-portable-0.119/compat/siphash.h0000664000175000017500000000652015066536113012712 /*- * Copyright (c) 2013 Andre Oppermann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $OpenBSD: siphash.h,v 1.3 2015/02/20 11:51:03 tedu Exp $ */ /* * SipHash is a family of pseudorandom functions (a.k.a. keyed hash functions) * optimized for speed on short messages returning a 64bit hash/digest value. * * The number of rounds is defined during the initialization: * SipHash24_Init() for the fast and resonable strong version * SipHash48_Init() for the strong version (half as fast) * * struct SIPHASH_CTX ctx; * SipHash24_Init(&ctx); * SipHash_SetKey(&ctx, "16bytes long key"); * SipHash_Update(&ctx, pointer_to_string, length_of_string); * SipHash_Final(output, &ctx); */ #ifndef _SIPHASH_H_ #define _SIPHASH_H_ #define SIPHASH_BLOCK_LENGTH 8 #define SIPHASH_KEY_LENGTH 16 #define SIPHASH_DIGEST_LENGTH 8 typedef struct _SIPHASH_CTX { uint64_t v[4]; uint8_t buf[SIPHASH_BLOCK_LENGTH]; uint32_t bytes; } SIPHASH_CTX; typedef struct { uint64_t k0; uint64_t k1; } SIPHASH_KEY; void SipHash_Init(SIPHASH_CTX *, const SIPHASH_KEY *); void SipHash_Update(SIPHASH_CTX *, int, int, const void *, size_t); uint64_t SipHash_End(SIPHASH_CTX *, int, int); void SipHash_Final(void *, SIPHASH_CTX *, int, int); uint64_t SipHash(const SIPHASH_KEY *, int, int, const void *, size_t); #define SipHash24_Init(_c, _k) SipHash_Init((_c), (_k)) #define SipHash24_Update(_c, _p, _l) SipHash_Update((_c), 2, 4, (_p), (_l)) #define SipHash24_End(_d) SipHash_End((_d), 2, 4) #define SipHash24_Final(_d, _c) SipHash_Final((_d), (_c), 2, 4) #define SipHash24(_k, _p, _l) SipHash((_k), 2, 4, (_p), (_l)) #define SipHash48_Init(_c, _k) SipHash_Init((_c), (_k)) #define SipHash48_Update(_c, _p, _l) SipHash_Update((_c), 4, 8, (_p), (_l)) #define SipHash48_End(_d) SipHash_End((_d), 4, 8) #define SipHash48_Final(_d, _c) SipHash_Final((_d), (_c), 4, 8) #define SipHash48(_k, _p, _l) SipHash((_k), 4, 8, (_p), (_l)) #endif /* _SIPHASH_H_ */ got-portable-0.119/compat/uuid.c0000664000175000017500000000444515066536113012220 /* * Copyright (c) 2002,2005 Marcel Moolenaar * Copyright (c) 2002 Hiten Mahesh Pandya * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "got_compat.h" int32_t uuid_equal(struct uuid* a, struct uuid* b, uint32_t* unused) { return (uuid_compare(*(uuid_t *)a, *(uuid_t *)b) == 0); } int32_t uuid_is_nil(struct uuid* uuid, uint32_t* unused) { return uuid_is_null(*(uuid_t *)uuid); } void uuid_create(uuid_t *uuid, uint32_t* status) { *status = uuid_s_ok; return uuid_generate(*(uuid_t *)uuid); } void uuid_create_nil(struct uuid* uuid, uint32_t* unused) { return uuid_clear(*(uuid_t *)uuid); } void uuid_from_string(const char* s, uuid_t *uuid, uint32_t *status) { *status = uuid_parse(s, *(uuid_t *)uuid); } void uuid_to_string(uuid_t *uuid, char** s, uint32_t *status) { *s = malloc(36 + 1); /* 36 byte uuid plus '\0' */ if (*s == NULL) { fprintf(stderr, "uuid_to_string: fatal: malloc\n"); exit (1); } uuid_unparse(*(uuid_t *)uuid, *s); *status = uuid_s_ok; } got-portable-0.119/compat/recallocarray.c0000664000175000017500000000452415066536113014073 /* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ /* * Copyright (c) 2008, 2017 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) { size_t oldsize, newsize; void *newptr; if (ptr == NULL) return calloc(newnmemb, size); if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && newnmemb > 0 && SIZE_MAX / newnmemb < size) { errno = ENOMEM; return NULL; } newsize = newnmemb * size; if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { errno = EINVAL; return NULL; } oldsize = oldnmemb * size; /* * Don't bother too much if we're shrinking just a bit, * we do not shrink for series of small steps, oh well. */ if (newsize <= oldsize) { size_t d = oldsize - newsize; if (d < oldsize / 2 && d < (size_t)getpagesize()) { memset((char *)ptr + newsize, 0, d); return ptr; } } newptr = malloc(newsize); if (newptr == NULL) return NULL; if (newsize > oldsize) { memcpy(newptr, ptr, oldsize); memset((char *)newptr + oldsize, 0, newsize - oldsize); } else memcpy(newptr, ptr, newsize); #ifdef __APPLE__ memset_s(ptr, oldsize, 0, oldsize); #elif defined(__NetBSD__) explicit_memset(ptr, oldsize, 0); #else explicit_bzero(ptr, oldsize); #endif free(ptr); return newptr; } got-portable-0.119/compat/merge.c0000664000175000017500000002165315066536113012351 /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Peter McIlroy. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include /* * Hybrid exponential search/linear search merge sort with hybrid * natural/pairwise first pass. Requires about .3% more comparisons * for random data than LSMS with pairwise first pass alone. * It works for objects as small as two bytes. */ #define NATURAL #define THRESHOLD 16 /* Best choice for natural merge cut-off. */ /* #define NATURAL to get hybrid natural merge. * (The default is pairwise merging.) */ #include #include #include #include #include "got_compat.h" static void setup(unsigned char *, unsigned char *, size_t, size_t, int (*)(const void *, const void *)); static void insertionsort(unsigned char *, size_t, size_t, int (*)(const void *, const void *)); #define ISIZE sizeof(int) #define PSIZE sizeof(unsigned char *) #define ICOPY_LIST(src, dst, last) \ do \ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ while(src < last) #define ICOPY_ELT(src, dst, i) \ do \ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ while (i -= ISIZE) #define CCOPY_LIST(src, dst, last) \ do \ *dst++ = *src++; \ while (src < last) #define CCOPY_ELT(src, dst, i) \ do \ *dst++ = *src++; \ while (i -= 1) /* * Find the next possible pointer head. (Trickery for forcing an array * to do double duty as a linked list when objects do not align with word * boundaries. */ /* Assumption: PSIZE is a power of 2. */ #define EVAL(p) (unsigned char **) \ ((unsigned char *)0 + \ (((unsigned char *)p + PSIZE - 1 - \ (unsigned char *)0) & ~(PSIZE - 1))) /* * Arguments are as for qsort. */ int mergesort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *)) { size_t i; int sense; int big, iflag; unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; unsigned char *list2, *list1, *p2, *p, *last, **p1; if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ errno = EINVAL; return (-1); } if (nmemb == 0) return (0); /* * XXX * Stupid subtraction for the Cray. */ iflag = 0; if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) iflag = 1; if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) return (-1); list1 = base; setup(list1, list2, nmemb, size, cmp); last = list2 + nmemb * size; i = big = 0; while (*EVAL(list2) != last) { l2 = list1; p1 = EVAL(list1); for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { p2 = *EVAL(p2); f1 = l2; f2 = l1 = list1 + (p2 - list2); if (p2 != last) p2 = *EVAL(p2); l2 = list1 + (p2 - list2); while (f1 < l1 && f2 < l2) { if ((*cmp)(f1, f2) <= 0) { q = f2; b = f1, t = l1; sense = -1; } else { q = f1; b = f2, t = l2; sense = 0; } if (!big) { /* here i = 0 */ while ((b += size) < t && cmp(q, b) >sense) if (++i == 6) { big = 1; goto EXPONENTIAL; } } else { EXPONENTIAL: for (i = size; ; i <<= 1) if ((p = (b + i)) >= t) { if ((p = t - size) > b && (*cmp)(q, p) <= sense) t = p; else b = p; break; } else if ((*cmp)(q, p) <= sense) { t = p; if (i == size) big = 0; goto FASTCASE; } else b = p; while (t > b+size) { i = (((t - b) / size) >> 1) * size; if ((*cmp)(q, p = b + i) <= sense) t = p; else b = p; } goto COPY; FASTCASE: while (i > size) if ((*cmp)(q, p = b + (i >>= 1)) <= sense) t = p; else b = p; COPY: b = t; } i = size; if (q == f1) { if (iflag) { ICOPY_LIST(f2, tp2, b); ICOPY_ELT(f1, tp2, i); } else { CCOPY_LIST(f2, tp2, b); CCOPY_ELT(f1, tp2, i); } } else { if (iflag) { ICOPY_LIST(f1, tp2, b); ICOPY_ELT(f2, tp2, i); } else { CCOPY_LIST(f1, tp2, b); CCOPY_ELT(f2, tp2, i); } } } if (f2 < l2) { if (iflag) ICOPY_LIST(f2, tp2, l2); else CCOPY_LIST(f2, tp2, l2); } else if (f1 < l1) { if (iflag) ICOPY_LIST(f1, tp2, l1); else CCOPY_LIST(f1, tp2, l1); } *p1 = l2; } tp2 = list1; /* swap list1, list2 */ list1 = list2; list2 = tp2; last = list2 + nmemb*size; } if (base == list2) { memmove(list2, list1, nmemb*size); list2 = list1; } free(list2); return (0); } #define swap(a, b) { \ s = b; \ i = size; \ do { \ tmp = *a; *a++ = *s; *s++ = tmp; \ } while (--i); \ a -= size; \ } #define reverse(bot, top) { \ s = top; \ do { \ i = size; \ do { \ tmp = *bot; *bot++ = *s; *s++ = tmp; \ } while (--i); \ s -= size2; \ } while(bot < s); \ } /* * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of * increasing order, list2 in a corresponding linked list. Checks for runs * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL * is defined. Otherwise simple pairwise merging is used.) */ static void setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, int (*cmp)(const void *, const void *)) { int i, length, size2, tmp, sense; unsigned char *f1, *f2, *s, *l2, *last, *p2; size2 = size*2; if (n <= 5) { insertionsort(list1, n, size, cmp); *EVAL(list2) = (unsigned char*) list2 + n*size; return; } /* * Avoid running pointers out of bounds; limit n to evens * for simplicity. */ i = 4 + (n & 1); insertionsort(list1 + (n - i) * size, i, size, cmp); last = list1 + size * (n - i); *EVAL(list2 + (last - list1)) = list2 + n * size; #ifdef NATURAL p2 = list2; f1 = list1; sense = (cmp(f1, f1 + size) > 0); for (; f1 < last; sense = !sense) { length = 2; /* Find pairs with same sense. */ for (f2 = f1 + size2; f2 < last; f2 += size2) { if ((cmp(f2, f2+ size) > 0) != sense) break; length += 2; } if (length < THRESHOLD) { /* Pairwise merge */ do { p2 = *EVAL(p2) = f1 + size2 - list1 + list2; if (sense > 0) swap (f1, f1 + size); } while ((f1 += size2) < f2); } else { /* Natural merge */ l2 = f2; for (f2 = f1 + size2; f2 < l2; f2 += size2) { if ((cmp(f2-size, f2) > 0) != sense) { p2 = *EVAL(p2) = f2 - list1 + list2; if (sense > 0) reverse(f1, f2-size); f1 = f2; } } if (sense > 0) reverse (f1, f2-size); f1 = f2; if (f2 < last || cmp(f2 - size, f2) > 0) p2 = *EVAL(p2) = f2 - list1 + list2; else p2 = *EVAL(p2) = list2 + n*size; } } #else /* pairwise merge only. */ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { p2 = *EVAL(p2) = p2 + size2; if (cmp (f1, f1 + size) > 0) swap(f1, f1 + size); } #endif /* NATURAL */ } /* * This is to avoid out-of-bounds addresses in sorting the * last 4 elements. */ static void insertionsort(unsigned char *a, size_t n, size_t size, int (*cmp)(const void *, const void *)) { unsigned char *ai, *s, *t, *u, tmp; int i; for (ai = a+size; --n >= 1; ai += size) for (t = ai; t > a; t -= size) { u = t - size; if (cmp(u, t) <= 0) break; swap(u, t); } } got-portable-0.119/compat/fmt_scaled.c0000664000175000017500000001455615066536113013357 /* * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * fmt_scaled: Format numbers scaled for human comprehension * scan_scaled: Scan numbers in this format. * * "Human-readable" output uses 4 digits max, and puts a unit suffix at * the end. Makes output compact and easy-to-read esp. on huge disks. * Formatting code was originally in OpenBSD "df", converted to library routine. * Scanning code written for OpenBSD libutil. */ #include #include #include #include #include #include #include "got_compat.h" typedef enum { NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6 } unit_type; /* These three arrays MUST be in sync! XXX make a struct */ static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA }; static char scale_chars[] = "BKMGTPE"; static long long scale_factors[] = { 1LL, 1024LL, 1024LL*1024, 1024LL*1024*1024, 1024LL*1024*1024*1024, 1024LL*1024*1024*1024*1024, 1024LL*1024*1024*1024*1024*1024, }; #define SCALE_LENGTH (sizeof(units)/sizeof(units[0])) #define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ /* Convert the given input string "scaled" into numeric in "result". * Return 0 on success, -1 and errno set on error. */ int scan_scaled(char *scaled, long long *result) { char *p = scaled; int sign = 0; unsigned int i, ndigits = 0, fract_digits = 0; long long scale_fact = 1, whole = 0, fpart = 0; /* Skip leading whitespace */ while (isascii(*p) && isspace(*p)) ++p; /* Then at most one leading + or - */ while (*p == '-' || *p == '+') { if (*p == '-') { if (sign) { errno = EINVAL; return -1; } sign = -1; ++p; } else if (*p == '+') { if (sign) { errno = EINVAL; return -1; } sign = +1; ++p; } } /* Main loop: Scan digits, find decimal point, if present. * We don't allow exponentials, so no scientific notation * (but note that E for Exa might look like e to some!). * Advance 'p' to end, to get scale factor. */ for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { if (*p == '.') { if (fract_digits > 0) { /* oops, more than one '.' */ errno = EINVAL; return -1; } fract_digits = 1; continue; } i = (*p) - '0'; /* whew! finally a digit we can use */ if (fract_digits > 0) { if (fract_digits >= MAX_DIGITS-1) /* ignore extra fractional digits */ continue; fract_digits++; /* for later scaling */ fpart *= 10; fpart += i; } else { /* normal digit */ if (++ndigits >= MAX_DIGITS) { errno = ERANGE; return -1; } whole *= 10; whole += i; } } if (sign) { whole *= sign; fpart *= sign; } /* If no scale factor given, we're done. fraction is discarded. */ if (!*p) { *result = whole; return 0; } /* Validate scale factor, and scale whole and fraction by it. */ for (i = 0; i < SCALE_LENGTH; i++) { /* Are we there yet? */ if (*p == scale_chars[i] || *p == tolower(scale_chars[i])) { /* If it ends with alphanumerics after the scale char, bad. */ if (isalnum(*(p+1))) { errno = EINVAL; return -1; } scale_fact = scale_factors[i]; /* scale whole part */ whole *= scale_fact; /* truncate fpart so it does't overflow. * then scale fractional part. */ while (fpart >= LLONG_MAX / scale_fact) { fpart /= 10; fract_digits--; } fpart *= scale_fact; if (fract_digits > 0) { for (i = 0; i < fract_digits -1; i++) fpart /= 10; } whole += fpart; *result = whole; return 0; } } errno = ERANGE; return -1; } /* Format the given "number" into human-readable form in "result". * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE. * Return 0 on success, -1 and errno set if error. */ int fmt_scaled(long long number, char *result) { long long abval, fract = 0; unsigned int i; unit_type unit = NONE; abval = llabs(number); /* Not every negative long long has a positive representation. * Also check for numbers that are just too darned big to format */ if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) { errno = ERANGE; return -1; } /* scale whole part; get unscaled fraction */ for (i = 0; i < SCALE_LENGTH; i++) { if (abval/1024 < scale_factors[i]) { unit = units[i]; fract = (i == 0) ? 0 : abval % scale_factors[i]; number /= scale_factors[i]; if (i > 0) fract /= scale_factors[i - 1]; break; } } fract = (10 * fract + 512) / 1024; /* if the result would be >= 10, round main number */ if (fract == 10) { if (number >= 0) number++; else number--; fract = 0; } if (number == 0) strlcpy(result, "0B", FMT_SCALED_STRSIZE); else if (unit == NONE || number >= 100 || number <= -100) { if (fract >= 5) { if (number >= 0) number++; else number--; } (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c", number, scale_chars[unit]); } else (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c", number, fract, scale_chars[unit]); return 0; } got-portable-0.119/compat/setproctitle.c0000664000175000017500000000261015066536113013763 /* * Copyright (c) 2016 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "got_compat.h" #if defined(HAVE_PRCTL) && defined(HAVE_PR_SET_NAME) #include void setproctitle(const char *fmt, ...) { char title[16], name[16], *cp; va_list ap; int used; va_start(ap, fmt); vsnprintf(title, sizeof title, fmt, ap); va_end(ap); used = snprintf(name, sizeof name, "%s: %s", getprogname(), title); if (used >= (int)sizeof name) { cp = strrchr(name, ' '); if (cp != NULL) *cp = '\0'; } prctl(PR_SET_NAME, name); } #else void setproctitle(__unused const char *fmt, ...) { } #endif got-portable-0.119/compat/strlcpy.c0000664000175000017500000000304415066536113012744 /* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } got-portable-0.119/compat/base64.c0000664000175000017500000002430015066536113012326 /* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */ /* * Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int b64_ntop(src, srclength, target, targsize) u_char const *src; size_t srclength; char *target; size_t targsize; { size_t datalength = 0; u_char input[3]; u_char output[4]; int i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ int b64_pton(src, target, targsize) char const *src; u_char *target; size_t targsize; { int tarindex, state, ch; u_char nextbyte; char *pos; state = 0; tarindex = 0; while ((ch = (unsigned char)*src++) != '\0') { if (isspace(ch)) /* Skip whitespace anywhere. */ continue; if (ch == Pad64) break; pos = strchr(Base64, ch); if (pos == 0) /* A non-base64 character. */ return (-1); switch (state) { case 0: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] = (pos - Base64) << 2; } state = 1; break; case 1: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 4; nextbyte = ((pos - Base64) & 0x0f) << 4; if (tarindex + 1 < targsize) target[tarindex+1] = nextbyte; else if (nextbyte) return (-1); } tarindex++; state = 2; break; case 2: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 2; nextbyte = ((pos - Base64) & 0x03) << 6; if (tarindex + 1 < targsize) target[tarindex+1] = nextbyte; else if (nextbyte) return (-1); } tarindex++; state = 3; break; case 3: if (target) { if (tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64); } tarindex++; state = 0; break; } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = (unsigned char)*src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for (; ch != '\0'; ch = (unsigned char)*src++) if (!isspace(ch)) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = (unsigned char)*src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for (; ch != '\0'; ch = (unsigned char)*src++) if (!isspace(ch)) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target && tarindex < targsize && target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } got-portable-0.119/compat/Makefile.am0000664000175000017500000000315015066536113013132 noinst_LIBRARIES = libopenbsd-compat.a include $(top_builddir)/Makefile.common LDADD = $(libbsd_LIBS) AM_CPPFLAGS += $(libbsd_CFLAGS) libopenbsd_compat_a_SOURCES = \ asprintf.c \ fmt_scaled.c \ freezero.c \ getdtablecount.c \ getprogname.c \ merge.c \ reallocarray.c \ recallocarray.c \ strndup.c \ strnlen.c \ strsep.c \ strtonum.c \ imsg.h \ tree.h # For MacOS, don't build the compat versions of strl{cat,cpy}, but do for all # other systems. if !HOST_DARWIN libopenbsd_compat_a_SOURCES += strlcat.c strlcpy.c endif if HOST_DARWIN libopenbsd_compat_a_SOURCES += uuid.c bsd-poll.c bsd-poll.h endif if !HAVE_GETOPT libopenbsd_compat_a_SOURCES += getopt.c endif if !HAVE_B64 libopenbsd_compat_a_SOURCES += base64.c LDADD += $(libresolv_LIBS) endif if !HAVE_CLOSEFROM libopenbsd_compat_a_SOURCES += closefrom.c endif if HOST_NETBSD libopenbsd_compat_a_SOURCES += bsd-poll.c bsd-poll.h endif if HOST_LINUX libopenbsd_compat_a_SOURCES += uuid.c endif if HAVE_LINUX_LANDLOCK libopenbsd_compat_a_SOURCES += landlock.c endif if !HAVE_SIPHASH libopenbsd_compat_a_SOURCES += siphash.c siphash.h endif if !HAVE_SETPROCTITLE libopenbsd_compat_a_SOURCES += setproctitle.c endif if !HAVE_IMSG libopenbsd_compat_a_SOURCES += imsg-buffer.c imsg.c endif if !HOST_DARWIN # Fake an assigment here. It does nothing, but you cannot have consecutive # nested if statements in Makefiles, so we have to do something here, even if # it's a dummy assignment. NOTING=something if !HAVE_SHA2 libopenbsd_compat_a_SOURCES += sha2.c sha2.h endif endif EXTRA_DIST = \ $(top_srcdir)/include/got_compat.h \ imsg.h \ tree.h \ bsd-poll.h got-portable-0.119/compat/sha2.c0000664000175000017500000006735315066536113012116 /* $OpenBSD: sha2.c,v 1.28 2019/07/23 12:35:22 dtucker Exp $ */ /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ */ /* OPENBSD ORIGINAL: lib/libc/hash/sha2.c */ #include #include "got_compat.h" #define DEF_WEAK(x) void __ssh_compat_weak_##x(void) #if !defined(HAVE_SHA256UPDATE) || !defined(HAVE_SHA384UPDATE) || \ !defined(HAVE_SHA512UPDATE) /* no-op out, similar to DEF_WEAK but only needed here */ #define MAKE_CLONE(x, y) void __ssh_compat_make_clone_##x_##y(void) /* * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ #ifndef SHA2_SMALL #if defined(__amd64__) || defined(__i386__) #define SHA2_UNROLL_TRANSFORM #endif #endif /*** SHA-224/256/384/512 Machine Architecture Definitions *****************/ /* * BYTE_ORDER NOTE: * * Please make sure that your system defines BYTE_ORDER. If your * architecture is little-endian, make sure it also defines * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are * equivalent. * * If your system does not define the above, then you can do so by * hand like this: * * #define LITTLE_ENDIAN 1234 * #define BIG_ENDIAN 4321 * * And for little-endian machines, add: * * #define BYTE_ORDER LITTLE_ENDIAN * * Or for big-endian machines: * * #define BYTE_ORDER BIG_ENDIAN * * The FreeBSD machine this was written on defines BYTE_ORDER * appropriately by including (which in turn includes * where the appropriate definitions are actually * made). */ #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN #endif /*** SHA-224/256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA224_SHORT_BLOCK_LENGTH (SHA224_BLOCK_LENGTH - 8) #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /*** ENDIAN SPECIFIC COPY MACROS **************************************/ #define BE_8_TO_32(dst, cp) do { \ (dst) = (u_int32_t)(cp)[3] | ((u_int32_t)(cp)[2] << 8) | \ ((u_int32_t)(cp)[1] << 16) | ((u_int32_t)(cp)[0] << 24); \ } while(0) #define BE_8_TO_64(dst, cp) do { \ (dst) = (u_int64_t)(cp)[7] | ((u_int64_t)(cp)[6] << 8) | \ ((u_int64_t)(cp)[5] << 16) | ((u_int64_t)(cp)[4] << 24) | \ ((u_int64_t)(cp)[3] << 32) | ((u_int64_t)(cp)[2] << 40) | \ ((u_int64_t)(cp)[1] << 48) | ((u_int64_t)(cp)[0] << 56); \ } while (0) #define BE_64_TO_8(cp, src) do { \ (cp)[0] = (src) >> 56; \ (cp)[1] = (src) >> 48; \ (cp)[2] = (src) >> 40; \ (cp)[3] = (src) >> 32; \ (cp)[4] = (src) >> 24; \ (cp)[5] = (src) >> 16; \ (cp)[6] = (src) >> 8; \ (cp)[7] = (src); \ } while (0) #define BE_32_TO_8(cp, src) do { \ (cp)[0] = (src) >> 24; \ (cp)[1] = (src) >> 16; \ (cp)[2] = (src) >> 8; \ (cp)[3] = (src); \ } while (0) /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) do { \ (w)[0] += (u_int64_t)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } while (0) /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-224/256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-224, SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-224 and SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-224, SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-224 and SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-224 and SHA-256: */ static const u_int32_t K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ static const u_int32_t sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; #if 0 /* Hash constant words K for SHA-384 and SHA-512: */ static const u_int64_t K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* Initial hash value H for SHA-512 */ static const u_int64_t sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; #if !defined(SHA2_SMALL) /* Initial hash value H for SHA-224: */ static const u_int32_t sha224_initial_hash_value[8] = { 0xc1059ed8UL, 0x367cd507UL, 0x3070dd17UL, 0xf70e5939UL, 0xffc00b31UL, 0x68581511UL, 0x64f98fa7UL, 0xbefa4fa4UL }; /* Initial hash value H for SHA-384 */ static const u_int64_t sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* Initial hash value H for SHA-512-256 */ static const u_int64_t sha512_256_initial_hash_value[8] = { 0x22312194fc2bf72cULL, 0x9f555fa3c84c64c2ULL, 0x2393b86b6f53b151ULL, 0x963877195940eabdULL, 0x96283ee2a88effe3ULL, 0xbe5e1e2553863992ULL, 0x2b0199fc2c85b8aaULL, 0x0eb72ddc81c52ca2ULL }; /*** SHA-224: *********************************************************/ void SHA224Init(SHA2_CTX *context) { memcpy(context->state.st32, sha224_initial_hash_value, sizeof(sha224_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = 0; } DEF_WEAK(SHA224Init); MAKE_CLONE(SHA224Transform, SHA256Transform); MAKE_CLONE(SHA224Update, SHA256Update); MAKE_CLONE(SHA224Pad, SHA256Pad); DEF_WEAK(SHA224Transform); DEF_WEAK(SHA224Update); DEF_WEAK(SHA224Pad); void SHA224Final(u_int8_t digest[SHA224_DIGEST_LENGTH], SHA2_CTX *context) { SHA224Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 7; i++) BE_32_TO_8(digest + i * 4, context->state.st32[i]); #else memcpy(digest, context->state.st32, SHA224_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA224Final); #endif /* !defined(SHA2_SMALL) */ #endif /* 0 */ /*** SHA-256: *********************************************************/ void SHA256Init(SHA2_CTX *context) { memcpy(context->state.st32, sha256_initial_hash_value, sizeof(sha256_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = 0; } DEF_WEAK(SHA256Init); #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \ BE_8_TO_32(W256[j], data); \ data += 4; \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND256(a,b,c,d,e,f,g,h) do { \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 63: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, T2, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { BE_8_TO_32(W256[j], data); data += 4; /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ DEF_WEAK(SHA256Transform); void SHA256Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { u_int64_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); context->bitcount[0] += freespace << 3; len -= freespace; data += freespace; SHA256Transform(context->state.st32, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); context->bitcount[0] += (u_int64_t)len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256Transform(context->state.st32, data); context->bitcount[0] += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); context->bitcount[0] += len << 3; } /* Clean up: */ usedspace = freespace = 0; } DEF_WEAK(SHA256Update); void SHA256Pad(SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256Transform(context->state.st32, context->buffer); /* Prepare for last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits) in big endian format: */ BE_64_TO_8(&context->buffer[SHA256_SHORT_BLOCK_LENGTH], context->bitcount[0]); /* Final transform: */ SHA256Transform(context->state.st32, context->buffer); /* Clean up: */ usedspace = 0; } DEF_WEAK(SHA256Pad); void SHA256Final(u_int8_t digest[SHA256_DIGEST_LENGTH], SHA2_CTX *context) { SHA256Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 8; i++) BE_32_TO_8(digest + i * 4, context->state.st32[i]); #else memcpy(digest, context->state.st32, SHA256_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA256Final); #if 0 /*** SHA-512: *********************************************************/ void SHA512Init(SHA2_CTX *context) { memcpy(context->state.st64, sha512_initial_hash_value, sizeof(sha512_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA512Init); #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \ BE_8_TO_64(W512[j], data); \ data += 8; \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND512(a,b,c,d,e,f,g,h) do { \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, T2, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { BE_8_TO_64(W512[j], data); data += 8; /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ DEF_WEAK(SHA512Transform); void SHA512Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512Transform(context->state.st64, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512Transform(context->state.st64, data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } DEF_WEAK(SHA512Update); void SHA512Pad(SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512Transform(context->state.st64, context->buffer); /* And set-up for the last transform: */ memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits) in big endian format: */ BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH], context->bitcount[1]); BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH + 8], context->bitcount[0]); /* Final transform: */ SHA512Transform(context->state.st64, context->buffer); /* Clean up: */ usedspace = 0; } DEF_WEAK(SHA512Pad); void SHA512Final(u_int8_t digest[SHA512_DIGEST_LENGTH], SHA2_CTX *context) { SHA512Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 8; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA512_DIGEST_LENGTH); #endif explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA512Final); #if !defined(SHA2_SMALL) /*** SHA-384: *********************************************************/ void SHA384Init(SHA2_CTX *context) { memcpy(context->state.st64, sha384_initial_hash_value, sizeof(sha384_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA384Init); MAKE_CLONE(SHA384Transform, SHA512Transform); MAKE_CLONE(SHA384Update, SHA512Update); MAKE_CLONE(SHA384Pad, SHA512Pad); DEF_WEAK(SHA384Transform); DEF_WEAK(SHA384Update); DEF_WEAK(SHA384Pad); /* Equivalent of MAKE_CLONE (which is a no-op) for SHA384 funcs */ void SHA384Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH]) { SHA512Transform(state, data); } void SHA384Update(SHA2_CTX *context, const u_int8_t *data, size_t len) { SHA512Update(context, data, len); } void SHA384Pad(SHA2_CTX *context) { SHA512Pad(context); } void SHA384Final(u_int8_t digest[SHA384_DIGEST_LENGTH], SHA2_CTX *context) { SHA384Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 6; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA384_DIGEST_LENGTH); #endif /* Zero out state data */ explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA384Final); /*** SHA-512/256: *********************************************************/ void SHA512_256Init(SHA2_CTX *context) { memcpy(context->state.st64, sha512_256_initial_hash_value, sizeof(sha512_256_initial_hash_value)); memset(context->buffer, 0, sizeof(context->buffer)); context->bitcount[0] = context->bitcount[1] = 0; } DEF_WEAK(SHA512_256Init); MAKE_CLONE(SHA512_256Transform, SHA512Transform); MAKE_CLONE(SHA512_256Update, SHA512Update); MAKE_CLONE(SHA512_256Pad, SHA512Pad); DEF_WEAK(SHA512_256Transform); DEF_WEAK(SHA512_256Update); DEF_WEAK(SHA512_256Pad); void SHA512_256Final(u_int8_t digest[SHA512_256_DIGEST_LENGTH], SHA2_CTX *context) { SHA512_256Pad(context); #if BYTE_ORDER == LITTLE_ENDIAN int i; /* Convert TO host byte order */ for (i = 0; i < 4; i++) BE_64_TO_8(digest + i * 8, context->state.st64[i]); #else memcpy(digest, context->state.st64, SHA512_256_DIGEST_LENGTH); #endif /* Zero out state data */ explicit_bzero(context, sizeof(*context)); } DEF_WEAK(SHA512_256Final); #endif /* !defined(SHA2_SMALL) */ #endif /* 0 */ #endif /* HAVE_SHA{256,384,512}UPDATE */ got-portable-0.119/compat/reallocarray.c0000664000175000017500000000255415066536113013731 /* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */ /* * Copyright (c) 2008 Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "got_compat.h" /* * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) void * reallocarray(void *optr, size_t nmemb, size_t size) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return realloc(optr, size * nmemb); } got-portable-0.119/compat/landlock.c0000664000175000017500000000711615066536113013037 /* * Copyright (c) 2021 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "got_compat.h" /* * What's the deal with landlock? While distro with linux >= 5.13 * have the struct declarations, libc wrappers are missing. The * sample landlock code provided by the authors includes these "shims" * in their example for the landlock API until libc provides them. */ #ifndef landlock_create_ruleset static inline int landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size, __u32 flags) { return syscall(__NR_landlock_create_ruleset, attr, size, flags); } #endif #ifndef landlock_add_rule static inline int landlock_add_rule(int ruleset_fd, enum landlock_rule_type type, const void *attr, __u32 flags) { return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags); } #endif #ifndef landlock_restrict_self static inline int landlock_restrict_self(int ruleset_fd, __u32 flags) { return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); } #endif /* * Maybe we should ship with a full copy of the linux headers because * you never know... */ #ifndef LANDLOCK_ACCESS_FS_REFER #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) #endif #ifndef LANDLOCK_ACCESS_FS_TRUNCATE #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) #endif /* * Revoke any fs access. */ int landlock_no_fs(void) { struct landlock_ruleset_attr rattr = { /* * List all capabilities currently defined by landlock. * Failure in doing so will implicitly allow those actions * (i.e. omitting READ_FILE will allow to read _any_ file.) */ .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_REMOVE_DIR | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_MAKE_CHAR | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_MAKE_SOCK | LANDLOCK_ACCESS_FS_MAKE_FIFO | LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_TRUNCATE, }; int fd, abi, saved_errno; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) return -1; abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); if (abi == -1) { /* this kernel doesn't have landlock built in */ if (errno == ENOSYS || errno == EOPNOTSUPP) return 0; return -1; } if (abi < 2) rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; if (abi < 3) rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; fd = landlock_create_ruleset(&rattr, sizeof(rattr), 0); if (fd == -1) return -1; if (landlock_restrict_self(fd, 0)) { saved_errno = errno; close(fd); errno = saved_errno; return -1; } close(fd); return 0; } got-portable-0.119/compat/strndup.c0000664000175000017500000000223215066536113012741 /* $OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */ /* * Copyright (c) 2010 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include char * strndup(const char *str, size_t maxlen) { char *copy; size_t len; len = strnlen(str, maxlen); copy = malloc(len + 1); if (copy != NULL) { (void)memcpy(copy, str, len); copy[len] = '\0'; } return copy; } got-portable-0.119/compat/bsd-poll.c0000664000175000017500000000620615066536113012763 /* * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au). * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_SYS_SELECT_H # include #endif #include #include #include #include "bsd-poll.h" #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif #ifndef howmany #define howmany(x,y) (((x)+((y)-1))/(y)) #endif /* * A minimal implementation of ppoll(2), built on top of pselect(2). * * Only supports POLLIN, POLLOUT and POLLPRI flags in pfd.events and * revents. Notably POLLERR, POLLHUP and POLLNVAL are not supported. * * Supports pfd.fd = -1 meaning "unused" although it's not standard. */ int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmoutp, const sigset_t *sigmask) { nfds_t i; int saved_errno, ret, fd, maxfd = 0; fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL; size_t nmemb; for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd != -1 && fd >= FD_SETSIZE) { errno = EINVAL; return -1; } maxfd = MAX(maxfd, fd); } nmemb = howmany(maxfd + 1 , NFDBITS); if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL || (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL || (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) { saved_errno = ENOMEM; ret = -1; goto out; } /* populate event bit vectors for the events we're interested in */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; if (fd == -1) continue; if (fds[i].events & POLLIN) FD_SET(fd, readfds); if (fds[i].events & POLLOUT) FD_SET(fd, writefds); if (fds[i].events & POLLPRI) FD_SET(fd, exceptfds); } ret = pselect(maxfd + 1, readfds, writefds, exceptfds, tmoutp, sigmask); saved_errno = errno; /* scan through select results and set poll() flags */ for (i = 0; i < nfds; i++) { fd = fds[i].fd; fds[i].revents = 0; if (fd == -1) continue; if (FD_ISSET(fd, readfds)) fds[i].revents |= POLLIN; if (FD_ISSET(fd, writefds)) fds[i].revents |= POLLOUT; if (FD_ISSET(fd, exceptfds)) fds[i].revents |= POLLPRI; } out: free(readfds); free(writefds); free(exceptfds); if (ret == -1) errno = saved_errno; return ret; } #if 0 int poll(struct pollfd *fds, nfds_t nfds, int timeout) { struct timespec ts, *tsp = NULL; /* poll timeout is msec, ppoll is timespec (sec + nsec) */ if (timeout >= 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; tsp = &ts; } return ppoll(fds, nfds, tsp, NULL); } #endif got-portable-0.119/compat/imsg.h0000664000175000017500000001444615066536113012220 /* $OpenBSD: imsg.h,v 1.24 2025/06/05 08:55:07 tb Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2006, 2007 Pierre-Yves Ritschard * Copyright (c) 2006, 2007, 2008 Reyk Floeter * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _IMSG_H_ #define _IMSG_H_ #include #include #include #include #define IBUF_READ_SIZE 65535 #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 16384 struct ibuf { TAILQ_ENTRY(ibuf) entry; unsigned char *buf; size_t size; size_t max; size_t wpos; size_t rpos; int fd; }; struct ibufqueue; struct msgbuf; struct imsgbuf { struct msgbuf *w; pid_t pid; uint32_t maxsize; int fd; int flags; }; struct imsg_hdr { uint32_t type; uint32_t len; uint32_t peerid; uint32_t pid; }; struct imsg { struct imsg_hdr hdr; void *data; struct ibuf *buf; }; struct iovec; /* imsg-buffer.c */ struct ibuf *ibuf_open(size_t); struct ibuf *ibuf_dynamic(size_t, size_t); int ibuf_add(struct ibuf *, const void *, size_t); int ibuf_add_ibuf(struct ibuf *, const struct ibuf *); int ibuf_add_zero(struct ibuf *, size_t); int ibuf_add_n8(struct ibuf *, uint64_t); int ibuf_add_n16(struct ibuf *, uint64_t); int ibuf_add_n32(struct ibuf *, uint64_t); int ibuf_add_n64(struct ibuf *, uint64_t); int ibuf_add_h16(struct ibuf *, uint64_t); int ibuf_add_h32(struct ibuf *, uint64_t); int ibuf_add_h64(struct ibuf *, uint64_t); int ibuf_add_strbuf(struct ibuf *, const char *, size_t); void *ibuf_reserve(struct ibuf *, size_t); void *ibuf_seek(struct ibuf *, size_t, size_t); int ibuf_set(struct ibuf *, size_t, const void *, size_t); int ibuf_set_n8(struct ibuf *, size_t, uint64_t); int ibuf_set_n16(struct ibuf *, size_t, uint64_t); int ibuf_set_n32(struct ibuf *, size_t, uint64_t); int ibuf_set_n64(struct ibuf *, size_t, uint64_t); int ibuf_set_h16(struct ibuf *, size_t, uint64_t); int ibuf_set_h32(struct ibuf *, size_t, uint64_t); int ibuf_set_h64(struct ibuf *, size_t, uint64_t); int ibuf_set_maxsize(struct ibuf *, size_t); void *ibuf_data(const struct ibuf *); size_t ibuf_size(const struct ibuf *); size_t ibuf_left(const struct ibuf *); int ibuf_truncate(struct ibuf *, size_t); void ibuf_rewind(struct ibuf *); void ibuf_close(struct msgbuf *, struct ibuf *); void ibuf_from_buffer(struct ibuf *, void *, size_t); void ibuf_from_ibuf(struct ibuf *, const struct ibuf *); int ibuf_get(struct ibuf *, void *, size_t); int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *); int ibuf_get_n8(struct ibuf *, uint8_t *); int ibuf_get_n16(struct ibuf *, uint16_t *); int ibuf_get_n32(struct ibuf *, uint32_t *); int ibuf_get_n64(struct ibuf *, uint64_t *); int ibuf_get_h16(struct ibuf *, uint16_t *); int ibuf_get_h32(struct ibuf *, uint32_t *); int ibuf_get_h64(struct ibuf *, uint64_t *); char *ibuf_get_string(struct ibuf *, size_t); int ibuf_get_strbuf(struct ibuf *, char *, size_t); int ibuf_skip(struct ibuf *, size_t); void ibuf_free(struct ibuf *); int ibuf_fd_avail(struct ibuf *); int ibuf_fd_get(struct ibuf *); void ibuf_fd_set(struct ibuf *, int); struct msgbuf *msgbuf_new(void); struct msgbuf *msgbuf_new_reader(size_t, struct ibuf *(*)(struct ibuf *, void *, int *), void *); void msgbuf_free(struct msgbuf *); void msgbuf_clear(struct msgbuf *); void msgbuf_concat(struct msgbuf *, struct ibufqueue *); uint32_t msgbuf_queuelen(struct msgbuf *); int ibuf_write(int, struct msgbuf *); int msgbuf_write(int, struct msgbuf *); int ibuf_read(int, struct msgbuf *); int msgbuf_read(int, struct msgbuf *); struct ibuf *msgbuf_get(struct msgbuf *); struct ibufqueue *ibufq_new(void); void ibufq_free(struct ibufqueue *); struct ibuf *ibufq_pop(struct ibufqueue *bufq); void ibufq_push(struct ibufqueue *, struct ibuf *); uint32_t ibufq_queuelen(struct ibufqueue *); void ibufq_concat(struct ibufqueue *, struct ibufqueue *); void ibufq_flush(struct ibufqueue *); /* imsg.c */ int imsgbuf_init(struct imsgbuf *, int); void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf); int imsgbuf_set_maxsize(struct imsgbuf *, uint32_t); int imsgbuf_read(struct imsgbuf *); int imsgbuf_write(struct imsgbuf *); int imsgbuf_flush(struct imsgbuf *); void imsgbuf_clear(struct imsgbuf *); uint32_t imsgbuf_queuelen(struct imsgbuf *); int imsgbuf_get(struct imsgbuf *, struct imsg *); ssize_t imsg_get(struct imsgbuf *, struct imsg *); int imsg_ibufq_pop(struct ibufqueue *, struct imsg *); void imsg_ibufq_push(struct ibufqueue *, struct imsg *); int imsg_get_ibuf(struct imsg *, struct ibuf *); int imsg_get_data(struct imsg *, void *, size_t); int imsg_get_buf(struct imsg *, void *, size_t); int imsg_get_strbuf(struct imsg *, char *, size_t); int imsg_get_fd(struct imsg *); uint32_t imsg_get_id(struct imsg *); size_t imsg_get_len(struct imsg *); pid_t imsg_get_pid(struct imsg *); uint32_t imsg_get_type(struct imsg *); int imsg_forward(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, const void *, size_t); int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, const struct iovec *, int); int imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t, struct ibuf *); struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t); int imsg_add(struct ibuf *, const void *, size_t); void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_free(struct imsg *); int imsg_set_maxsize(struct ibuf *, size_t); #endif got-portable-0.119/compat/getprogname.c0000664000175000017500000000224215066536113013553 /* * Copyright (c) 2016 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) const char * getprogname(void) { return (program_invocation_short_name); } #elif defined(HAVE___PROGNAME) const char * getprogname(void) { extern char *__progname; return (__progname); } #else const char * getprogname(void) { return ("got"); } #endif got-portable-0.119/compat/imsg.c0000664000175000017500000002102715066536113012204 /* $OpenBSD: imsg.c,v 1.42 2025/06/16 13:56:11 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "imsg.h" #define IMSG_ALLOW_FDPASS 0x01 #define IMSG_FD_MARK 0x80000000U static struct ibuf *imsg_parse_hdr(struct ibuf *, void *, int *); int imsgbuf_init(struct imsgbuf *imsgbuf, int fd) { imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr, imsgbuf); if (imsgbuf->w == NULL) return (-1); imsgbuf->pid = getpid(); imsgbuf->maxsize = MAX_IMSGSIZE; imsgbuf->fd = fd; imsgbuf->flags = 0; return (0); } void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf) { imsgbuf->flags |= IMSG_ALLOW_FDPASS; } int imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t max) { if (max > UINT32_MAX - IMSG_HEADER_SIZE) { errno = ERANGE; return (-1); } max += IMSG_HEADER_SIZE; if (max & IMSG_FD_MARK) { errno = EINVAL; return (-1); } imsgbuf->maxsize = max; return (0); } int imsgbuf_read(struct imsgbuf *imsgbuf) { if (imsgbuf->flags & IMSG_ALLOW_FDPASS) return msgbuf_read(imsgbuf->fd, imsgbuf->w); else return ibuf_read(imsgbuf->fd, imsgbuf->w); } int imsgbuf_write(struct imsgbuf *imsgbuf) { if (imsgbuf->flags & IMSG_ALLOW_FDPASS) return msgbuf_write(imsgbuf->fd, imsgbuf->w); else return ibuf_write(imsgbuf->fd, imsgbuf->w); } int imsgbuf_flush(struct imsgbuf *imsgbuf) { while (imsgbuf_queuelen(imsgbuf) > 0) { if (imsgbuf_write(imsgbuf) == -1) return (-1); } return (0); } void imsgbuf_clear(struct imsgbuf *imsgbuf) { msgbuf_free(imsgbuf->w); imsgbuf->w = NULL; } uint32_t imsgbuf_queuelen(struct imsgbuf *imsgbuf) { return msgbuf_queuelen(imsgbuf->w); } int imsgbuf_get(struct imsgbuf *imsgbuf, struct imsg *imsg) { struct imsg m; struct ibuf *buf; if ((buf = msgbuf_get(imsgbuf->w)) == NULL) return (0); if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1) return (-1); if (ibuf_size(buf)) m.data = ibuf_data(buf); else m.data = NULL; m.buf = buf; m.hdr.len &= ~IMSG_FD_MARK; *imsg = m; return (1); } ssize_t imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg) { int rv; if ((rv = imsgbuf_get(imsgbuf, imsg)) != 1) return rv; return (imsg_get_len(imsg) + IMSG_HEADER_SIZE); } int imsg_ibufq_pop(struct ibufqueue *bufq, struct imsg *imsg) { struct imsg m; struct ibuf *buf; if ((buf = ibufq_pop(bufq)) == NULL) return (0); if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1) return (-1); if (ibuf_size(buf)) m.data = ibuf_data(buf); else m.data = NULL; m.buf = buf; m.hdr.len &= ~IMSG_FD_MARK; *imsg = m; return (1); } void imsg_ibufq_push(struct ibufqueue *bufq, struct imsg *imsg) { ibuf_rewind(imsg->buf); ibufq_push(bufq, imsg->buf); memset(imsg, 0, sizeof(*imsg)); } int imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf) { if (ibuf_size(imsg->buf) == 0) { errno = EBADMSG; return (-1); } return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf); } int imsg_get_data(struct imsg *imsg, void *data, size_t len) { if (len == 0) { errno = EINVAL; return (-1); } if (ibuf_size(imsg->buf) != len) { errno = EBADMSG; return (-1); } return ibuf_get(imsg->buf, data, len); } int imsg_get_buf(struct imsg *imsg, void *data, size_t len) { return ibuf_get(imsg->buf, data, len); } int imsg_get_strbuf(struct imsg *imsg, char *str, size_t len) { return ibuf_get_strbuf(imsg->buf, str, len); } int imsg_get_fd(struct imsg *imsg) { return ibuf_fd_get(imsg->buf); } uint32_t imsg_get_id(struct imsg *imsg) { return (imsg->hdr.peerid); } size_t imsg_get_len(struct imsg *imsg) { return ibuf_size(imsg->buf); } pid_t imsg_get_pid(struct imsg *imsg) { return (imsg->hdr.pid); } uint32_t imsg_get_type(struct imsg *imsg) { return (imsg->hdr.type); } int imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, int fd, const void *data, size_t datalen) { struct ibuf *wbuf; if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) goto fail; if (ibuf_add(wbuf, data, datalen) == -1) goto fail; ibuf_fd_set(wbuf, fd); imsg_close(imsgbuf, wbuf); return (1); fail: ibuf_free(wbuf); return (-1); } int imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, int fd, const struct iovec *iov, int iovcnt) { struct ibuf *wbuf; int i; size_t datalen = 0; for (i = 0; i < iovcnt; i++) datalen += iov[i].iov_len; if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) goto fail; for (i = 0; i < iovcnt; i++) if (ibuf_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) goto fail; ibuf_fd_set(wbuf, fd); imsg_close(imsgbuf, wbuf); return (1); fail: ibuf_free(wbuf); return (-1); } /* * Enqueue imsg with payload from ibuf buf. fd passing is not possible * with this function. */ int imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, struct ibuf *buf) { struct ibuf *hdrbuf = NULL; struct imsg_hdr hdr; if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) { errno = ERANGE; goto fail; } hdr.type = type; hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL) goto fail; if (ibuf_add(hdrbuf, &hdr, sizeof(hdr)) == -1) goto fail; ibuf_close(imsgbuf->w, hdrbuf); ibuf_close(imsgbuf->w, buf); return (1); fail: ibuf_free(buf); ibuf_free(hdrbuf); return (-1); } /* * Forward imsg to another channel. Any attached fd is closed. */ int imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg) { struct ibuf *wbuf; size_t len; ibuf_rewind(msg->buf); ibuf_skip(msg->buf, sizeof(msg->hdr)); len = ibuf_size(msg->buf); if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid, msg->hdr.pid, len)) == NULL) return (-1); if (len != 0) { if (ibuf_add_ibuf(wbuf, msg->buf) == -1) { ibuf_free(wbuf); return (-1); } } imsg_close(imsgbuf, wbuf); return (1); } struct ibuf * imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, size_t datalen) { struct ibuf *wbuf; struct imsg_hdr hdr; datalen += IMSG_HEADER_SIZE; if (datalen > imsgbuf->maxsize) { errno = ERANGE; return (NULL); } hdr.len = 0; hdr.type = type; hdr.peerid = id; if ((hdr.pid = pid) == 0) hdr.pid = imsgbuf->pid; if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) goto fail; if (ibuf_add(wbuf, &hdr, sizeof(hdr)) == -1) goto fail; return (wbuf); fail: ibuf_free(wbuf); return (NULL); } int imsg_add(struct ibuf *msg, const void *data, size_t datalen) { if (datalen) if (ibuf_add(msg, data, datalen) == -1) { ibuf_free(msg); return (-1); } return (datalen); } void imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg) { uint32_t len; len = ibuf_size(msg); if (ibuf_fd_avail(msg)) len |= IMSG_FD_MARK; (void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len); ibuf_close(imsgbuf->w, msg); } void imsg_free(struct imsg *imsg) { ibuf_free(imsg->buf); } int imsg_set_maxsize(struct ibuf *msg, size_t max) { if (max > UINT32_MAX - IMSG_HEADER_SIZE) { errno = ERANGE; return (-1); } return ibuf_set_maxsize(msg, max + IMSG_HEADER_SIZE); } static struct ibuf * imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd) { struct imsgbuf *imsgbuf = arg; struct imsg_hdr hdr; struct ibuf *b; uint32_t len; if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1) return (NULL); len = hdr.len & ~IMSG_FD_MARK; if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) { errno = ERANGE; return (NULL); } if ((b = ibuf_open(len)) == NULL) return (NULL); if (hdr.len & IMSG_FD_MARK) { ibuf_fd_set(b, *fd); *fd = -1; } return b; } got-portable-0.119/compat/asprintf.c0000664000175000017500000000300115066536113013063 /* * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include int vasprintf(char **, const char *, va_list); int asprintf(char **ret, const char *fmt, ...) { va_list ap; int n; va_start(ap, fmt); n = vasprintf(ret, fmt, ap); va_end(ap); return (n); } int vasprintf(char **ret, const char *fmt, va_list ap) { int n; va_list ap2; va_copy(ap2, ap); if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) goto error; *ret = malloc(n + 1); if (*ret == NULL) errx(1, "vasprintf: malloc failed"); if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) { free(*ret); goto error; } va_end(ap2); return (n); error: va_end(ap2); *ret = NULL; return (-1); } got-portable-0.119/compat/imsg-buffer.c0000664000175000017500000004537715066536113013471 /* $OpenBSD: imsg-buffer.c,v 1.36 2025/08/25 08:29:49 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker * Copyright (c) 2003, 2004 Henning Brauer * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "imsg.h" struct ibufqueue { TAILQ_HEAD(, ibuf) bufs; uint32_t queued; }; struct msgbuf { struct ibufqueue bufs; struct ibufqueue rbufs; char *rbuf; struct ibuf *rpmsg; struct ibuf *(*readhdr)(struct ibuf *, void *, int *); void *rarg; size_t roff; size_t hdrsize; }; static void msgbuf_drain(struct msgbuf *, size_t); static void ibufq_init(struct ibufqueue *); #define IBUF_FD_MARK_ON_STACK -2 struct ibuf * ibuf_open(size_t len) { struct ibuf *buf; if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if (len > 0) { if ((buf->buf = calloc(len, 1)) == NULL) { free(buf); return (NULL); } } buf->size = buf->max = len; buf->fd = -1; return (buf); } struct ibuf * ibuf_dynamic(size_t len, size_t max) { struct ibuf *buf; if (max == 0 || max < len) { errno = EINVAL; return (NULL); } if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) return (NULL); if (len > 0) { if ((buf->buf = calloc(len, 1)) == NULL) { free(buf); return (NULL); } } buf->size = len; buf->max = max; buf->fd = -1; return (buf); } void * ibuf_reserve(struct ibuf *buf, size_t len) { void *b; if (len > SIZE_MAX - buf->wpos) { errno = ERANGE; return (NULL); } if (buf->fd == IBUF_FD_MARK_ON_STACK) { /* can not grow stack buffers */ errno = EINVAL; return (NULL); } if (buf->wpos + len > buf->size) { unsigned char *nb; /* check if buffer is allowed to grow */ if (buf->wpos + len > buf->max) { errno = ERANGE; return (NULL); } nb = realloc(buf->buf, buf->wpos + len); if (nb == NULL) return (NULL); memset(nb + buf->size, 0, buf->wpos + len - buf->size); buf->buf = nb; buf->size = buf->wpos + len; } b = buf->buf + buf->wpos; buf->wpos += len; return (b); } int ibuf_add(struct ibuf *buf, const void *data, size_t len) { void *b; if (len == 0) return (0); if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); memcpy(b, data, len); return (0); } int ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from) { return ibuf_add(buf, ibuf_data(from), ibuf_size(from)); } int ibuf_add_n8(struct ibuf *buf, uint64_t value) { uint8_t v; if (value > UINT8_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n16(struct ibuf *buf, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = htobe16(value); return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n32(struct ibuf *buf, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = htobe32(value); return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_n64(struct ibuf *buf, uint64_t value) { value = htobe64(value); return ibuf_add(buf, &value, sizeof(value)); } int ibuf_add_h16(struct ibuf *buf, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_h32(struct ibuf *buf, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = value; return ibuf_add(buf, &v, sizeof(v)); } int ibuf_add_h64(struct ibuf *buf, uint64_t value) { return ibuf_add(buf, &value, sizeof(value)); } int ibuf_add_zero(struct ibuf *buf, size_t len) { void *b; if (len == 0) return (0); if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); memset(b, 0, len); return (0); } int ibuf_add_strbuf(struct ibuf *buf, const char *str, size_t len) { char *b; size_t n; if ((b = ibuf_reserve(buf, len)) == NULL) return (-1); n = strlcpy(b, str, len); if (n >= len) { /* also covers the case where len == 0 */ errno = EOVERFLOW; return (-1); } memset(b + n, 0, len - n); return (0); } void * ibuf_seek(struct ibuf *buf, size_t pos, size_t len) { /* only allow seeking between rpos and wpos */ if (ibuf_size(buf) < pos || SIZE_MAX - pos < len || ibuf_size(buf) < pos + len) { errno = ERANGE; return (NULL); } return (buf->buf + buf->rpos + pos); } int ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len) { void *b; if ((b = ibuf_seek(buf, pos, len)) == NULL) return (-1); if (len == 0) return (0); memcpy(b, data, len); return (0); } int ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value) { uint8_t v; if (value > UINT8_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = htobe16(value); return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = htobe32(value); return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value) { value = htobe64(value); return (ibuf_set(buf, pos, &value, sizeof(value))); } int ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value) { uint16_t v; if (value > UINT16_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value) { uint32_t v; if (value > UINT32_MAX) { errno = EINVAL; return (-1); } v = value; return (ibuf_set(buf, pos, &v, sizeof(v))); } int ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value) { return (ibuf_set(buf, pos, &value, sizeof(value))); } int ibuf_set_maxsize(struct ibuf *buf, size_t max) { if (buf->fd == IBUF_FD_MARK_ON_STACK) { /* can't fiddle with stack buffers */ errno = EINVAL; return (-1); } if (max > buf->max) { errno = ERANGE; return (-1); } buf->max = max; return (0); } void * ibuf_data(const struct ibuf *buf) { return (buf->buf + buf->rpos); } size_t ibuf_size(const struct ibuf *buf) { return (buf->wpos - buf->rpos); } size_t ibuf_left(const struct ibuf *buf) { /* on stack buffers have no space left */ if (buf->fd == IBUF_FD_MARK_ON_STACK) return (0); return (buf->max - buf->wpos); } int ibuf_truncate(struct ibuf *buf, size_t len) { if (ibuf_size(buf) >= len) { buf->wpos = buf->rpos + len; return (0); } if (buf->fd == IBUF_FD_MARK_ON_STACK) { /* only allow to truncate down for stack buffers */ errno = ERANGE; return (-1); } return ibuf_add_zero(buf, len - ibuf_size(buf)); } void ibuf_rewind(struct ibuf *buf) { buf->rpos = 0; } void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) { ibufq_push(&msgbuf->bufs, buf); } void ibuf_from_buffer(struct ibuf *buf, void *data, size_t len) { memset(buf, 0, sizeof(*buf)); buf->buf = data; buf->size = buf->wpos = len; buf->fd = IBUF_FD_MARK_ON_STACK; } void ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from) { ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from)); } int ibuf_get(struct ibuf *buf, void *data, size_t len) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } memcpy(data, ibuf_data(buf), len); buf->rpos += len; return (0); } int ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } ibuf_from_buffer(new, ibuf_data(buf), len); buf->rpos += len; return (0); } int ibuf_get_h16(struct ibuf *buf, uint16_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_h32(struct ibuf *buf, uint32_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_h64(struct ibuf *buf, uint64_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_n8(struct ibuf *buf, uint8_t *value) { return ibuf_get(buf, value, sizeof(*value)); } int ibuf_get_n16(struct ibuf *buf, uint16_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be16toh(*value); return (rv); } int ibuf_get_n32(struct ibuf *buf, uint32_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be32toh(*value); return (rv); } int ibuf_get_n64(struct ibuf *buf, uint64_t *value) { int rv; rv = ibuf_get(buf, value, sizeof(*value)); *value = be64toh(*value); return (rv); } char * ibuf_get_string(struct ibuf *buf, size_t len) { char *str; if (ibuf_size(buf) < len) { errno = EBADMSG; return (NULL); } str = strndup(ibuf_data(buf), len); if (str == NULL) return (NULL); buf->rpos += len; return (str); } int ibuf_get_strbuf(struct ibuf *buf, char *str, size_t len) { if (len == 0) { errno = EINVAL; return (-1); } if (ibuf_get(buf, str, len) == -1) return -1; if (str[len - 1] != '\0') { str[len - 1] = '\0'; errno = EOVERFLOW; return -1; } return 0; } int ibuf_skip(struct ibuf *buf, size_t len) { if (ibuf_size(buf) < len) { errno = EBADMSG; return (-1); } buf->rpos += len; return (0); } void ibuf_free(struct ibuf *buf) { int save_errno = errno; if (buf == NULL) return; /* if buf lives on the stack abort before causing more harm */ if (buf->fd == IBUF_FD_MARK_ON_STACK) abort(); if (buf->fd >= 0) close(buf->fd); freezero(buf->buf, buf->size); free(buf); errno = save_errno; } int ibuf_fd_avail(struct ibuf *buf) { return (buf->fd >= 0); } int ibuf_fd_get(struct ibuf *buf) { int fd; /* negative fds are internal use and equivalent to -1 */ if (buf->fd < 0) return (-1); fd = buf->fd; buf->fd = -1; return (fd); } void ibuf_fd_set(struct ibuf *buf, int fd) { /* if buf lives on the stack abort before causing more harm */ if (buf->fd == IBUF_FD_MARK_ON_STACK) abort(); if (buf->fd >= 0) close(buf->fd); buf->fd = -1; if (fd >= 0) buf->fd = fd; } struct msgbuf * msgbuf_new(void) { struct msgbuf *msgbuf; if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL) return (NULL); ibufq_init(&msgbuf->bufs); ibufq_init(&msgbuf->rbufs); return msgbuf; } struct msgbuf * msgbuf_new_reader(size_t hdrsz, struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg) { struct msgbuf *msgbuf; char *buf; if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) { errno = EINVAL; return (NULL); } if ((buf = malloc(IBUF_READ_SIZE)) == NULL) return (NULL); msgbuf = msgbuf_new(); if (msgbuf == NULL) { free(buf); return (NULL); } msgbuf->rbuf = buf; msgbuf->hdrsize = hdrsz; msgbuf->readhdr = readhdr; msgbuf->rarg = arg; return (msgbuf); } void msgbuf_free(struct msgbuf *msgbuf) { if (msgbuf == NULL) return; msgbuf_clear(msgbuf); free(msgbuf->rbuf); free(msgbuf); } uint32_t msgbuf_queuelen(struct msgbuf *msgbuf) { return ibufq_queuelen(&msgbuf->bufs); } void msgbuf_clear(struct msgbuf *msgbuf) { /* write side */ ibufq_flush(&msgbuf->bufs); /* read side */ ibufq_flush(&msgbuf->rbufs); msgbuf->roff = 0; ibuf_free(msgbuf->rpmsg); msgbuf->rpmsg = NULL; } struct ibuf * msgbuf_get(struct msgbuf *msgbuf) { return ibufq_pop(&msgbuf->rbufs); } void msgbuf_concat(struct msgbuf *msgbuf, struct ibufqueue *from) { ibufq_concat(&msgbuf->bufs, from); } int ibuf_write(int fd, struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf; unsigned int i = 0; ssize_t n; memset(&iov, 0, sizeof(iov)); TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) { if (i >= IOV_MAX) break; iov[i].iov_base = ibuf_data(buf); iov[i].iov_len = ibuf_size(buf); i++; } if (i == 0) return (0); /* nothing queued */ again: if ((n = writev(fd, iov, i)) == -1) { if (errno == EINTR) goto again; if (errno == EAGAIN || errno == ENOBUFS) /* lets retry later again */ return (0); return (-1); } msgbuf_drain(msgbuf, n); return (0); } int msgbuf_write(int fd, struct msgbuf *msgbuf) { struct iovec iov[IOV_MAX]; struct ibuf *buf, *buf0 = NULL; unsigned int i = 0; ssize_t n; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int))]; } cmsgbuf; memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) { if (i >= IOV_MAX) break; if (i > 0 && buf->fd != -1) break; iov[i].iov_base = ibuf_data(buf); iov[i].iov_len = ibuf_size(buf); i++; if (buf->fd != -1) buf0 = buf; } if (i == 0) return (0); /* nothing queued */ msg.msg_iov = iov; msg.msg_iovlen = i; if (buf0 != NULL) { msg.msg_control = (caddr_t)&cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = buf0->fd; } again: if ((n = sendmsg(fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; if (errno == EAGAIN || errno == ENOBUFS) /* lets retry later again */ return (0); return (-1); } /* * assumption: fd got sent if sendmsg sent anything * this works because fds are passed one at a time */ if (buf0 != NULL) { close(buf0->fd); buf0->fd = -1; } msgbuf_drain(msgbuf, n); return (0); } static int ibuf_read_process(struct msgbuf *msgbuf, int fd) { struct ibuf rbuf, msg; ssize_t sz; ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff); do { if (msgbuf->rpmsg == NULL) { if (ibuf_size(&rbuf) < msgbuf->hdrsize) break; /* get size from header */ ibuf_from_buffer(&msg, ibuf_data(&rbuf), msgbuf->hdrsize); if ((msgbuf->rpmsg = msgbuf->readhdr(&msg, msgbuf->rarg, &fd)) == NULL) goto fail; } if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf)) sz = ibuf_left(msgbuf->rpmsg); else sz = ibuf_size(&rbuf); /* neither call below can fail */ if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 || ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1) goto fail; if (ibuf_left(msgbuf->rpmsg) == 0) { ibufq_push(&msgbuf->rbufs, msgbuf->rpmsg); msgbuf->rpmsg = NULL; } } while (ibuf_size(&rbuf) > 0); if (ibuf_size(&rbuf) > 0) memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf)); msgbuf->roff = ibuf_size(&rbuf); if (fd != -1) close(fd); return (1); fail: /* XXX how to properly clean up is unclear */ if (fd != -1) close(fd); return (-1); } int ibuf_read(int fd, struct msgbuf *msgbuf) { struct iovec iov; ssize_t n; if (msgbuf->rbuf == NULL) { errno = EINVAL; return (-1); } iov.iov_base = msgbuf->rbuf + msgbuf->roff; iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; again: if ((n = readv(fd, &iov, 1)) == -1) { if (errno == EINTR) goto again; if (errno == EAGAIN) /* lets retry later again */ return (1); return (-1); } if (n == 0) /* connection closed */ return (0); msgbuf->roff += n; /* new data arrived, try to process it */ return (ibuf_read_process(msgbuf, -1)); } int msgbuf_read(int fd, struct msgbuf *msgbuf) { struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(int) * 1)]; } cmsgbuf; struct iovec iov; ssize_t n; int fdpass = -1; if (msgbuf->rbuf == NULL) { errno = EINVAL; return (-1); } memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); iov.iov_base = msgbuf->rbuf + msgbuf->roff; iov.iov_len = IBUF_READ_SIZE - msgbuf->roff; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); again: if ((n = recvmsg(fd, &msg, 0)) == -1) { if (errno == EINTR) goto again; if (errno == EMSGSIZE) /* * Not enough fd slots: fd passing failed, retry * to receive the message without fd. * imsg_get_fd() will return -1 in that case. */ goto again; if (errno == EAGAIN) /* lets retry later again */ return (1); return (-1); } if (n == 0) /* connection closed */ return (0); msgbuf->roff += n; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int i, j, f; /* * We only accept one file descriptor. Due to C * padding rules, our control buffer might contain * more than one fd, and we must close them. */ j = ((char *)cmsg + cmsg->cmsg_len - (char *)CMSG_DATA(cmsg)) / sizeof(int); for (i = 0; i < j; i++) { f = ((int *)CMSG_DATA(cmsg))[i]; if (i == 0) fdpass = f; else close(f); } } /* we do not handle other ctl data level */ } /* new data arrived, try to process it */ return (ibuf_read_process(msgbuf, fdpass)); } static void msgbuf_drain(struct msgbuf *msgbuf, size_t n) { struct ibuf *buf; while ((buf = TAILQ_FIRST(&msgbuf->bufs.bufs)) != NULL) { if (n >= ibuf_size(buf)) { n -= ibuf_size(buf); TAILQ_REMOVE(&msgbuf->bufs.bufs, buf, entry); msgbuf->bufs.queued--; ibuf_free(buf); } else { buf->rpos += n; return; } } } static void ibufq_init(struct ibufqueue *bufq) { TAILQ_INIT(&bufq->bufs); bufq->queued = 0; } struct ibufqueue * ibufq_new(void) { struct ibufqueue *bufq; if ((bufq = calloc(1, sizeof(*bufq))) == NULL) return NULL; ibufq_init(bufq); return bufq; } void ibufq_free(struct ibufqueue *bufq) { if (bufq == NULL) return; ibufq_flush(bufq); free(bufq); } struct ibuf * ibufq_pop(struct ibufqueue *bufq) { struct ibuf *buf; if ((buf = TAILQ_FIRST(&bufq->bufs)) == NULL) return NULL; TAILQ_REMOVE(&bufq->bufs, buf, entry); bufq->queued--; return buf; } void ibufq_push(struct ibufqueue *bufq, struct ibuf *buf) { /* if buf lives on the stack abort before causing more harm */ if (buf->fd == IBUF_FD_MARK_ON_STACK) abort(); TAILQ_INSERT_TAIL(&bufq->bufs, buf, entry); bufq->queued++; } uint32_t ibufq_queuelen(struct ibufqueue *bufq) { return (bufq->queued); } void ibufq_concat(struct ibufqueue *to, struct ibufqueue *from) { to->queued += from->queued; TAILQ_CONCAT(&to->bufs, &from->bufs, entry); from->queued = 0; } void ibufq_flush(struct ibufqueue *bufq) { struct ibuf *buf; while ((buf = TAILQ_FIRST(&bufq->bufs)) != NULL) { TAILQ_REMOVE(&bufq->bufs, buf, entry); ibuf_free(buf); } bufq->queued = 0; } got-portable-0.119/compat/freezero.c0000664000175000017500000000172415066536113013070 /* * Copyright (c) 2017 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include void freezero(void *ptr, size_t size) { if (ptr != NULL) { memset(ptr, 0, size); free(ptr); } } got-portable-0.119/compat/strlcat.c0000664000175000017500000000322315066536113012717 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } got-portable-0.119/compat/tree.h0000664000175000017500000006106415066536113012216 /* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) do {} while (0) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ attr struct type *name##_RB_INSERT(struct name *, struct type *); \ attr struct type *name##_RB_FIND(struct name *, struct type *); \ attr struct type *name##_RB_NFIND(struct name *, struct type *); \ attr struct type *name##_RB_NEXT(struct type *); \ attr struct type *name##_RB_PREV(struct type *); \ attr struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp,) #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ /* Finds the first node greater than or equal to the search key */ \ attr struct type * \ name##_RB_NFIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *res = NULL; \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) { \ res = tmp; \ tmp = RB_LEFT(tmp, field); \ } \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (res); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_PREV(struct type *elm) \ { \ if (RB_LEFT(elm, field)) { \ elm = RB_LEFT(elm, field); \ while (RB_RIGHT(elm, field)) \ elm = RB_RIGHT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #define RB_FOREACH_SAFE(x, name, head, y) \ for ((x) = RB_MIN(name, head); \ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ (x) = (y)) #define RB_FOREACH_REVERSE(x, name, head) \ for ((x) = RB_MAX(name, head); \ (x) != NULL; \ (x) = name##_RB_PREV(x)) #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ for ((x) = RB_MAX(name, head); \ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ (x) = (y)) #endif /* _SYS_TREE_H_ */ got-portable-0.119/compat/Makefile.in0000664000175000017500000006233715066537206013163 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ # For MacOS, don't build the compat versions of strl{cat,cpy}, but do for all # other systems. @HOST_DARWIN_FALSE@am__append_1 = strlcat.c strlcpy.c @HOST_DARWIN_TRUE@am__append_2 = uuid.c bsd-poll.c bsd-poll.h @HAVE_GETOPT_FALSE@am__append_3 = getopt.c @HAVE_B64_FALSE@am__append_4 = base64.c @HAVE_B64_FALSE@am__append_5 = $(libresolv_LIBS) @HAVE_CLOSEFROM_FALSE@am__append_6 = closefrom.c @HOST_NETBSD_TRUE@am__append_7 = bsd-poll.c bsd-poll.h @HOST_LINUX_TRUE@am__append_8 = uuid.c @HAVE_LINUX_LANDLOCK_TRUE@am__append_9 = landlock.c @HAVE_SIPHASH_FALSE@am__append_10 = siphash.c siphash.h @HAVE_SETPROCTITLE_FALSE@am__append_11 = setproctitle.c @HAVE_IMSG_FALSE@am__append_12 = imsg-buffer.c imsg.c @HAVE_SHA2_FALSE@@HOST_DARWIN_FALSE@am__append_13 = sha2.c sha2.h subdir = compat ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cr AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libopenbsd_compat_a_AR = $(AR) $(ARFLAGS) libopenbsd_compat_a_RANLIB = $(RANLIB) libopenbsd_compat_a_LIBADD = am__libopenbsd_compat_a_SOURCES_DIST = asprintf.c fmt_scaled.c \ freezero.c getdtablecount.c getprogname.c merge.c \ reallocarray.c recallocarray.c strndup.c strnlen.c strsep.c \ strtonum.c imsg.h tree.h strlcat.c strlcpy.c uuid.c bsd-poll.c \ bsd-poll.h getopt.c base64.c closefrom.c landlock.c siphash.c \ siphash.h setproctitle.c imsg-buffer.c imsg.c sha2.c sha2.h @HOST_DARWIN_FALSE@am__objects_1 = strlcat.$(OBJEXT) strlcpy.$(OBJEXT) @HOST_DARWIN_TRUE@am__objects_2 = uuid.$(OBJEXT) bsd-poll.$(OBJEXT) @HAVE_GETOPT_FALSE@am__objects_3 = getopt.$(OBJEXT) @HAVE_B64_FALSE@am__objects_4 = base64.$(OBJEXT) @HAVE_CLOSEFROM_FALSE@am__objects_5 = closefrom.$(OBJEXT) @HOST_NETBSD_TRUE@am__objects_6 = bsd-poll.$(OBJEXT) @HOST_LINUX_TRUE@am__objects_7 = uuid.$(OBJEXT) @HAVE_LINUX_LANDLOCK_TRUE@am__objects_8 = landlock.$(OBJEXT) @HAVE_SIPHASH_FALSE@am__objects_9 = siphash.$(OBJEXT) @HAVE_SETPROCTITLE_FALSE@am__objects_10 = setproctitle.$(OBJEXT) @HAVE_IMSG_FALSE@am__objects_11 = imsg-buffer.$(OBJEXT) imsg.$(OBJEXT) @HAVE_SHA2_FALSE@@HOST_DARWIN_FALSE@am__objects_12 = sha2.$(OBJEXT) am_libopenbsd_compat_a_OBJECTS = asprintf.$(OBJEXT) \ fmt_scaled.$(OBJEXT) freezero.$(OBJEXT) \ getdtablecount.$(OBJEXT) getprogname.$(OBJEXT) merge.$(OBJEXT) \ reallocarray.$(OBJEXT) recallocarray.$(OBJEXT) \ strndup.$(OBJEXT) strnlen.$(OBJEXT) strsep.$(OBJEXT) \ strtonum.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) \ $(am__objects_12) libopenbsd_compat_a_OBJECTS = $(am_libopenbsd_compat_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/asprintf.Po ./$(DEPDIR)/base64.Po \ ./$(DEPDIR)/bsd-poll.Po ./$(DEPDIR)/closefrom.Po \ ./$(DEPDIR)/fmt_scaled.Po ./$(DEPDIR)/freezero.Po \ ./$(DEPDIR)/getdtablecount.Po ./$(DEPDIR)/getopt.Po \ ./$(DEPDIR)/getprogname.Po ./$(DEPDIR)/imsg-buffer.Po \ ./$(DEPDIR)/imsg.Po ./$(DEPDIR)/landlock.Po \ ./$(DEPDIR)/merge.Po ./$(DEPDIR)/reallocarray.Po \ ./$(DEPDIR)/recallocarray.Po ./$(DEPDIR)/setproctitle.Po \ ./$(DEPDIR)/sha2.Po ./$(DEPDIR)/siphash.Po \ ./$(DEPDIR)/strlcat.Po ./$(DEPDIR)/strlcpy.Po \ ./$(DEPDIR)/strndup.Po ./$(DEPDIR)/strnlen.Po \ ./$(DEPDIR)/strsep.Po ./$(DEPDIR)/strtonum.Po \ ./$(DEPDIR)/uuid.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libopenbsd_compat_a_SOURCES) DIST_SOURCES = $(am__libopenbsd_compat_a_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ noinst_LIBRARIES = libopenbsd-compat.a LDADD = $(libbsd_LIBS) $(am__append_5) libopenbsd_compat_a_SOURCES = asprintf.c fmt_scaled.c freezero.c \ getdtablecount.c getprogname.c merge.c reallocarray.c \ recallocarray.c strndup.c strnlen.c strsep.c strtonum.c imsg.h \ tree.h $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_6) $(am__append_7) \ $(am__append_8) $(am__append_9) $(am__append_10) \ $(am__append_11) $(am__append_12) $(am__append_13) # Fake an assigment here. It does nothing, but you cannot have consecutive # nested if statements in Makefiles, so we have to do something here, even if # it's a dummy assignment. @HOST_DARWIN_FALSE@NOTING = something EXTRA_DIST = \ $(top_srcdir)/include/got_compat.h \ imsg.h \ tree.h \ bsd-poll.h all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign compat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign compat/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -$(am__rm_f) $(noinst_LIBRARIES) libopenbsd-compat.a: $(libopenbsd_compat_a_OBJECTS) $(libopenbsd_compat_a_DEPENDENCIES) $(EXTRA_libopenbsd_compat_a_DEPENDENCIES) $(AM_V_at)-rm -f libopenbsd-compat.a $(AM_V_AR)$(libopenbsd_compat_a_AR) libopenbsd-compat.a $(libopenbsd_compat_a_OBJECTS) $(libopenbsd_compat_a_LIBADD) $(AM_V_at)$(libopenbsd_compat_a_RANLIB) libopenbsd-compat.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asprintf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsd-poll.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/closefrom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt_scaled.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freezero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdtablecount.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getprogname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg-buffer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/landlock.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setproctitle.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/siphash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcat.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlcpy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strndup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnlen.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtonum.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uuid.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/asprintf.Po -rm -f ./$(DEPDIR)/base64.Po -rm -f ./$(DEPDIR)/bsd-poll.Po -rm -f ./$(DEPDIR)/closefrom.Po -rm -f ./$(DEPDIR)/fmt_scaled.Po -rm -f ./$(DEPDIR)/freezero.Po -rm -f ./$(DEPDIR)/getdtablecount.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getprogname.Po -rm -f ./$(DEPDIR)/imsg-buffer.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/landlock.Po -rm -f ./$(DEPDIR)/merge.Po -rm -f ./$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/recallocarray.Po -rm -f ./$(DEPDIR)/setproctitle.Po -rm -f ./$(DEPDIR)/sha2.Po -rm -f ./$(DEPDIR)/siphash.Po -rm -f ./$(DEPDIR)/strlcat.Po -rm -f ./$(DEPDIR)/strlcpy.Po -rm -f ./$(DEPDIR)/strndup.Po -rm -f ./$(DEPDIR)/strnlen.Po -rm -f ./$(DEPDIR)/strsep.Po -rm -f ./$(DEPDIR)/strtonum.Po -rm -f ./$(DEPDIR)/uuid.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/asprintf.Po -rm -f ./$(DEPDIR)/base64.Po -rm -f ./$(DEPDIR)/bsd-poll.Po -rm -f ./$(DEPDIR)/closefrom.Po -rm -f ./$(DEPDIR)/fmt_scaled.Po -rm -f ./$(DEPDIR)/freezero.Po -rm -f ./$(DEPDIR)/getdtablecount.Po -rm -f ./$(DEPDIR)/getopt.Po -rm -f ./$(DEPDIR)/getprogname.Po -rm -f ./$(DEPDIR)/imsg-buffer.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/landlock.Po -rm -f ./$(DEPDIR)/merge.Po -rm -f ./$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/recallocarray.Po -rm -f ./$(DEPDIR)/setproctitle.Po -rm -f ./$(DEPDIR)/sha2.Po -rm -f ./$(DEPDIR)/siphash.Po -rm -f ./$(DEPDIR)/strlcat.Po -rm -f ./$(DEPDIR)/strlcpy.Po -rm -f ./$(DEPDIR)/strndup.Po -rm -f ./$(DEPDIR)/strnlen.Po -rm -f ./$(DEPDIR)/strsep.Po -rm -f ./$(DEPDIR)/strtonum.Po -rm -f ./$(DEPDIR)/uuid.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/compat/bsd-poll.h0000664000175000017500000000411615066536113012766 /* $OpenBSD: poll.h,v 1.11 2003/12/10 23:10:08 millert Exp $ */ /* * Copyright (c) 1996 Theo de Raadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* OPENBSD ORIGINAL: sys/sys/poll.h */ #ifndef _COMPAT_POLL_H_ #define _COMPAT_POLL_H_ #include #include #include #include #include #ifndef HAVE_STRUCT_POLLFD_FD #define POLLIN 0x0001 #define POLLPRI 0x0002 #define POLLOUT 0x0004 #define POLLERR 0x0008 #define POLLHUP 0x0010 #define POLLNVAL 0x0020 #if 0 /* the following are currently not implemented */ #define POLLRDNORM 0x0040 #define POLLNORM POLLRDNORM #define POLLWRNORM POLLOUT #define POLLRDBAND 0x0080 #define POLLWRBAND 0x0100 #endif #endif /* !HAVE_STRUCT_POLLFD_FD */ typedef unsigned int nfds_t; int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); #endif /* !_COMPAT_POLL_H_ */ got-portable-0.119/got/0000775000175000017500000000000015066537274010476 5got-portable-0.119/got/got.c0000664000175000017500000132467515066536113011364 /* * Copyright (c) 2017 Martin Pieuchot * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_fetch.h" #include "got_send.h" #include "got_blame.h" #include "got_privsep.h" #include "got_opentemp.h" #include "got_gotconfig.h" #include "got_dial.h" #include "got_patch.h" #include "got_sigs.h" #include "got_date.h" #include "got_keyword.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #ifndef GOT_DEFAULT_EDITOR #define GOT_DEFAULT_EDITOR "/usr/bin/vi" #endif static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigpipe_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigpipe(int signo) { sigpipe_received = 1; } struct got_cmd { const char *cmd_name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); const char *cmd_alias; }; __dead static void usage(int, int); __dead static void usage_init(void); __dead static void usage_import(void); __dead static void usage_clone(void); __dead static void usage_fetch(void); __dead static void usage_checkout(void); __dead static void usage_update(void); __dead static void usage_log(void); __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_status(void); __dead static void usage_ref(void); __dead static void usage_branch(void); __dead static void usage_tag(void); __dead static void usage_add(void); __dead static void usage_remove(void); __dead static void usage_patch(void); __dead static void usage_revert(void); __dead static void usage_commit(void); __dead static void usage_send(void); __dead static void usage_cherrypick(void); __dead static void usage_backout(void); __dead static void usage_rebase(void); __dead static void usage_histedit(void); __dead static void usage_integrate(void); __dead static void usage_merge(void); __dead static void usage_stage(void); __dead static void usage_unstage(void); __dead static void usage_cat(void); __dead static void usage_info(void); static const struct got_error* cmd_init(int, char *[]); static const struct got_error* cmd_import(int, char *[]); static const struct got_error* cmd_clone(int, char *[]); static const struct got_error* cmd_fetch(int, char *[]); static const struct got_error* cmd_checkout(int, char *[]); static const struct got_error* cmd_update(int, char *[]); static const struct got_error* cmd_log(int, char *[]); static const struct got_error* cmd_diff(int, char *[]); static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_status(int, char *[]); static const struct got_error* cmd_ref(int, char *[]); static const struct got_error* cmd_branch(int, char *[]); static const struct got_error* cmd_tag(int, char *[]); static const struct got_error* cmd_add(int, char *[]); static const struct got_error* cmd_remove(int, char *[]); static const struct got_error* cmd_patch(int, char *[]); static const struct got_error* cmd_revert(int, char *[]); static const struct got_error* cmd_commit(int, char *[]); static const struct got_error* cmd_send(int, char *[]); static const struct got_error* cmd_cherrypick(int, char *[]); static const struct got_error* cmd_backout(int, char *[]); static const struct got_error* cmd_rebase(int, char *[]); static const struct got_error* cmd_histedit(int, char *[]); static const struct got_error* cmd_integrate(int, char *[]); static const struct got_error* cmd_merge(int, char *[]); static const struct got_error* cmd_stage(int, char *[]); static const struct got_error* cmd_unstage(int, char *[]); static const struct got_error* cmd_cat(int, char *[]); static const struct got_error* cmd_info(int, char *[]); static const struct got_cmd got_commands[] = { { "init", cmd_init, usage_init, "" }, { "import", cmd_import, usage_import, "im" }, { "clone", cmd_clone, usage_clone, "cl" }, { "fetch", cmd_fetch, usage_fetch, "fe" }, { "checkout", cmd_checkout, usage_checkout, "co" }, { "update", cmd_update, usage_update, "up" }, { "log", cmd_log, usage_log, "" }, { "diff", cmd_diff, usage_diff, "di" }, { "blame", cmd_blame, usage_blame, "bl" }, { "tree", cmd_tree, usage_tree, "tr" }, { "status", cmd_status, usage_status, "st" }, { "ref", cmd_ref, usage_ref, "" }, { "branch", cmd_branch, usage_branch, "br" }, { "tag", cmd_tag, usage_tag, "" }, { "add", cmd_add, usage_add, "" }, { "remove", cmd_remove, usage_remove, "rm" }, { "patch", cmd_patch, usage_patch, "pa" }, { "revert", cmd_revert, usage_revert, "rv" }, { "commit", cmd_commit, usage_commit, "ci" }, { "send", cmd_send, usage_send, "se" }, { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" }, { "backout", cmd_backout, usage_backout, "bo" }, { "rebase", cmd_rebase, usage_rebase, "rb" }, { "histedit", cmd_histedit, usage_histedit, "he" }, { "integrate", cmd_integrate, usage_integrate,"ig" }, { "merge", cmd_merge, usage_merge, "mg" }, { "stage", cmd_stage, usage_stage, "sg" }, { "unstage", cmd_unstage, usage_unstage, "ug" }, { "cat", cmd_cat, usage_cat, "" }, { "info", cmd_info, usage_info, "" }, }; static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(got_commands); i++) { const struct got_cmd *cmd = &got_commands[i]; fprintf(fp, " %s", cmd->cmd_name); } fputc('\n', fp); } __dead static void option_conflict(char a, char b) { errx(1, "-%c and -%c options are mutually exclusive", a, b); } int main(int argc, char *argv[]) { const struct got_cmd *cmd; size_t i; int ch; int hflag = 0, Vflag = 0; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; setlocale(LC_CTYPE, ""); while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc <= 0) usage(hflag, hflag ? 0 : 1); signal(SIGINT, catch_sigint); signal(SIGPIPE, catch_sigpipe); for (i = 0; i < nitems(got_commands); i++) { const struct got_error *error; cmd = &got_commands[i]; if (strcmp(cmd->cmd_name, argv[0]) != 0 && strcmp(cmd->cmd_alias, argv[0]) != 0) continue; if (hflag) cmd->cmd_usage(); error = cmd->cmd_main(argc, argv); if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_PRIVSEP_EXIT && !(sigpipe_received && error->code == GOT_ERR_ERRNO && errno == EPIPE) && !(sigint_received && error->code == GOT_ERR_ERRNO && errno == EINTR)) { fflush(stdout); fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]); list_commands(stderr); return 1; } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) list_commands(fp); exit(status); } static const struct got_error * get_editor(char **abspath) { const struct got_error *err = NULL; const char *editor; *abspath = NULL; editor = getenv("VISUAL"); if (editor == NULL) editor = getenv("EDITOR"); if (editor) { err = got_path_find_prog(abspath, editor); if (err) return err; } if (*abspath == NULL) { *abspath = strdup(GOT_DEFAULT_EDITOR); if (*abspath == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * apply_unveil(const char *repo_path, int repo_read_only, const char *worktree_path) { const struct got_error *err; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0) return got_error_from_errno2("unveil", repo_path); if (worktree_path && unveil(worktree_path, "rwc") != 0) return got_error_from_errno2("unveil", worktree_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); err = got_privsep_unveil_exec_helpers(); if (err != NULL) return err; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } __dead static void usage_init(void) { fprintf(stderr, "usage: %s init [-A hashing-algorithm] [-b branch]" " repository-path\n", getprogname()); exit(1); } static const struct got_error * cmd_init(int argc, char *argv[]) { const struct got_error *error = NULL; const char *head_name = NULL; char *repo_path = NULL; enum got_hash_algorithm algo = GOT_HASH_SHA1; int ch; while ((ch = getopt(argc, argv, "A:b:")) != -1) { switch (ch) { case 'A': if (!strcmp(optarg, "sha1")) algo = GOT_HASH_SHA1; else if (!strcmp(optarg, "sha256")) algo = GOT_HASH_SHA256; else return got_error_path(optarg, GOT_ERR_OBJECT_FORMAT); break; case 'b': head_name = optarg; break; default: usage_init(); /* NOTREACHED */ } } argc -= optind; argv += optind; #ifndef PROFILE if (pledge("stdio rpath wpath cpath unveil", NULL) == -1) err(1, "pledge"); #endif if (argc != 1) usage_init(); repo_path = strdup(argv[0]); if (repo_path == NULL) return got_error_from_errno("strdup"); got_path_strip_trailing_slashes(repo_path); error = got_path_mkdir(repo_path); if (error && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; error = apply_unveil(repo_path, 0, NULL); if (error) goto done; error = got_repo_init(repo_path, head_name, algo); done: free(repo_path); return error; } __dead static void usage_import(void) { fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] " "[-r repository-path] directory\n", getprogname()); exit(1); } static int spawn_editor(const char *editor, const char *file) { pid_t pid; sig_t sighup, sigint, sigquit; int st = -1; sighup = signal(SIGHUP, SIG_IGN); sigint = signal(SIGINT, SIG_IGN); sigquit = signal(SIGQUIT, SIG_IGN); switch (pid = fork()) { case -1: goto doneediting; case 0: execl(editor, editor, file, (char *)NULL); _exit(127); } while (waitpid(pid, &st, 0) == -1) if (errno != EINTR) break; doneediting: (void)signal(SIGHUP, sighup); (void)signal(SIGINT, sigint); (void)signal(SIGQUIT, sigquit); if (!WIFEXITED(st)) { errno = EINTR; return -1; } return WEXITSTATUS(st); } static const struct got_error * read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; *logmsg = NULL; *len = 0; if (fseeko(fp, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); *logmsg = malloc(filesize + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); (*logmsg)[0] = '\0'; while (getline(&line, &linesize, fp) != -1) { if (line[0] == '#' || (*len == 0 && line[0] == '\n')) continue; /* remove comments and leading empty lines */ *len = strlcat(*logmsg, line, filesize + 1); if (*len >= filesize + 1) { err = got_error(GOT_ERR_NO_SPACE); goto done; } } if (ferror(fp)) { err = got_ferror(fp, GOT_ERR_IO); goto done; } while (*len > 0 && (*logmsg)[*len - 1] == '\n') { (*logmsg)[*len - 1] = '\0'; (*len)--; } done: free(line); if (err) { free(*logmsg); *logmsg = NULL; *len = 0; } return err; } static const struct got_error * edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path, const char *initial_content, size_t initial_content_len, int require_modification) { const struct got_error *err = NULL; struct stat st, st2; FILE *fp = NULL; size_t logmsg_len; *logmsg = NULL; if (stat(logmsg_path, &st) == -1) return got_error_from_errno2("stat", logmsg_path); if (spawn_editor(editor, logmsg_path) == -1) return got_error_from_errno("failed spawning editor"); if (require_modification) { struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); } if (stat(logmsg_path, &st2) == -1) return got_error_from_errno2("stat", logmsg_path); if (require_modification && st.st_size == st2.st_size && timespeccmp(&st.st_mtim, &st2.st_mtim, ==)) return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "no changes made to commit message, aborting"); fp = fopen(logmsg_path, "re"); if (fp == NULL) { err = got_error_from_errno("fopen"); goto done; } /* strip comments and leading/trailing newlines */ err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size); if (err) goto done; if (logmsg_len == 0) { err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty, aborting"); goto done; } done: if (fp && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_import_msg(char **logmsg, char **logmsg_path, const char *editor, const char *path_dir, const char *branch_name) { char *initial_content = NULL; const struct got_error *err = NULL; int initial_content_len; int fd = -1; initial_content_len = asprintf(&initial_content, "\n# %s to be imported to branch %s\n", path_dir, branch_name); if (initial_content_len == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(logmsg_path, &fd, GOT_TMPDIR_STR "/got-importmsg", ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *logmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content, initial_content_len, 1); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *logmsg_path); free(initial_content); if (err && *logmsg_path) { unlink(*logmsg_path); free(*logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * import_progress(void *arg, const char *path) { printf("A %s\n", path); return NULL; } static const struct got_error * valid_author(const char *author) { const char *email = author; /* * Git' expects the author (or committer) to be in the form * "name ", which are mostly free form (see the * "committer" description in git-fast-import(1)). We're only * doing this to avoid git's object parser breaking on commits * we create. */ while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (author != email && *author == '<' && *(author - 1) != ' ') return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space " "between author name and email required", email); if (*author++ != '<') return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (strcmp(author, ">") != 0) return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); return NULL; } static const struct got_error * get_author(char **author, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; const char *got_author = NULL, *name, *email; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *author = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file * 3) repository's git config file * 4) environment variables * 5) global git config files (in user's home directory or /etc) */ if (worktree_conf) got_author = got_gotconfig_get_author(worktree_conf); if (got_author == NULL) got_author = got_gotconfig_get_author(repo_conf); if (got_author == NULL) { name = got_repo_get_gitconfig_author_name(repo); email = got_repo_get_gitconfig_author_email(repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } got_author = getenv("GOT_AUTHOR"); if (got_author == NULL) { name = got_repo_get_global_gitconfig_author_name(repo); email = got_repo_get_global_gitconfig_author_email( repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } /* TODO: Look up user in password database? */ return got_error(GOT_ERR_COMMIT_NO_AUTHOR); } } *author = strdup(got_author); if (*author == NULL) return got_error_from_errno("strdup"); err = valid_author(*author); if (err) { free(*author); *author = NULL; } return err; } static const struct got_error * get_allowed_signers(char **allowed_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_allowed_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *allowed_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_allowed_signers = got_gotconfig_get_allowed_signers_file( worktree_conf); if (got_allowed_signers == NULL) got_allowed_signers = got_gotconfig_get_allowed_signers_file( repo_conf); if (got_allowed_signers) { *allowed_signers = strdup(got_allowed_signers); if (*allowed_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * get_revoked_signers(char **revoked_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_revoked_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *revoked_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_revoked_signers = got_gotconfig_get_revoked_signers_file( worktree_conf); if (got_revoked_signers == NULL) got_revoked_signers = got_gotconfig_get_revoked_signers_file( repo_conf); if (got_revoked_signers) { *revoked_signers = strdup(got_revoked_signers); if (*revoked_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const char * get_signer_id(struct got_repository *repo, struct got_worktree *worktree) { const char *got_signer_id = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_signer_id = got_gotconfig_get_signer_id(worktree_conf); if (got_signer_id == NULL) got_signer_id = got_gotconfig_get_signer_id(repo_conf); return got_signer_id; } static const struct got_error * get_gitconfig_path(char **gitconfig_path) { const char *homedir = getenv("HOME"); *gitconfig_path = NULL; if (homedir) { if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1) return got_error_from_errno("asprintf"); } return NULL; } static const struct got_error * cmd_import(int argc, char *argv[]) { const struct got_error *error = NULL; char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL; char *gitconfig_path = NULL, *editor = NULL, *author = NULL; const char *branch_name = NULL; char *id_str = NULL, *logmsg_path = NULL; char refname[PATH_MAX] = "refs/heads/"; struct got_repository *repo = NULL; struct got_reference *branch_ref = NULL, *head_ref = NULL; struct got_object_id *new_commit_id = NULL; int ch, n = 0; struct got_pathlist_head ignores; struct got_pathlist_entry *pe; int preserve_logmsg = 0; RB_INIT(&ignores); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'I': if (optarg[0] == '\0') break; error = got_pathlist_insert(&pe, &ignores, optarg, NULL); if (error) goto done; break; case 'm': logmsg = strdup(optarg); if (logmsg == NULL) { error = got_error_from_errno("strdup"); goto done; } break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } break; default: usage_import(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_import(); if (repo_path == NULL) { repo_path = getcwd(NULL, 0); if (repo_path == NULL) { error = got_error_from_errno("getcwd"); goto done; } } got_path_strip_trailing_slashes(repo_path); error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, NULL); if (error) goto done; path_dir = realpath(argv[0], NULL); if (path_dir == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } got_path_strip_trailing_slashes(path_dir); error = get_editor(&editor); if (error) goto done; if (unveil(path_dir, "r") != 0) { error = got_error_from_errno2("unveil", path_dir); goto done; } if (unveil(editor, "x") != 0) { error = got_error_from_errno2("unveil", editor); goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; error = get_author(&author, repo, NULL); if (error) goto done; /* * Don't let the user create a branch name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (branch_name && branch_name[0] == '-') { error = got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS); goto done; } error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error && error->code != GOT_ERR_NOT_REF) goto done; if (branch_name) n = strlcat(refname, branch_name, sizeof(refname)); else if (head_ref && got_ref_is_symbolic(head_ref)) n = strlcpy(refname, got_ref_get_symref_target(head_ref), sizeof(refname)); else n = strlcat(refname, "main", sizeof(refname)); if (n >= sizeof(refname)) { error = got_error(GOT_ERR_NO_SPACE); goto done; } error = got_ref_open(&branch_ref, repo, refname, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; } else { error = got_error_msg(GOT_ERR_BRANCH_EXISTS, "import target branch already exists"); goto done; } if (logmsg == NULL || *logmsg == '\0') { free(logmsg); error = collect_import_msg(&logmsg, &logmsg_path, editor, path_dir, refname); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && logmsg_path != NULL) preserve_logmsg = 1; goto done; } } error = got_repo_import(&new_commit_id, path_dir, logmsg, author, &ignores, repo, import_progress, NULL); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc(&branch_ref, refname, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(branch_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD, branch_ref); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(head_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } } printf("Created branch %s with commit %s\n", got_ref_get_name(branch_ref), id_str); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), logmsg_path); } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", logmsg_path); got_pathlist_free(&ignores, GOT_PATHLIST_FREE_NONE); free(logmsg); free(logmsg_path); free(path_dir); free(repo_path); free(editor); free(new_commit_id); free(id_str); free(author); free(gitconfig_path); if (branch_ref) got_ref_close(branch_ref); if (head_ref) got_ref_close(head_ref); return error; } __dead static void usage_clone(void) { fprintf(stderr, "usage: %s clone [-almqv] [-b branch] " "[-i identity-file] [-J jumphost] [-R reference] " "repository-URL [directory]\n", getprogname()); exit(1); } struct got_fetch_progress_arg { char last_scaled_size[FMT_SCALED_STRSIZE]; int last_p_indexed; int last_p_resolved; int verbosity; struct got_repository *repo; int create_configs; int configs_created; struct { struct got_pathlist_head *symrefs; struct got_pathlist_head *wanted_branches; struct got_pathlist_head *wanted_refs; const char *proto; const char *host; const char *port; const char *remote_repo_path; const char *git_url; int fetch_all_branches; int mirror_references; } config_info; }; /* XXX forward declaration */ static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo); static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { const struct got_error *err = NULL; struct got_fetch_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_indexed, p_resolved; int print_size = 0, print_indexed = 0, print_resolved = 0; /* * In order to allow a failed clone to be resumed with 'got fetch' * we try to create configuration files as soon as possible. * Once the server has sent information about its default branch * we have all required information. */ if (a->create_configs && !a->configs_created && !RB_EMPTY(a->config_info.symrefs)) { err = create_config_files(a->config_info.proto, a->config_info.host, a->config_info.port, a->config_info.remote_repo_path, a->config_info.git_url, a->config_info.fetch_all_branches, a->config_info.mirror_references, a->config_info.symrefs, a->config_info.wanted_branches, a->config_info.wanted_refs, a->repo); if (err) return err; a->configs_created = 1; } if (a->verbosity < 0) return NULL; if (message && message[0] != '\0') { printf("\rserver: %s", message); fflush(stdout); return NULL; } if (packfile_size > 0 || nobj_indexed > 0) { if (fmt_scaled(packfile_size, scaled_size) == 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { print_size = 1; if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_indexed > 0) { p_indexed = (nobj_indexed * 100) / nobj_total; if (p_indexed != a->last_p_indexed) { a->last_p_indexed = p_indexed; print_indexed = 1; print_size = 1; } } if (nobj_resolved > 0) { p_resolved = (nobj_resolved * 100) / (nobj_total - nobj_loose); if (p_resolved != a->last_p_resolved) { a->last_p_resolved = p_resolved; print_resolved = 1; print_indexed = 1; print_size = 1; } } } if (print_size || print_indexed || print_resolved) printf("\r"); if (print_size) printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size); if (print_indexed) printf("; indexing %d%%", p_indexed); if (print_resolved) printf("; resolving deltas %d%%", p_resolved); if (print_size || print_indexed || print_resolved) fflush(stdout); return NULL; } static const struct got_error * create_symref(const char *refname, struct got_reference *target_ref, int verbosity, struct got_repository *repo) { const struct got_error *err; struct got_reference *head_symref; err = got_ref_alloc_symref(&head_symref, refname, target_ref); if (err) return err; err = got_ref_write(head_symref, repo); if (err == NULL && verbosity > 0) { printf("Created reference %s: %s\n", GOT_REF_HEAD, got_ref_get_name(target_ref)); } got_ref_close(head_symref); return err; } static const struct got_error * list_remote_refs(struct got_pathlist_head *symrefs, struct got_pathlist_head *refs) { const struct got_error *err; struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *refname = pe->path; const char *targetref = pe->data; printf("%s: %s\n", refname, targetref); } RB_FOREACH(pe,got_pathlist_head, refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; printf("%s: %s\n", refname, id_str); free(id_str); } return NULL; } static const struct got_error * create_ref(const char *refname, struct got_object_id *id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); got_ref_close(ref); if (err == NULL && verbosity >= 0) printf("Created reference %s: %s\n", refname, id_str); done: free(id_str); return err; } static int match_wanted_ref(const char *refname, const char *wanted_ref) { if (strncmp(refname, "refs/", 5) != 0) return 0; refname += 5; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ if (strncmp(refname, "got/", 4) == 0) return 0; if (strncmp(refname, "remotes/", 8) == 0) return 0; if (strncmp(wanted_ref, "refs/", 5) == 0) wanted_ref += 5; /* Allow prefix match. */ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) return 1; /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); } static int is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { if (match_wanted_ref(refname, pe->path)) return 1; } return 0; } static const struct got_error * create_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err; char *remote_refname; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = create_ref(remote_refname, id, verbosity, repo); free(remote_refname); return err; } static const struct got_error * create_gotconfig(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path = NULL; char *gotconfig = NULL; FILE *gotconfig_file = NULL; const char *branchname = NULL; char *branches = NULL, *refs = NULL; ssize_t n; if (!fetch_all_branches && !RB_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_branches) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&s, "%s\"%s\" ", branches ? branches : "", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else if (!fetch_all_branches && default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&branches, "\"%s\" ", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!RB_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) branchname += 5; if (asprintf(&s, "%s\"%s\" ", refs ? refs : "", refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } /* Create got.conf(5). */ gotconfig_path = got_repo_get_path_gotconfig(repo); if (gotconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gotconfig"); goto done; } gotconfig_file = fopen(gotconfig_path, "ae"); if (gotconfig_file == NULL) { err = got_error_from_errno2("fopen", gotconfig_path); goto done; } if (asprintf(&gotconfig, "remote \"%s\" {\n" "\tserver %s\n" "\tprotocol %s\n" "%s%s%s" "\trepository \"%s\"\n" "%s" "%s%s%s" "%s" "%s%s%s" "%s" "%s" "}\n", GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto, port ? "\tport " : "", port ? port : "", port ? "\n" : "", remote_repo_path, branches ? "\tfetch {\n" : "", branches ? "\t\tbranch { " : "", branches ? branches : "", branches ? "}\n" : "", branches ? "\t}\n" : "", refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "", mirror_references ? "\tmirror_references yes\n" : "", fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file); if (n != strlen(gotconfig)) { err = got_ferror(gotconfig_file, GOT_ERR_IO); goto done; } done: if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gotconfig_path); free(gotconfig_path); free(branches); return err; } static const struct got_error * create_gitconfig(const char *git_url, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gitconfig_path = NULL; char *gitconfig = NULL; FILE *gitconfig_file = NULL; char *branches = NULL, *refs = NULL; const char *branchname; ssize_t n; /* Create a config file Git can understand. */ gitconfig_path = got_repo_get_path_gitconfig(repo); if (gitconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gitconfig"); goto done; } gitconfig_file = fopen(gitconfig_path, "ae"); if (gitconfig_file == NULL) { err = got_error_from_errno2("fopen", gitconfig_path); goto done; } if (fetch_all_branches) { if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/*:refs/heads/*\n") == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/*:refs/remotes/%s/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (!RB_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_branches) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/heads/%s\n", branches ? branches : "", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branches ? branches : "", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else { /* * If the server specified a default branch, use just that one. * Otherwise fall back to fetching all branches on next fetch. */ if (default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; } else branchname = "*"; /* fall back to all branches */ if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/heads/%s\n", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!RB_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) refname += 5; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/%s:refs/%s\n", refs ? refs : "", refname, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/%s:refs/remotes/%s/%s\n", refs ? refs : "", refname, GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } if (asprintf(&gitconfig, "[remote \"%s\"]\n" "\turl = %s\n" "%s" "%s" "\tfetch = refs/tags/*:refs/tags/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "", refs ? refs : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file); if (n != strlen(gitconfig)) { err = got_ferror(gitconfig_file, GOT_ERR_IO); goto done; } done: if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gitconfig_path); free(gitconfig_path); free(branches); return err; } static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo) { const struct got_error *err = NULL; const char *default_branch = NULL; struct got_pathlist_entry *pe; /* * If we asked for a set of wanted branches then use the first * one of those. */ if (!RB_EMPTY(wanted_branches)) { pe = RB_MIN(got_pathlist_head, wanted_branches); default_branch = pe->path; } else { /* First HEAD ref listed by server is the default branch. */ RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *refname = pe->path; const char *target = pe->data; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; default_branch = target; break; } } /* Create got.conf(5). */ err = create_gotconfig(proto, host, port, remote_repo_path, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); if (err) return err; /* Create a config file Git can understand. */ return create_gitconfig(git_url, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); } static const struct got_error * cmd_clone(int argc, char *argv[]) { const struct got_error *error = NULL; const char *uri, *dirname; char *proto, *host, *port, *repo_name, *server_path; char *default_destdir = NULL, *id_str = NULL; const char *repo_path; struct got_repository *repo = NULL; struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_object_id *pack_hash = NULL; int ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; char *git_url = NULL; const char *jumphost = NULL, *identity_file = NULL; int verbosity = 0, fetch_all_branches = 0, mirror_references = 0; int bflag = 0, list_refs_only = 0; int *pack_fds = NULL, have_head_ref = 0; RB_INIT(&refs); RB_INIT(&symrefs); RB_INIT(&wanted_branches); RB_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "ab:i:J:lmqR:v")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; break; case 'b': error = got_pathlist_insert(NULL, &wanted_branches, optarg, NULL); if (error) return error; bflag = 1; break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 'l': list_refs_only = 1; break; case 'm': mirror_references = 1; break; case 'q': verbosity = -1; break; case 'R': error = got_pathlist_insert(NULL, &wanted_refs, optarg, NULL); if (error) return error; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_clone(); break; } } argc -= optind; argv += optind; if (fetch_all_branches && !RB_EMPTY(&wanted_branches)) option_conflict('a', 'b'); if (list_refs_only) { if (!RB_EMPTY(&wanted_branches)) option_conflict('l', 'b'); if (fetch_all_branches) option_conflict('l', 'a'); if (mirror_references) option_conflict('l', 'm'); if (!RB_EMPTY(&wanted_refs)) option_conflict('l', 'R'); } uri = argv[0]; if (argc == 1) dirname = NULL; else if (argc == 2) dirname = argv[1]; else usage_clone(); error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, uri); if (error) goto done; if (asprintf(&git_url, "%s://%s%s%s%s%s", proto, host, port ? ":" : "", port ? port : "", server_path[0] != '/' ? "/" : "", server_path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0 || strcmp(proto, "git+http") == 0 || strcmp(proto, "http") == 0 || strcmp(proto, "git+https") == 0 || strcmp(proto, "https") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } if (dirname == NULL) { if (asprintf(&default_destdir, "%s.git", repo_name) == -1) { error = got_error_from_errno("asprintf"); goto done; } repo_path = default_destdir; } else repo_path = dirname; if (!list_refs_only) { error = got_path_mkdir(repo_path); if (error && (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))) goto done; if (!got_path_dir_is_empty(repo_path)) { error = got_error_path(repo_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(repo_path, 0, NULL); if (error) goto done; if (verbosity >= 0) printf("Connecting to %s\n", git_url); error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, jumphost, identity_file, verbosity); if (error) goto done; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd", NULL) == -1) err(1, "pledge"); #endif if (!list_refs_only) { error = got_repo_init(repo_path, NULL, GOT_HASH_SHA1); if (error) goto done; error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; } fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.create_configs = 1; fpa.configs_created = 0; fpa.repo = repo; fpa.config_info.symrefs = &symrefs; fpa.config_info.wanted_branches = &wanted_branches; fpa.config_info.wanted_refs = &wanted_refs; fpa.config_info.proto = proto; fpa.config_info.host = host; fpa.config_info.port = port; fpa.config_info.remote_repo_path = server_path; fpa.config_info.git_url = git_url; fpa.config_info.fetch_all_branches = fetch_all_branches; fpa.config_info.mirror_references = mirror_references; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag, fetch_progress, &fpa); if (error) goto done; if (list_refs_only) { error = list_remote_refs(&symrefs, &refs); goto done; } if (pack_hash == NULL) { error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s", "server sent an empty pack file"); goto done; } error = got_object_id_str(&id_str, pack_hash); if (error) goto done; if (verbosity >= 0) printf("\nFetched %s.pack\n", id_str); free(id_str); /* Set up references provided with the pack file. */ RB_FOREACH(pe, got_pathlist_head, &refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *remote_refname; if (is_wanted_ref(&wanted_refs, refname) && !mirror_references) { error = create_wanted_ref(refname, id, GOT_FETCH_DEFAULT_REMOTE_NAME, verbosity - 1, repo); if (error) goto done; continue; } error = create_ref(refname, id, verbosity - 1, repo); if (error) goto done; if (mirror_references) continue; if (strncmp("refs/heads/", refname, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname + 11) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = create_ref(remote_refname, id, verbosity - 1, repo); free(remote_refname); if (error) goto done; } /* Set the HEAD reference if the server provided one. */ RB_FOREACH(pe, got_pathlist_head, &symrefs) { struct got_reference *target_ref; const char *refname = pe->path; const char *target = pe->data; char *remote_refname = NULL, *remote_target = NULL; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(refname, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; have_head_ref = 1; if (mirror_references) continue; if (strncmp("refs/heads/", target, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (asprintf(&remote_target, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, target + 11) == -1) { error = got_error_from_errno("asprintf"); free(remote_refname); goto done; } error = got_ref_open(&target_ref, repo, remote_target, 0); if (error) { free(remote_refname); free(remote_target); if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(remote_refname, target_ref, verbosity - 1, repo); free(remote_refname); free(remote_target); got_ref_close(target_ref); if (error) goto done; } if (!have_head_ref) { /* * We failed to set the HEAD reference. If we asked for * a set of wanted branches use the first of one of those * which could be fetched instead. */ RB_FOREACH(pe, got_pathlist_head, &wanted_branches) { const char *target = pe->path; struct got_reference *target_ref; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(GOT_REF_HEAD, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; have_head_ref = 1; break; } /* * If we have no HEAD ref yet, set it to the first branch * which was fetched. */ if (!have_head_ref) { RB_FOREACH(pe, got_pathlist_head, &refs) { const char *refname = pe->path; struct got_reference *target_ref; if (strncmp("refs/heads/", refname, 11) != 0) continue; error = got_ref_open(&target_ref, repo, refname, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(GOT_REF_HEAD, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; break; } } if (!fpa.configs_created && pe != NULL) { error = create_config_files(fpa.config_info.proto, fpa.config_info.host, fpa.config_info.port, fpa.config_info.remote_repo_path, fpa.config_info.git_url, fpa.config_info.fetch_all_branches, fpa.config_info.mirror_references, fpa.config_info.symrefs, fpa.config_info.wanted_branches, fpa.config_info.wanted_refs, fpa.repo); if (error) goto done; } } if (verbosity >= 0) printf("Created %s repository '%s'\n", mirror_references ? "mirrored" : "cloned", repo_path); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); free(default_destdir); free(git_url); return error; } static const struct got_error * update_ref(struct got_reference *ref, struct got_object_id *new_id, int replace_tags, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; char *new_id_str = NULL; struct got_object_id *old_id = NULL; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; if (!replace_tags && strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; if (verbosity >= 0) { printf("Rejecting update of existing tag %s: %s\n", got_ref_get_name(ref), new_id_str); } goto done; } if (got_ref_is_symbolic(ref)) { if (verbosity >= 0) { printf("Replacing reference %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } err = got_ref_change_symref_to_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } else { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; err = got_ref_change_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(ref), new_id_str); done: free(old_id); free(new_id_str); return err; } static const struct got_error * update_symref(const char *refname, struct got_reference *target_ref, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err; struct got_reference *symref; int symref_is_locked = 0; err = got_ref_open(&symref, repo, refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; err = got_ref_alloc_symref(&symref, refname, target_ref); if (err) goto done; err = got_ref_write(symref, repo); if (err) goto done; if (verbosity >= 0) printf("Created reference %s: %s\n", got_ref_get_name(symref), got_ref_get_symref_target(symref)); } else { symref_is_locked = 1; if (strcmp(got_ref_get_symref_target(symref), got_ref_get_name(target_ref)) == 0) goto done; err = got_ref_change_symref(symref, got_ref_get_name(target_ref)); if (err) goto done; err = got_ref_write(symref, repo); if (err) goto done; if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(symref), got_ref_get_symref_target(symref)); } done: if (symref_is_locked) { unlock_err = got_ref_unlock(symref); if (unlock_err && err == NULL) err = unlock_err; } got_ref_close(symref); return err; } __dead static void usage_fetch(void) { fprintf(stderr, "usage: %s fetch [-adlqtvX] [-b branch] " "[-i identity-file] [-J jumphost] [-R reference] " "[-r repository-path] [remote-repository]\n", getprogname()); exit(1); } static const struct got_error * delete_missing_ref(struct got_reference *ref, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *id = NULL; char *id_str = NULL; if (got_ref_is_symbolic(ref)) { err = got_ref_delete(ref, repo); if (err) return err; if (verbosity >= 0) { printf("Deleted %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } } else { err = got_ref_resolve(&id, repo, ref); if (err) return err; err = got_object_id_str(&id_str, id); if (err) goto done; err = got_ref_delete(ref, repo); if (err) goto done; if (verbosity >= 0) { printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str); } } done: free(id); free(id_str); return err; } static const struct got_error * delete_missing_refs(struct got_pathlist_head *their_refs, struct got_pathlist_head *their_symrefs, const struct got_remote_repo *remote, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err; struct got_reflist_head my_refs; struct got_reflist_entry *re; struct got_pathlist_entry *pe; char *remote_namespace = NULL; char *local_refname = NULL; TAILQ_INIT(&my_refs); if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name) == -1) return got_error_from_errno("asprintf"); err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; TAILQ_FOREACH(re, &my_refs, entry) { const char *refname = got_ref_get_name(re->ref); const char *their_refname; if (remote->mirror_references) { their_refname = refname; } else { if (strncmp(refname, remote_namespace, strlen(remote_namespace)) == 0) { if (strcmp(refname + strlen(remote_namespace), GOT_REF_HEAD) == 0) continue; if (asprintf(&local_refname, "refs/heads/%s", refname + strlen(remote_namespace)) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (strncmp(refname, "refs/tags/", 10) != 0) continue; their_refname = local_refname; } RB_FOREACH(pe, got_pathlist_head, their_refs) { if (strcmp(their_refname, pe->path) == 0) break; } if (pe != NULL) continue; RB_FOREACH(pe, got_pathlist_head, their_symrefs) { if (strcmp(their_refname, pe->path) == 0) break; } if (pe != NULL) continue; err = delete_missing_ref(re->ref, verbosity, repo); if (err) break; if (local_refname) { struct got_reference *ref; err = got_ref_open(&ref, repo, local_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) break; free(local_refname); local_refname = NULL; continue; } err = delete_missing_ref(ref, verbosity, repo); if (err) break; unlock_err = got_ref_unlock(ref); got_ref_close(ref); if (unlock_err && err == NULL) { err = unlock_err; break; } free(local_refname); local_refname = NULL; } } done: got_ref_list_free(&my_refs); free(remote_namespace); free(local_refname); return err; } static const struct got_error * update_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err, *unlock_err; char *remote_refname; struct got_reference *ref; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = got_ref_open(&ref, repo, remote_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = create_ref(remote_refname, id, verbosity, repo); } else { err = update_ref(ref, id, 0, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; got_ref_close(ref); } done: free(remote_refname); return err; } static const struct got_error * delete_ref(struct got_repository *repo, struct got_reference *ref) { const struct got_error *err = NULL; struct got_object_id *id = NULL; char *id_str = NULL; const char *target; if (got_ref_is_symbolic(ref)) { target = got_ref_get_symref_target(ref); } else { err = got_ref_resolve(&id, repo, ref); if (err) goto done; err = got_object_id_str(&id_str, id); if (err) goto done; target = id_str; } err = got_ref_delete(ref, repo); if (err) goto done; printf("Deleted %s: %s\n", got_ref_get_name(ref), target); done: free(id); free(id_str); return err; } static const struct got_error * delete_refs_for_remote(struct got_repository *repo, const char *remote_name) { const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; char *prefix; TAILQ_INIT(&refs); if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) delete_ref(repo, re->ref); done: got_ref_list_free(&refs); return err; } static const struct got_error * cmd_fetch(int argc, char *argv[]) { const struct got_error *error = NULL, *unlock_err; char *cwd = NULL, *repo_path = NULL; const char *remote_name; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const struct got_remote_repo *remotes; struct got_remote_repo *remote = NULL; int nremotes; char *id_str = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs; char *head_refname = NULL; struct got_pathlist_entry *pe; struct got_reflist_head remote_refs; struct got_reflist_entry *re; struct got_object_id *pack_hash = NULL; int i, ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0; int delete_refs = 0, replace_tags = 0, delete_remote = 0; int *pack_fds = NULL, have_bflag = 0; const char *remote_head = NULL, *worktree_branch = NULL; const char *jumphost = NULL, *identity_file = NULL; RB_INIT(&refs); RB_INIT(&symrefs); TAILQ_INIT(&remote_refs); RB_INIT(&wanted_branches); RB_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "ab:di:J:lqR:r:tvX")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; break; case 'b': error = got_pathlist_insert(NULL, &wanted_branches, optarg, NULL); if (error) return error; have_bflag = 1; break; case 'd': delete_refs = 1; break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 'l': list_refs_only = 1; break; case 'q': verbosity = -1; break; case 'R': error = got_pathlist_insert(NULL, &wanted_refs, optarg, NULL); if (error) return error; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 't': replace_tags = 1; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; case 'X': delete_remote = 1; break; default: usage_fetch(); break; } } argc -= optind; argv += optind; if (fetch_all_branches && !RB_EMPTY(&wanted_branches)) option_conflict('a', 'b'); if (list_refs_only) { if (!RB_EMPTY(&wanted_branches)) option_conflict('l', 'b'); if (fetch_all_branches) option_conflict('l', 'a'); if (delete_refs) option_conflict('l', 'd'); if (delete_remote) option_conflict('l', 'X'); } if (delete_remote) { if (fetch_all_branches) option_conflict('X', 'a'); if (!RB_EMPTY(&wanted_branches)) option_conflict('X', 'b'); if (delete_refs) option_conflict('X', 'd'); if (replace_tags) option_conflict('X', 't'); if (!RB_EMPTY(&wanted_refs)) option_conflict('X', 'R'); } if (argc == 0) { if (delete_remote) errx(1, "-X option requires a remote name"); remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME; } else if (argc == 1) remote_name = argv[0]; else usage_fetch(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; if (delete_remote) { error = delete_refs_for_remote(repo, remote_name); goto done; /* nothing else to do */ } if (worktree) { worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } if (RB_EMPTY(&wanted_branches)) { if (!fetch_all_branches) fetch_all_branches = remote->fetch_all_branches; for (i = 0; i < remote->nfetch_branches; i++) { error = got_pathlist_insert(NULL, &wanted_branches, remote->fetch_branches[i], NULL); if (error) goto done; } } if (RB_EMPTY(&wanted_refs)) { for (i = 0; i < remote->nfetch_refs; i++) { error = got_pathlist_insert(NULL, &wanted_refs, remote->fetch_refs[i], NULL); if (error) goto done; } } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->fetch_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0 || strcmp(proto, "git+http") == 0 || strcmp(proto, "http") == 0 || strcmp(proto, "git+https") == 0 || strcmp(proto, "https") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; if (worktree) { head_refname = strdup(got_worktree_get_head_ref_name(worktree)); if (head_refname == NULL) { error = got_error_from_errno("strdup"); goto done; } /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); } error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, jumphost, identity_file, verbosity); if (error) goto done; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd", NULL) == -1) err(1, "pledge"); #endif if (!have_bflag) { /* * If set, get this remote's HEAD ref target so * if it has changed on the server we can fetch it. */ error = got_ref_list(&remote_refs, repo, "refs/remotes", got_ref_cmp_by_name, repo); if (error) goto done; TAILQ_FOREACH(re, &remote_refs, entry) { const char *remote_refname, *remote_target; size_t remote_name_len; if (!got_ref_is_symbolic(re->ref)) continue; remote_name_len = strlen(remote->name); remote_refname = got_ref_get_name(re->ref); /* we only want refs/remotes/$remote->name/HEAD */ if (strncmp(remote_refname + 13, remote->name, remote_name_len) != 0) continue; if (strcmp(remote_refname + remote_name_len + 14, GOT_REF_HEAD) != 0) continue; /* * Take the name itself because we already * only match with refs/heads/ in fetch_pack(). */ remote_target = got_ref_get_symref_target(re->ref); remote_head = remote_target + remote_name_len + 14; break; } if (head_refname && strncmp(head_refname, "refs/heads/", 11) == 0) worktree_branch = head_refname; } fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.repo = repo; fpa.create_configs = 0; fpa.configs_created = 0; memset(&fpa.config_info, 0, sizeof(fpa.config_info)); error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, list_refs_only, verbosity, fetchfd, repo, worktree_branch, remote_head, have_bflag, fetch_progress, &fpa); if (error) goto done; if (list_refs_only) { error = list_remote_refs(&symrefs, &refs); goto done; } if (pack_hash == NULL) { if (verbosity >= 0) printf("Already up-to-date\n"); } else if (verbosity >= 0) { error = got_object_id_str(&id_str, pack_hash); if (error) goto done; printf("\nFetched %s.pack\n", id_str); free(id_str); id_str = NULL; } /* Update references provided with the pack file. */ RB_FOREACH(pe, got_pathlist_head, &refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_reference *ref; char *remote_refname; if (is_wanted_ref(&wanted_refs, refname) && !remote->mirror_references) { error = update_wanted_ref(refname, id, remote->name, verbosity, repo); if (error) goto done; continue; } if (remote->mirror_references || strncmp("refs/tags/", refname, 10) == 0) { error = got_ref_open(&ref, repo, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(refname, id, verbosity, repo); if (error) goto done; } else { error = update_ref(ref, id, replace_tags, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); if (error) goto done; } } else if (strncmp("refs/heads/", refname, 11) == 0) { if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_name, refname + 11) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_ref_open(&ref, repo, remote_refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(remote_refname, id, verbosity, repo); if (error) goto done; } else { error = update_ref(ref, id, replace_tags, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); if (error) goto done; } /* Also create a local branch if none exists yet. */ error = got_ref_open(&ref, repo, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(refname, id, verbosity, repo); if (error) goto done; } else { unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); } } } if (delete_refs) { error = delete_missing_refs(&refs, &symrefs, remote, verbosity, repo); if (error) goto done; } if (!remote->mirror_references) { /* Update remote HEAD reference if the server provided one. */ RB_FOREACH(pe, got_pathlist_head, &symrefs) { struct got_reference *target_ref; const char *refname = pe->path; const char *target = pe->data; char *remote_refname = NULL, *remote_target = NULL; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; if (strncmp("refs/heads/", target, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote->name, refname) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (asprintf(&remote_target, "refs/remotes/%s/%s", remote->name, target + 11) == -1) { error = got_error_from_errno("asprintf"); free(remote_refname); goto done; } error = got_ref_open(&target_ref, repo, remote_target, 0); if (error) { free(remote_refname); free(remote_target); if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = update_symref(remote_refname, target_ref, verbosity, repo); free(remote_refname); free(remote_target); got_ref_close(target_ref); if (error) goto done; } } done: if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&remote_refs); got_repo_free_remote_repo_data(remote); free(remote); free(head_refname); free(id_str); free(cwd); free(repo_path); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); return error; } __dead static void usage_checkout(void) { fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] " "[-p path-prefix] repository-path [work-tree-path]\n", getprogname()); exit(1); } static void show_worktree_base_ref_warning(void) { fprintf(stderr, "%s: warning: could not create a reference " "to the work tree's base commit; the commit could be " "garbage-collected by Git or 'gotadmin cleanup'; making the " "repository writable and running 'got update' will prevent this\n", getprogname()); } struct got_checkout_progress_arg { const char *worktree_path; int had_base_commit_ref_error; int verbosity; }; static const struct got_error * checkout_progress(void *arg, unsigned char status, const char *path) { struct got_checkout_progress_arg *a = arg; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_BASE_REF_ERR) { a->had_base_commit_ref_error = 1; return NULL; } while (path[0] == '/') path++; if (a->verbosity >= 0) printf("%c %s/%s\n", status, a->worktree_path, path); return NULL; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigpipe_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * check_linear_ancestry(struct got_object_id *commit_id, struct got_object_id *base_commit_id, int allow_forwards_in_time_only, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *yca_id; err = got_commit_graph_find_youngest_common_ancestor(&yca_id, commit_id, base_commit_id, 1, 0, repo, check_cancelled, NULL); if (err) return err; if (yca_id == NULL) return got_error(GOT_ERR_ANCESTRY); /* * Require a straight line of history between the target commit * and the work tree's base commit. * * Non-linear situations such as this require a rebase: * * (commit) D F (base_commit) * \ / * C E * \ / * B (yca) * | * A * * 'got update' only handles linear cases: * Update forwards in time: A (base/yca) - B - C - D (commit) * Update backwards in time: D (base) - C - B - A (commit/yca) */ if (allow_forwards_in_time_only) { if (got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); } else if (got_object_id_cmp(commit_id, yca_id) != 0 && got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); free(yca_id); return NULL; } static const struct got_error * check_same_branch(struct got_object_id *commit_id, struct got_reference *head_ref, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL; struct got_object_id *head_commit_id = NULL; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; if (got_object_id_cmp(head_commit_id, commit_id) == 0) goto done; err = got_commit_graph_open(&graph, "/", 1); if (err) goto done; err = got_commit_graph_bfsort(graph, head_commit_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = got_error(GOT_ERR_ANCESTRY); break; } if (got_object_id_cmp(&id, commit_id) == 0) break; } done: if (graph) got_commit_graph_close(graph); free(head_commit_id); return err; } static const struct got_error * checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str) { static char msg[512]; const char *branch_name; if (got_ref_is_symbolic(ref)) branch_name = got_ref_get_symref_target(ref); else branch_name = got_ref_get_name(ref); if (strncmp("refs/heads/", branch_name, 11) == 0) branch_name += 11; snprintf(msg, sizeof(msg), "target commit is not contained in branch '%s'; " "the branch to use must be specified with -b; " "if necessary a new branch can be created for " "this commit with 'got branch -c %s BRANCH_NAME'", branch_name, commit_id_str); return got_error_msg(GOT_ERR_ANCESTRY, msg); } static const struct got_error * cmd_checkout(int argc, char *argv[]) { const struct got_error *close_err, *error = NULL; struct got_repository *repo = NULL; struct got_reference *head_ref = NULL, *ref = NULL; struct got_worktree *worktree = NULL; char *repo_path = NULL; char *worktree_path = NULL; const char *path_prefix = ""; const char *branch_name = GOT_REF_HEAD, *refname = NULL; char *commit_id_str = NULL, *keyword_idstr = NULL; struct got_object_id *commit_id = NULL; char *cwd = NULL; int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 'E': allow_nonempty = 1; break; case 'p': path_prefix = optarg; break; case 'q': verbosity = -1; break; default: usage_checkout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) { char *base, *dotgit; const char *path; repo_path = realpath(argv[0], NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", argv[0]); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } if (path_prefix[0]) path = path_prefix; else path = repo_path; error = got_path_basename(&base, path); if (error) goto done; dotgit = strstr(base, ".git"); if (dotgit) *dotgit = '\0'; if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) { error = got_error_from_errno("asprintf"); free(base); goto done; } free(base); } else if (argc == 2) { repo_path = realpath(argv[0], NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } worktree_path = realpath(argv[1], NULL); if (worktree_path == NULL) { if (errno != ENOENT) { error = got_error_from_errno2("realpath", argv[1]); goto done; } worktree_path = strdup(argv[1]); if (worktree_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else usage_checkout(); got_path_strip_trailing_slashes(repo_path); got_path_strip_trailing_slashes(worktree_path); if (got_path_is_child(worktree_path, repo_path, strlen(repo_path)) || got_path_is_child(repo_path, worktree_path, strlen(worktree_path))) { error = got_error_fmt(GOT_ERR_BAD_PATH, "work tree and repository paths may not overlap: %s", worktree_path); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; /* Pre-create work tree path for unveil(2) */ error = got_path_mkdir(worktree_path); if (error) { if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; if (!allow_nonempty && !got_path_dir_is_empty(worktree_path)) { error = got_error_path(worktree_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); if (error) goto done; error = got_ref_open(&head_ref, repo, branch_name, 0); if (error != NULL) goto done; error = got_worktree_init(worktree_path, head_ref, path_prefix, GOT_WORKTREE_GOT_DIR, repo); if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_GOT_DIR); if (error != NULL) goto done; error = got_worktree_match_path_prefix(&same_path_prefix, worktree, path_prefix); if (error != NULL) goto done; if (!same_path_prefix) { error = got_error(GOT_ERR_PATH_PREFIX); goto done; } if (commit_id_str) { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) { free(commit_id_str); commit_id_str = keyword_idstr; } error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; /* Expand potentially abbreviated commit ID string. */ free(commit_id_str); error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } else { commit_id = got_object_id_dup( got_worktree_get_base_commit_id(worktree)); if (commit_id == NULL) { error = got_error_from_errno("got_object_id_dup"); goto done; } error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } error = got_pathlist_insert(NULL, &paths, "", NULL); if (error) goto done; cpa.worktree_path = worktree_path; cpa.had_base_commit_ref_error = 0; cpa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, checkout_progress, &cpa, check_cancelled, NULL); if (error != NULL) goto done; if (got_ref_is_symbolic(head_ref)) { error = got_ref_resolve_symbolic(&ref, repo, head_ref); if (error) goto done; refname = got_ref_get_name(ref); } else refname = got_ref_get_name(head_ref); printf("Checked out %s: %s\n", refname, commit_id_str); printf("Now shut up and hack\n"); if (cpa.had_base_commit_ref_error) show_worktree_base_ref_warning(); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (head_ref) got_ref_close(head_ref); if (ref) got_ref_close(ref); if (repo) { close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree != NULL) { close_err = got_worktree_close(worktree); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); free(commit_id_str); free(commit_id); free(repo_path); free(worktree_path); free(cwd); return error; } struct got_update_progress_arg { int did_something; int conflicts; int obstructed; int not_updated; int missing; int not_deleted; int unversioned; int verbosity; }; static void print_update_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->not_updated > 0) printf("Files not updated because of existing merge " "conflicts: %d\n", upa->not_updated); } /* * The meaning of some status codes differs between merge-style operations and * update operations. For example, the ! status code means "file was missing" * if changes were merged into the work tree, and "missing file was restored" * if the work tree was updated. This function should be used by any operation * which merges changes into the work tree without updating the work tree. */ static void print_merge_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->missing > 0) printf("Files which had incoming changes but could not be " "found in the work tree: %d\n", upa->missing); if (upa->not_deleted > 0) printf("Files not deleted due to differences in deleted " "content: %d\n", upa->not_deleted); if (upa->unversioned > 0) printf("Files not merged because an unversioned file was " "found in the work tree: %d\n", upa->unversioned); } __dead static void usage_update(void) { fprintf(stderr, "usage: %s update [-q] [-b branch] [-c commit] " "[path ...]\n", getprogname()); exit(1); } static const struct got_error * update_progress(void *arg, unsigned char status, const char *path) { struct got_update_progress_arg *upa = arg; if (status == GOT_STATUS_EXISTS || status == GOT_STATUS_BASE_REF_ERR) return NULL; upa->did_something = 1; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_CONFLICT) upa->conflicts++; if (status == GOT_STATUS_OBSTRUCTED) upa->obstructed++; if (status == GOT_STATUS_CANNOT_UPDATE) upa->not_updated++; if (status == GOT_STATUS_MISSING) upa->missing++; if (status == GOT_STATUS_CANNOT_DELETE) upa->not_deleted++; if (status == GOT_STATUS_UNVERSIONED) upa->unversioned++; while (path[0] == '/') path++; if (upa->verbosity >= 0) printf("%c %s\n", status, path); return NULL; } static const struct got_error * switch_head_ref(struct got_reference *head_ref, struct got_object_id *commit_id, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *base_id_str; int ref_has_moved = 0; /* Trivial case: switching between two different references. */ if (strcmp(got_ref_get_name(head_ref), got_worktree_get_head_ref_name(worktree)) != 0) { printf("Switching work tree from %s to %s\n", got_worktree_get_head_ref_name(worktree), got_ref_get_name(head_ref)); return got_worktree_set_head_ref(worktree, head_ref); } err = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (err) { if (err->code != GOT_ERR_ANCESTRY) return err; ref_has_moved = 1; } if (!ref_has_moved) return NULL; /* Switching to a rebased branch with the same reference name. */ err = got_object_id_str(&base_id_str, got_worktree_get_base_commit_id(worktree)); if (err) return err; printf("Reference %s now points at a different branch\n", got_worktree_get_head_ref_name(worktree)); printf("Switching work tree from %s to %s\n", base_id_str, got_worktree_get_head_ref_name(worktree)); return NULL; } static const struct got_error * check_rebase_or_histedit_in_progress(struct got_worktree *worktree) { const struct got_error *err; int in_progress; err = got_worktree_rebase_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_REBASING); err = got_worktree_histedit_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_HISTEDIT_BUSY); return NULL; } static const struct got_error * check_merge_in_progress(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; int in_progress; err = got_worktree_merge_in_progress(&in_progress, worktree, repo); if (err) return err; if (in_progress) return got_error(GOT_ERR_MERGE_BUSY); return NULL; } static const struct got_error * get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc, char *argv[], struct got_worktree *worktree) { const struct got_error *err = NULL; char *path; struct got_pathlist_entry *new; int i; if (argc == 0) { path = strdup(""); if (path == NULL) return got_error_from_errno("strdup"); return got_pathlist_insert(NULL, paths, path, NULL); } for (i = 0; i < argc; i++) { err = got_worktree_resolve_path(&path, worktree, argv[i]); if (err) break; err = got_pathlist_insert(&new, paths, path, NULL); if (err || new == NULL /* duplicate */) { free(path); if (err) break; } } return err; } static const struct got_error * wrap_not_worktree_error(const struct got_error *orig_err, const char *cmdname, const char *path) { const struct got_error *err; struct got_repository *repo; static char msg[512]; err = got_repo_open(&repo, path, NULL, NULL); if (err) return orig_err; snprintf(msg, sizeof(msg), "'got %s' needs a work tree in addition to a git repository\n" "Work trees can be checked out from this Git repository with " "'got checkout'.\n" "The got(1) manual page contains more information.", cmdname); err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (err == NULL) err = close_err; } return err; } static const struct got_error * cmd_update(int argc, char *argv[]) { const struct got_error *close_err, *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *worktree_path = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; const char *branch_name = NULL; struct got_reference *head_ref = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, verbosity = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:c:q")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 'q': verbosity = -1; break; default: usage_update(); /* NOTREACHED */ } } argc -= optind; argv += optind; worktree_path = getcwd(NULL, 0); if (worktree_path == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "update", worktree_path); goto done; } error = check_rebase_or_histedit_in_progress(worktree); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = check_merge_in_progress(worktree, repo); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_ref_open(&head_ref, repo, branch_name ? branch_name : got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; if (commit_id_str == NULL) { error = got_ref_resolve(&commit_id, repo, head_ref); if (error != NULL) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error != NULL) goto done; } else { struct got_reflist_head refs; char *keyword_idstr = NULL; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) { free(commit_id_str); commit_id_str = keyword_idstr; } error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); free(commit_id_str); commit_id_str = NULL; if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } if (branch_name) { struct got_object_id *head_commit_id; RB_FOREACH(pe, got_pathlist_head, &paths) { if (pe->path_len == 0) continue; error = got_error_msg(GOT_ERR_BAD_PATH, "switching between branches requires that " "the entire work tree gets updated"); goto done; } error = got_ref_resolve(&head_commit_id, repo, head_ref); if (error) goto done; error = check_linear_ancestry(commit_id, head_commit_id, 0, repo); free(head_commit_id); if (error != NULL) goto done; error = check_same_branch(commit_id, head_ref, repo); if (error) goto done; error = switch_head_ref(head_ref, commit_id, worktree, repo); if (error) goto done; } else { error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_BRANCH_MOVED); goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) goto done; } if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree), commit_id) != 0) { error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; } memset(&upa, 0, sizeof(upa)); upa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { printf("Updated to %s: %s\n", got_worktree_get_head_ref_name(worktree), commit_id_str); } else printf("Already up-to-date\n"); print_update_progress_stats(&upa); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree != NULL) { close_err = got_worktree_close(worktree); if (error == NULL) error = close_err; } if (head_ref != NULL) got_ref_close(head_ref); free(worktree_path); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(commit_id); free(commit_id_str); return error; } static const struct got_error * diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL, *blob2 = NULL; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (blob_id1) { err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192, fd1); if (err) goto done; } err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } while (path[0] == '/') path++; err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, dsa, outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob2) got_object_blob_close(blob2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_diff_blob_output_unidiff_arg arg; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } arg.diff_context = diff_context; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = dsa; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.outfile = outfile; arg.lines = NULL; arg.nlines = 0; while (path[0] == '/') path++; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, path, path, repo, got_diff_blob_output_unidiff, &arg, 1); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static const struct got_error * get_changed_paths(struct got_pathlist_head *paths, struct got_commit_object *commit, struct got_repository *repo, struct got_diffstat_cb_arg *dsa) { const struct got_error *err = NULL; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_object_qid *qid; got_diff_blob_cb cb = got_diff_tree_collect_changed_paths; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (dsa) { cb = got_diff_tree_compute_diffstat; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { struct got_commit_object *pcommit; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; tree_id1 = got_object_id_dup( got_object_commit_get_tree_id(pcommit)); if (tree_id1 == NULL) { got_object_commit_close(pcommit); return got_error_from_errno("got_object_id_dup"); } got_object_commit_close(pcommit); } if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; } tree_id2 = got_object_commit_get_tree_id(commit); err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(tree_id1); return err; } static const struct got_error * print_patch(struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_commit_object *pcommit = NULL; char *id_str1 = NULL, *id_str2 = NULL; struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL; struct got_object_qid *qid; qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; err = got_object_id_str(&id_str1, &qid->id); if (err) goto done; } err = got_object_id_str(&id_str2, id); if (err) goto done; if (path && path[0] != '\0') { int obj_type; err = got_object_id_by_path(&obj_id2, repo, commit, path); if (err) goto done; if (pcommit) { err = got_object_id_by_path(&obj_id1, repo, pcommit, path); if (err) { if (err->code != GOT_ERR_NO_TREE_ENTRY) { free(obj_id2); goto done; } } } err = got_object_get_type(&obj_type, repo, obj_id2); if (err) { free(obj_id2); goto done; } fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = diff_blobs(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; case GOT_OBJ_TYPE_TREE: err = diff_trees(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } free(obj_id1); free(obj_id2); } else { obj_id2 = got_object_commit_get_tree_id(commit); if (pcommit) obj_id1 = got_object_commit_get_tree_id(pcommit); fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0, dsa, repo, outfile); } done: free(id_str1); free(id_str2); if (pcommit) got_object_commit_close(pcommit); return err; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = gmtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * match_commit(int *have_match, struct got_object_id *id, struct got_commit_object *commit, regex_t *regex) { const struct got_error *err = NULL; regmatch_t regmatch; char *id_str = NULL, *logmsg = NULL; *have_match = 0; err = got_object_id_str(&id_str, id); if (err) return err; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; if (regexec(regex, got_object_commit_get_author(commit), 1, ®match, 0) == 0 || regexec(regex, got_object_commit_get_committer(commit), 1, ®match, 0) == 0 || regexec(regex, id_str, 1, ®match, 0) == 0 || regexec(regex, logmsg, 1, ®match, 0) == 0) *have_match = 1; done: free(id_str); free(logmsg); return err; } static void match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths, regex_t *regex) { regmatch_t regmatch; struct got_pathlist_entry *pe; *have_match = 0; RB_FOREACH(pe, got_pathlist_head, changed_paths) { if (regexec(regex, pe->path, 1, ®match, 0) == 0) { *have_match = 1; break; } } } static const struct got_error * match_patch(int *have_match, struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_repository *repo, regex_t *regex, FILE *f) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; regmatch_t regmatch; *have_match = 0; err = got_opentemp_truncate(f); if (err) return err; err = print_patch(commit, id, path, diff_context, NULL, repo, f); if (err) goto done; if (fseeko(f, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (getline(&line, &linesize, f) != -1) { if (regexec(regex, line, 1, ®match, 0) == 0) { *have_match = 1; break; } } done: free(line); return err; } #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n" static const struct got_error* build_refs_str(char **refs_str, struct got_reflist_head *refs, struct got_object_id *id, struct got_repository *repo, int local_only) { static const struct got_error *err = NULL; struct got_reflist_entry *re; char *s; const char *name; *refs_str = NULL; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; name = got_ref_get_name(re->ref); if (strcmp(name, GOT_REF_HEAD) == 0) continue; if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { if (local_only) continue; name += 8; s = strstr(name, "/" GOT_REF_HEAD); if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0) continue; } err = got_ref_resolve(&ref_id, repo, re->ref); if (err) break; if (strncmp(name, "tags/", 5) == 0) { err = got_object_open_as_tag(&tag, repo, ref_id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(ref_id); break; } /* Ref points at something other than a tag. */ err = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = *refs_str; if (asprintf(refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { err = got_error_from_errno("asprintf"); free(s); *refs_str = NULL; break; } free(s); } return err; } static const struct got_error * print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, struct got_reflist_object_id_map *refs_idmap) { const struct got_error *err = NULL; char *ref_str = NULL, *id_str = NULL, *logmsg0 = NULL; char *comma, *s, *nl; struct got_reflist_head *refs; char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */ struct tm tm; time_t committer_time; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&ref_str, refs, id, repo, 1); if (err) return err; /* Display the first matching ref only. */ if (ref_str && (comma = strchr(ref_str, ',')) != NULL) *comma = '\0'; } if (ref_str == NULL) { err = got_object_id_str(&id_str, id); if (err) return err; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) { err = got_error_from_errno("gmtime_r"); goto done; } if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; s = logmsg0; while (isspace((unsigned char)s[0])) s++; nl = strchr(s, '\n'); if (nl) { *nl = '\0'; } if (ref_str) printf("%s%-7s %s\n", datebuf, ref_str, s); else printf("%s%.7s %s\n", datebuf, id_str, s); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: free(id_str); free(ref_str); free(logmsg0); return err; } static const struct got_error * print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header) { struct got_pathlist_entry *pe; if (header != NULL) printf("%s\n", header); RB_FOREACH(pe, got_pathlist_head, dsa->paths) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; printf(" %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); } printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); if (fflush(stdout) != 0) return got_error_from_errno("fflush"); return NULL; } static const struct got_error * printfile(FILE *f) { char buf[8192]; size_t r; if (fseeko(f, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); for (;;) { r = fread(buf, 1, sizeof(buf), f); if (r == 0) { if (ferror(f)) return got_error_from_errno("fread"); if (feof(f)) break; } if (fwrite(buf, 1, r, stdout) != r) return got_ferror(stdout, GOT_ERR_IO); } return NULL; } static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, const char *path, struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context, struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str, const char *prefix) { const struct got_error *err = NULL; FILE *f = NULL; char *id_str, *datestr, *logmsg0, *logmsg, *line; char datebuf[26]; time_t committer_time; const char *author, *committer; char *refs_str = NULL; err = got_object_id_str(&id_str, id); if (err) return err; if (custom_refs_str == NULL) { struct got_reflist_head *refs; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&refs_str, refs, id, repo, 0); if (err) goto done; } } printf(GOT_COMMIT_SEP_STR); if (custom_refs_str) printf("%s %s (%s)\n", prefix ? prefix : "commit", id_str, custom_refs_str); else printf("%s %s%s%s%s\n", prefix ? prefix : "commit", id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : ""); free(id_str); id_str = NULL; free(refs_str); refs_str = NULL; printf("from: %s\n", got_object_commit_get_author(commit)); author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) printf("via: %s\n", committer); committer_time = got_object_commit_get_committer_time(commit); datestr = get_datestr(&committer_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int n = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; printf("parent %d: %s\n", n++, id_str); free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; do { line = strsep(&logmsg, "\n"); if (line) printf(" %s\n", line); } while (line); free(logmsg0); if (changed_paths && diffstat == NULL) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, changed_paths) { struct got_diff_changed_path *cp = pe->data; printf(" %c %s\n", cp->status, pe->path); } printf("\n"); } if (show_patch) { if (diffstat) { f = got_opentemp(); if (f == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } err = print_patch(commit, id, path, diff_context, diffstat, repo, diffstat == NULL ? stdout : f); if (err) goto done; } if (diffstat) { err = print_diffstat(diffstat, NULL); if (err) goto done; if (show_patch) { err = printfile(f); if (err) goto done; } } if (show_patch) printf("\n"); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(id_str); free(refs_str); return err; } static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, const char *path, int show_changed_paths, int show_diffstat, int show_patch, const char *search_pattern, int diff_context, int limit, int log_branches, int reverse_display_order, struct got_reflist_object_id_map *refs_idmap, int one_line, int toposort, FILE *tmpfile) { const struct got_error *err; struct got_commit_graph *graph; regex_t regex; int have_match; struct got_object_id_queue reversed_commits; struct got_object_qid *qid; struct got_commit_object *commit; struct got_pathlist_head changed_paths; STAILQ_INIT(&reversed_commits); RB_INIT(&changed_paths); if (search_pattern && regcomp(®ex, search_pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) return got_error_msg(GOT_ERR_REGEX, search_pattern); err = got_commit_graph_open(&graph, path, !log_branches); if (err) return err; if (log_branches && toposort) { err = got_commit_graph_toposort(graph, root_id, repo, check_cancelled, NULL); } else { err = got_commit_graph_bfsort(graph, root_id, repo, check_cancelled, NULL); } if (err) goto done; for (;;) { struct got_object_id id; struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; if (sigint_received || sigpipe_received) break; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if (((show_changed_paths && !show_diffstat) || (show_diffstat && !show_patch)) && !reverse_display_order) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (search_pattern) { err = match_commit(&have_match, &id, commit, ®ex); if (err) { got_object_commit_close(commit); break; } if (have_match == 0 && show_changed_paths) match_changed_paths(&have_match, &changed_paths, ®ex); if (have_match == 0 && show_patch) { err = match_patch(&have_match, commit, &id, path, diff_context, repo, ®ex, tmpfile); if (err) break; } if (have_match == 0) { got_object_commit_close(commit); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); continue; } } if (reverse_display_order) { err = got_object_qid_alloc(&qid, &id); if (err) break; STAILQ_INSERT_HEAD(&reversed_commits, qid, entry); got_object_commit_close(commit); } else { if (one_line) err = print_commit_oneline(commit, &id, repo, refs_idmap); else err = print_commit(commit, &id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; } if ((limit && --limit == 0) || (end_id && got_object_id_cmp(&id, end_id) == 0)) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } if (reverse_display_order) { STAILQ_FOREACH(qid, &reversed_commits, entry) { struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; if ((show_changed_paths && !show_diffstat) || (show_diffstat && !show_patch)) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (one_line) err = print_commit_oneline(commit, &qid->id, repo, refs_idmap); else err = print_commit(commit, &qid->id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } } done: got_object_id_queue_free(&reversed_commits); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (search_pattern) regfree(®ex); got_commit_graph_close(graph); return err; } __dead static void usage_log(void) { fprintf(stderr, "usage: %s log [-bdPpRst] [-C number] [-c commit] " "[-l N] [-r repository-path] [-S search-pattern] [-x commit] " "[path]\n", getprogname()); exit(1); } static int get_default_log_limit(void) { const char *got_default_log_limit; long long n; const char *errstr; got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT"); if (got_default_log_limit == NULL) return 0; n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr); if (errstr != NULL) return 0; return n; } static const struct got_error * cmd_log(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *start_id = NULL, *end_id = NULL; char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL; char *keyword_idstr = NULL; const char *start_commit = NULL, *end_commit = NULL; const char *search_pattern = NULL; int diff_context = -1, ch; int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0; int show_diffstat = 0, reverse_display_order = 0, one_line = 0; int toposort = 0; const char *errstr; struct got_reflist_head refs; struct got_reflist_object_id_map *refs_idmap = NULL; FILE *tmpfile = NULL; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif limit = get_default_log_limit(); while ((ch = getopt(argc, argv, "bC:c:dl:PpRr:S:stx:")) != -1) { switch (ch) { case 'b': log_branches = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': start_commit = optarg; break; case 'd': show_diffstat = 1; break; case 'l': limit = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "number of commits is %s: %s", errstr, optarg); break; case 'P': show_changed_paths = 1; break; case 'p': show_patch = 1; break; case 'R': reverse_display_order = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'S': search_pattern = optarg; break; case 's': one_line = 1; break; case 't': toposort = 1; break; case 'x': end_commit = optarg; break; default: usage_log(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (diff_context == -1) diff_context = 3; else if (!show_patch) errx(1, "-C requires -p"); if (one_line && (show_patch || show_changed_paths || show_diffstat)) errx(1, "cannot use -s with -d, -p or -P"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; error = NULL; } if (argc == 1) { if (worktree) { error = got_worktree_resolve_path(&path, worktree, argv[0]); if (error) goto done; } else { path = strdup(argv[0]); if (path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else if (argc != 0) usage_log(); if (repo_path == NULL) { repo_path = worktree ? strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd); } if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (error) goto done; if (start_commit == NULL) { struct got_reference *head_ref; struct got_commit_object *commit = NULL; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&start_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; error = got_object_open_as_commit(&commit, repo, start_id); if (error != NULL) goto done; got_object_commit_close(commit); } else { error = got_keyword_to_idstr(&keyword_idstr, start_commit, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) start_commit = keyword_idstr; error = got_repo_match_object_id(&start_id, NULL, start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (end_commit != NULL) { error = got_keyword_to_idstr(&keyword_idstr, end_commit, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) end_commit = keyword_idstr; error = got_repo_match_object_id(&end_id, NULL, end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (worktree) { /* * If a path was specified on the command line it was resolved * to a path in the work tree above. Prepend the work tree's * path prefix to obtain the corresponding in-repository path. */ if (path) { const char *prefix; prefix = got_worktree_get_path_prefix(worktree); if (asprintf(&in_repo_path, "%s%s%s", prefix, (path[0] != '\0') ? "/" : "", path) == -1) { error = got_error_from_errno("asprintf"); goto done; } } } else error = got_repo_map_path(&in_repo_path, repo, path ? path : ""); if (error != NULL) goto done; if (in_repo_path) { free(path); path = in_repo_path; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } if (search_pattern && show_patch) { tmpfile = got_opentemp(); if (tmpfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } } error = print_commits(start_id, end_id, repo, path ? path : "", show_changed_paths, show_diffstat, show_patch, search_pattern, diff_context, limit, log_branches, reverse_display_order, refs_idmap, one_line, toposort, tmpfile); done: free(path); free(repo_path); free(cwd); free(start_id); free(end_id); free(keyword_idstr); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (tmpfile && fclose(tmpfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); got_ref_list_free(&refs); return error; } __dead static void usage_diff(void) { fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] " "[-r repository-path] [object1 object2 | path ...]\n", getprogname()); exit(1); } struct print_diff_arg { struct got_repository *repo; struct got_worktree *worktree; struct got_diffstat_cb_arg *diffstat; int diff_context; const char *id_str; int header_shown; int diff_staged; enum got_diff_algorithm diff_algo; int ignore_whitespace; int force_text_diff; FILE *f1; FILE *f2; FILE *outfile; }; /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * emit_base_commit_header(FILE *f, struct got_object_id *commit_id, struct got_worktree *worktree) { const struct got_error *err; struct got_object_id *base_commit_id; char *base_commit_idstr; if (worktree == NULL) /* shouldn't happen */ return got_error(GOT_ERR_NOT_WORKTREE); base_commit_id = got_worktree_get_base_commit_id(worktree); if (commit_id != NULL) { if (got_object_id_cmp(commit_id, base_commit_id) != 0) base_commit_id = commit_id; } err = got_object_id_str(&base_commit_idstr, base_commit_id); if (err != NULL) return err; if (fprintf(f, "commit - %s\n", base_commit_idstr) < 0) err = got_error_from_errno("fprintf"); free(base_commit_idstr); return err; } static const struct got_error * print_diff(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct print_diff_arg *a = arg; const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL; int fd = -1, fd1 = -1, fd2 = -1; FILE *f2 = NULL; char *abspath = NULL, *label1 = NULL; struct stat sb; off_t size1 = 0; int f2_exists = 0; memset(&sb, 0, sizeof(sb)); if (a->diff_staged) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (staged_status == GOT_STATUS_DELETE) return NULL; if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(a->f1); if (err) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(a->f2); if (err) return got_error_from_errno("got_opentemp_truncate"); if (!a->header_shown) { if (fprintf(a->outfile, "diff %s%s\n", a->diff_staged ? "-s " : "", got_worktree_get_root_path(a->worktree)) < 0) { err = got_error_from_errno("fprintf"); goto done; } if (fprintf(a->outfile, "path + %s%s\n", got_worktree_get_root_path(a->worktree), a->diff_staged ? " (staged changes)" : "") < 0) { err = got_error_from_errno("fprintf"); goto done; } a->header_shown = 1; } err = emit_base_commit_header(a->outfile, commit_id, a->worktree); if (err != NULL) goto done; if (a->diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (staged_status) { case GOT_STATUS_MODIFY: label1 = path; label2 = path; break; case GOT_STATUS_ADD: label2 = path; break; case GOT_STATUS_DELETE: label1 = path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2, fd1, fd2, blob_id, staged_blob_id, label1, label2, a->diff_algo, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->repo, a->outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { char *id_str; err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id, 8192, fd1); if (err) goto done; err = got_object_id_str(&id_str, staged_blob_id); if (err) goto done; if (asprintf(&label1, "%s (staged)", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } else if (status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192, fd1); if (err) goto done; } if (status != GOT_STATUS_DELETE) { if (asprintf(&abspath, "%s/%s", got_worktree_get_root_path(a->worktree), path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } if (fstatat(fd, abspath, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", abspath); goto done; } f2 = fdopen(fd, "r"); if (f2 == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; f2_exists = 1; } if (blob1) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, a->f1, blob1); if (err) goto done; } err = got_diff_blob_file(NULL, NULL, blob1, a->f1, size1, label1, f2 ? f2 : a->f2, f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(abspath); return err; } static const struct got_error * cmd_diff(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; const char *commit_args[2] = { NULL, NULL }; int ncommit_args = 0; struct got_object_id *ids[2] = { NULL, NULL }; char *labels[2] = { NULL, NULL }; int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY; int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i; int force_text_diff = 0, force_path = 0, rflag = 0, show_diffstat = 0; const char *errstr; struct got_reflist_head refs; struct got_pathlist_head diffstat_paths, paths; FILE *f1 = NULL, *f2 = NULL, *outfile = NULL; int fd1 = -1, fd2 = -1; int *pack_fds = NULL; struct got_diffstat_cb_arg dsa; memset(&dsa, 0, sizeof(dsa)); TAILQ_INIT(&refs); RB_INIT(&paths); RB_INIT(&diffstat_paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aC:c:dPr:sw")) != -1) { switch (ch) { case 'a': force_text_diff = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': if (ncommit_args >= 2) errx(1, "too many -c options used"); commit_args[ncommit_args++] = optarg; break; case 'd': show_diffstat = 1; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); rflag = 1; break; case 's': diff_staged = 1; break; case 'w': ignore_whitespace = 1; break; default: usage_diff(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; if (show_diffstat) { dsa.paths = &diffstat_paths; dsa.force_text = force_text_diff; dsa.ignore_ws = ignore_whitespace; dsa.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; } if (rflag || worktree == NULL || ncommit_args > 0) { if (force_path) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-P option can only be used when diffing " "a work tree"); goto done; } if (diff_staged) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-s option can only be used when diffing " "a work tree"); goto done; } } error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if ((!force_path && argc == 2) || ncommit_args > 0) { int obj_type = (ncommit_args > 0 ? GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) { const char *arg; char *keyword_idstr = NULL; if (ncommit_args > 0) arg = commit_args[i]; else arg = argv[i]; error = got_keyword_to_idstr(&keyword_idstr, arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) arg = keyword_idstr; error = got_repo_match_object_id(&ids[i], &labels[i], arg, obj_type, &refs, repo); free(keyword_idstr); if (error) { if (error->code != GOT_ERR_NOT_REF && error->code != GOT_ERR_NO_OBJ) goto done; if (ncommit_args > 0) goto done; error = NULL; break; } } } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } outfile = got_opentemp(); if (outfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) { struct print_diff_arg arg; char *id_str; if (worktree == NULL) { if (argc == 2 && ids[0] == NULL) { error = got_error_path(argv[0], GOT_ERR_NO_OBJ); goto done; } else if (argc == 2 && ids[1] == NULL) { error = got_error_path(argv[1], GOT_ERR_NO_OBJ); goto done; } else if (argc > 0) { error = got_error_fmt(GOT_ERR_NOT_WORKTREE, "%s", "specified paths cannot be resolved"); goto done; } else { error = got_error(GOT_ERR_NOT_WORKTREE); goto done; } } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; arg.repo = repo; arg.worktree = worktree; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.diff_context = diff_context; arg.id_str = id_str; arg.header_shown = 0; arg.diff_staged = diff_staged; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = show_diffstat ? &dsa : NULL; arg.f1 = f1; arg.f2 = f2; arg.outfile = outfile; error = got_worktree_status(worktree, &paths, repo, 0, print_diff, &arg, check_cancelled, NULL); free(id_str); if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header; if (asprintf(&header, "diffstat %s%s", diff_staged ? "-s " : "", got_worktree_get_root_path(worktree)) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); goto done; } if (ncommit_args == 1) { struct got_commit_object *commit; error = got_object_open_as_commit(&commit, repo, ids[0]); if (error) goto done; labels[1] = labels[0]; ids[1] = ids[0]; if (got_object_commit_get_nparents(commit) > 0) { const struct got_object_id_queue *pids; struct got_object_qid *pid; pids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(pids); ids[0] = got_object_id_dup(&pid->id); if (ids[0] == NULL) { error = got_error_from_errno( "got_object_id_dup"); got_object_commit_close(commit); goto done; } error = got_object_id_str(&labels[0], ids[0]); if (error) { got_object_commit_close(commit); goto done; } } else { ids[0] = NULL; labels[0] = strdup("/dev/null"); if (labels[0] == NULL) { error = got_error_from_errno("strdup"); got_object_commit_close(commit); goto done; } } got_object_commit_close(commit); } if (ncommit_args == 0 && argc > 2) { error = got_error_msg(GOT_ERR_BAD_PATH, "path arguments cannot be used when diffing two objects"); goto done; } if (ids[0]) { error = got_object_get_type(&type1, repo, ids[0]); if (error) goto done; } error = got_object_get_type(&type2, repo, ids[1]); if (error) goto done; if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) { error = got_error_msg(GOT_ERR_OBJ_TYPE, "path arguments cannot be used when diffing blobs"); goto done; } for (i = 0; ncommit_args > 0 && i < argc; i++) { char *in_repo_path; struct got_pathlist_entry *new; if (worktree) { const char *prefix; char *p; error = got_worktree_resolve_path(&p, worktree, argv[i]); if (error) goto done; prefix = got_worktree_get_path_prefix(worktree); while (prefix[0] == '/') prefix++; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && prefix[0] != '\0') ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); } else { char *mapped_path, *s; error = got_repo_map_path(&mapped_path, repo, argv[i]); if (error) goto done; s = mapped_path; while (s[0] == '/') s++; in_repo_path = strdup(s); if (in_repo_path == NULL) { error = got_error_from_errno("asprintf"); free(mapped_path); goto done; } free(mapped_path); } error = got_pathlist_insert(&new, &paths, in_repo_path, NULL); if (error || new == NULL /* duplicate */) free(in_repo_path); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } fd1 = got_opentempfd(); if (fd1 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, "", "", GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "diff %s %s\n", labels[0], labels[1]); error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; default: error = got_error(GOT_ERR_OBJ_TYPE); } if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header = NULL; if (asprintf(&header, "diffstat %s %s", labels[0], labels[1]) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); done: free(cwd); free(labels[0]); free(labels[1]); free(ids[0]); free(ids[1]); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); got_pathlist_free(&diffstat_paths, GOT_PATHLIST_FREE_ALL); got_ref_list_free(&refs); if (outfile && fclose(outfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } __dead static void usage_blame(void) { fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n", getprogname()); exit(1); } struct blame_line { int annotated; char *id_str; char *committer; char datebuf[11]; /* YYYY-MM-DD + NUL */ }; struct blame_cb_args { struct blame_line *lines; int nlines; int nlines_prec; int lineno_cur; off_t *line_offsets; FILE *f; struct got_repository *repo; }; static const struct got_error * blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct blame_cb_args *a = arg; struct blame_line *bline; char *line = NULL; size_t linesize = 0; off_t offset; struct tm tm; time_t committer_time; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); if (sigint_received) return got_error(GOT_ERR_ITER_COMPLETED); if (lineno == -1) return NULL; /* no change in this commit */ /* Annotate this line. */ bline = &a->lines[lineno - 1]; if (bline->annotated) return NULL; err = got_object_id_str(&bline->id_str, id); if (err) return err; bline->committer = strdup(got_object_commit_get_committer(commit)); if (bline->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(bline->datebuf, sizeof(bline->datebuf), "%F", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } bline->annotated = 1; /* Print lines annotated so far. */ bline = &a->lines[a->lineno_cur - 1]; if (!bline->annotated) goto done; offset = a->line_offsets[a->lineno_cur - 1]; if (fseeko(a->f, offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (a->lineno_cur <= a->nlines && bline->annotated) { char *smallerthan, *at, *nl, *committer; size_t len; if (getline(&line, &linesize, a->f) == -1) { if (ferror(a->f)) err = got_error_from_errno("getline"); break; } committer = bline->committer; smallerthan = strchr(committer, '<'); if (smallerthan && smallerthan[1] != '\0') committer = smallerthan + 1; at = strchr(committer, '@'); if (at) *at = '\0'; len = strlen(committer); if (len >= 9) committer[8] = '\0'; nl = strchr(line, '\n'); if (nl) *nl = '\0'; printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur, bline->id_str, bline->datebuf, committer, line); a->lineno_cur++; bline = &a->lines[a->lineno_cur - 1]; } done: free(line); return err; } static const struct got_error * cmd_blame(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *link_target = NULL; struct got_object_id *obj_id = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL; char *commit_id_str = NULL, *keyword_idstr = NULL; struct blame_cb_args bca; int ch, obj_type, i, fd1 = -1, fd2 = -1, fd3 = -1; off_t filesize; int *pack_fds = NULL; FILE *f1 = NULL, *f2 = NULL; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); memset(&bca, 0, sizeof(bca)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_blame(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else usage_blame(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); if (error) goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_repo_map_path(&in_repo_path, repo, path); } if (error) goto done; if (commit_id_str == NULL) { struct got_reference *head_ref; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_str = keyword_idstr; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_resolve_symlinks(&link_target, in_repo_path, commit, repo); if (error) goto done; error = got_object_id_by_path(&obj_id, repo, commit, link_target ? link_target : in_repo_path); if (error) goto done; error = got_object_get_type(&obj_type, repo, obj_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error_path(link_target ? link_target : in_repo_path, GOT_ERR_OBJ_TYPE); goto done; } error = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1); if (error) goto done; bca.f = got_opentemp(); if (bca.f == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_object_blob_dump_to_file(&filesize, &bca.nlines, &bca.line_offsets, bca.f, blob); if (error || bca.nlines == 0) goto done; /* Don't include \n at EOF in the blame line count. */ if (bca.line_offsets[bca.nlines - 1] == filesize) bca.nlines--; bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); if (bca.lines == NULL) { error = got_error_from_errno("calloc"); goto done; } bca.lineno_cur = 1; bca.nlines_prec = 0; i = bca.nlines; while (i > 0) { i /= 10; bca.nlines_prec++; } bca.repo = repo; fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd3 = got_opentempfd(); if (fd3 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_blame(link_target ? link_target : in_repo_path, commit_id, repo, GOT_DIFF_ALGORITHM_PATIENCE, blame_cb, &bca, check_cancelled, NULL, fd2, fd3, f1, f2); done: free(keyword_idstr); free(in_repo_path); free(link_target); free(repo_path); free(cwd); free(commit_id); free(obj_id); if (commit) got_object_commit_close(commit); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd3 != -1 && close(fd3) == -1 && error == NULL) error = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (blob) got_object_blob_close(blob); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (bca.lines) { for (i = 0; i < bca.nlines; i++) { struct blame_line *bline = &bca.lines[i]; free(bline->id_str); free(bline->committer); } free(bca.lines); } free(bca.line_offsets); if (bca.f && fclose(bca.f) == EOF && error == NULL) error = got_error_from_errno("fclose"); return error; } __dead static void usage_tree(void) { fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] " "[path]\n", getprogname()); exit(1); } static const struct got_error * print_entry(struct got_tree_entry *te, const char *id, const char *path, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; int is_root_path = (strcmp(path, root_path) == 0); const char *modestr = ""; mode_t mode = got_tree_entry_get_mode(te); char *link_target = NULL; path += strlen(root_path); while (path[0] == '/') path++; if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) { int i; err = got_tree_entry_get_symlink_target(&link_target, te, repo); if (err) return err; for (i = 0; link_target[i] != '\0'; i++) { if (!isprint((unsigned char)link_target[i])) link_target[i] = '?'; } modestr = "@"; } else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; printf("%s%s%s%s%s%s%s\n", id ? id : "", path, is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr, link_target ? " -> ": "", link_target ? link_target : ""); free(link_target); return NULL; } static const struct got_error * print_tree(const char *path, struct got_commit_object *commit, int show_ids, int recurse, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *tree_id = NULL; struct got_tree_object *tree = NULL; int nentries, i; err = got_object_id_by_path(&tree_id, repo, commit, path); if (err) goto done; err = got_object_open_as_tree(&tree, repo, tree_id); if (err) goto done; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id = NULL; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); if (show_ids) { char *id_str; err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) goto done; if (asprintf(&id, "%s ", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } err = print_entry(te, id, path, root_path, repo); free(id); if (err) goto done; if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) { char *child_path; if (asprintf(&child_path, "%s%s%s", path, path[0] == '/' && path[1] == '\0' ? "" : "/", got_tree_entry_get_name(te)) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = print_tree(child_path, commit, show_ids, 1, root_path, repo); free(child_path); if (err) goto done; } } done: if (tree) got_object_tree_close(tree); free(tree_id); return err; } static const struct got_error * cmd_tree(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const char *path, *refname = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; char *commit_id_str = NULL, *keyword_idstr = NULL; int show_ids = 0, recurse = 0; int ch; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:iRr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'i': show_ids = 1; break; case 'R': recurse = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_tree(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else if (argc > 1) usage_tree(); else path = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; if (path == NULL || got_path_is_root_dir(path)) path = ""; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; if (path == NULL) path = "/"; error = got_repo_map_path(&in_repo_path, repo, path); if (error != NULL) goto done; } if (commit_id_str == NULL) { struct got_reference *head_ref; if (worktree) refname = got_worktree_get_head_ref_name(worktree); else refname = GOT_REF_HEAD; error = got_ref_open(&head_ref, repo, refname, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_str = keyword_idstr; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = print_tree(in_repo_path, commit, show_ids, recurse, in_repo_path, repo); done: free(keyword_idstr); free(in_repo_path); free(repo_path); free(cwd); free(commit_id); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_status(void) { fprintf(stderr, "usage: %s status [-I] [-S status-codes] " "[-s status-codes] [path ...]\n", getprogname()); exit(1); } struct got_status_arg { char *status_codes; int suppress; }; static const struct got_error * print_status(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct got_status_arg *st = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (st != NULL && st->status_codes) { size_t ncodes = strlen(st->status_codes); int i, j = 0; for (i = 0; i < ncodes ; i++) { if (st->suppress) { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) { j++; continue; } } else { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) break; } } if (st->suppress && j == 0) goto print; if (i == ncodes) return NULL; } print: printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * show_operation_in_progress(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; char *new_base_branch_name = NULL; char *branch_name = NULL; int rebase_in_progress, histedit_in_progress, merge_in_progress; err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (err) return err; if (rebase_in_progress) { err = got_worktree_rebase_info(&new_base_branch_name, &branch_name, worktree, repo); if (err) return err; printf("Work tree is rebasing %s onto %s\n", branch_name, new_base_branch_name); } err = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (err) return err; if (histedit_in_progress) { err = got_worktree_histedit_info(&branch_name, worktree, repo); if (err) return err; printf("Work tree is editing the history of %s\n", branch_name); } err = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (err) return err; if (merge_in_progress) { err = got_worktree_merge_info(&branch_name, worktree, repo); if (err) return err; printf("Work tree is merging %s into %s\n", branch_name, got_worktree_get_head_ref_name(worktree)); } free(new_base_branch_name); free(branch_name); return NULL; } static const struct got_error * cmd_status(int argc, char *argv[]) { const struct got_error *close_err, *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_status_arg st; char *cwd = NULL; struct got_pathlist_head paths; int ch, i, no_ignores = 0; int *pack_fds = NULL; RB_INIT(&paths); memset(&st, 0, sizeof(st)); st.status_codes = NULL; st.suppress = 0; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IS:s:")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'S': if (st.status_codes != NULL && st.suppress == 0) option_conflict('S', 's'); st.suppress = 1; /* fallthrough */ case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_CONFLICT: case GOT_STATUS_MISSING: case GOT_STATUS_OBSTRUCTED: case GOT_STATUS_UNVERSIONED: case GOT_STATUS_MODE_CHANGE: case GOT_STATUS_NONEXISTENT: break; default: errx(1, "invalid status code '%c'", optarg[i]); } } if (ch == 's' && st.suppress) option_conflict('s', 'S'); st.status_codes = optarg; break; default: usage_status(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_worktree_status(worktree, &paths, repo, no_ignores, print_status, &st, check_cancelled, NULL); if (error) goto done; error = show_operation_in_progress(worktree, repo); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree != NULL) { close_err = got_worktree_close(worktree); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_ref(void) { fprintf(stderr, "usage: %s ref [-dlt] [-c object] [-r repository-path] " "[-s reference] [name]\n", getprogname()); exit(1); } static const struct got_error * list_refs(struct got_repository *repo, const char *refname, int sort_by_time) { static const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; TAILQ_INIT(&refs); err = got_ref_list(&refs, repo, refname, sort_by_time ? got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name, repo); if (err) return err; TAILQ_FOREACH(re, &refs, entry) { char *refstr; refstr = got_ref_to_str(re->ref); if (refstr == NULL) { err = got_error_from_errno("got_ref_to_str"); break; } printf("%s: %s\n", got_ref_get_name(re->ref), refstr); free(refstr); } got_ref_list_free(&refs); return err; } static const struct got_error * delete_ref_by_name(struct got_repository *repo, const char *refname) { const struct got_error *err; struct got_reference *ref; err = got_ref_open(&ref, repo, refname, 0); if (err) return err; err = delete_ref(repo, ref); got_ref_close(ref); return err; } static const struct got_error * add_ref(struct got_repository *repo, const char *refname, const char *target) { const struct got_error *err = NULL; struct got_object_id *id = NULL; struct got_reference *ref = NULL; struct got_reflist_head refs; /* * Don't let the user create a reference name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (refname[0] == '-') return got_error_path(refname, GOT_ERR_REF_NAME_MINUS); TAILQ_INIT(&refs); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; err = got_repo_match_object_id(&id, NULL, target, GOT_OBJ_TYPE_ANY, &refs, repo); got_ref_list_free(&refs); if (err) goto done; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); done: if (ref) got_ref_close(ref); free(id); return err; } static const struct got_error * add_symref(struct got_repository *repo, const char *refname, const char *target) { const struct got_error *err = NULL; struct got_reference *ref = NULL; struct got_reference *target_ref = NULL; /* * Don't let the user create a reference name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (refname[0] == '-') return got_error_path(refname, GOT_ERR_REF_NAME_MINUS); err = got_ref_open(&target_ref, repo, target, 0); if (err) return err; err = got_ref_alloc_symref(&ref, refname, target_ref); if (err) goto done; err = got_ref_write(ref, repo); done: if (target_ref) got_ref_close(target_ref); if (ref) got_ref_close(ref); return err; } static const struct got_error * cmd_ref(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch, do_list = 0, do_delete = 0, sort_by_time = 0; const char *obj_arg = NULL, *symref_target= NULL; char *refname = NULL, *keyword_idstr = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:dlr:s:t")) != -1) { switch (ch) { case 'c': obj_arg = optarg; break; case 'd': do_delete = 1; break; case 'l': do_list = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 's': symref_target = optarg; break; case 't': sort_by_time = 1; break; default: usage_ref(); /* NOTREACHED */ } } if (obj_arg && do_list) option_conflict('c', 'l'); if (obj_arg && do_delete) option_conflict('c', 'd'); if (obj_arg && symref_target) option_conflict('c', 's'); if (symref_target && do_delete) option_conflict('s', 'd'); if (symref_target && do_list) option_conflict('s', 'l'); if (do_delete && do_list) option_conflict('d', 'l'); if (sort_by_time && !do_list) errx(1, "-t option requires -l option"); argc -= optind; argv += optind; if (do_list) { if (argc != 0 && argc != 1) usage_ref(); if (argc == 1) { refname = strdup(argv[0]); if (refname == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else { if (argc != 1) usage_ref(); refname = strdup(argv[0]); if (refname == NULL) { error = got_error_from_errno("strdup"); goto done; } } if (refname) got_path_strip_trailing_slashes(refname); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, NULL); if (error != NULL) goto done; #ifndef PROFILE if (do_list) { /* Remove "cpath" promise. */ if (pledge("stdio rpath wpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); } #endif error = apply_unveil(got_repo_get_path(repo), do_list, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (do_list) error = list_refs(repo, refname, sort_by_time); else if (do_delete) error = delete_ref_by_name(repo, refname); else if (symref_target) error = add_symref(repo, refname, symref_target); else { if (obj_arg == NULL) usage_ref(); error = got_keyword_to_idstr(&keyword_idstr, obj_arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) obj_arg = keyword_idstr; error = add_ref(repo, refname, obj_arg); } done: free(refname); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); free(cwd); free(repo_path); free(keyword_idstr); return error; } __dead static void usage_branch(void) { fprintf(stderr, "usage: %s branch [-lnt] [-c commit] [-d name] " "[-r repository-path] [name]\n", getprogname()); exit(1); } static const struct got_error * list_branch(struct got_repository *repo, struct got_worktree *worktree, struct got_reference *ref) { const struct got_error *err = NULL; const char *refname; char *refstr; char marker = ' '; refname = got_ref_get_name(ref); if (worktree && strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) { err = got_worktree_get_state(&marker, repo, worktree, check_cancelled, NULL); if (err != NULL) return err; } if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; if (strncmp(refname, "refs/got/worktree/", 18) == 0) refname += 18; if (strncmp(refname, "refs/remotes/", 13) == 0) refname += 13; refstr = got_ref_to_str(ref); if (refstr == NULL) return got_error_from_errno("got_ref_to_str"); printf("%c %s: %s\n", marker, refname, refstr); free(refstr); return NULL; } static const struct got_error * show_current_branch(struct got_repository *repo, struct got_worktree *worktree) { const char *refname; if (worktree == NULL) return got_error(GOT_ERR_NOT_WORKTREE); refname = got_worktree_get_head_ref_name(worktree); if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; if (strncmp(refname, "refs/got/worktree/", 18) == 0) refname += 18; printf("%s\n", refname); return NULL; } static const struct got_error * list_branches(struct got_repository *repo, struct got_worktree *worktree, int sort_by_time) { static const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_reference *temp_ref = NULL; int rebase_in_progress, histedit_in_progress; TAILQ_INIT(&refs); if (worktree) { err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (err) return err; err = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (err) return err; if (rebase_in_progress || histedit_in_progress) { err = got_ref_open(&temp_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (err) return err; list_branch(repo, worktree, temp_ref); got_ref_close(temp_ref); } } err = got_ref_list(&refs, repo, "refs/heads", sort_by_time ? got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name, repo); if (err) return err; TAILQ_FOREACH(re, &refs, entry) list_branch(repo, worktree, re->ref); got_ref_list_free(&refs); err = got_ref_list(&refs, repo, "refs/remotes", sort_by_time ? got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name, repo); if (err) return err; TAILQ_FOREACH(re, &refs, entry) list_branch(repo, worktree, re->ref); got_ref_list_free(&refs); return NULL; } static const struct got_error * delete_branch(struct got_repository *repo, struct got_worktree *worktree, const char *branch_name) { const struct got_error *err = NULL; struct got_reference *ref = NULL; char *refname, *remote_refname = NULL; if (strncmp(branch_name, "refs/", 5) == 0) branch_name += 5; if (strncmp(branch_name, "heads/", 6) == 0) branch_name += 6; else if (strncmp(branch_name, "remotes/", 8) == 0) branch_name += 8; if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) return got_error_from_errno("asprintf"); if (asprintf(&remote_refname, "refs/remotes/%s", branch_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_ref_open(&ref, repo, refname, 0); if (err) { const struct got_error *err2; if (err->code != GOT_ERR_NOT_REF) goto done; /* * Keep 'err' intact such that if neither branch exists * we report "refs/heads" rather than "refs/remotes" in * our error message. */ err2 = got_ref_open(&ref, repo, remote_refname, 0); if (err2) goto done; err = NULL; } if (worktree && strcmp(got_worktree_get_head_ref_name(worktree), got_ref_get_name(ref)) == 0) { err = got_error_msg(GOT_ERR_SAME_BRANCH, "will not delete this work tree's current branch"); goto done; } err = delete_ref(repo, ref); done: if (ref) got_ref_close(ref); free(refname); free(remote_refname); return err; } static const struct got_error * add_branch(struct got_repository *repo, const char *branch_name, struct got_object_id *base_commit_id) { const struct got_error *err = NULL; struct got_reference *ref = NULL; char *refname = NULL; /* * Don't let the user create a branch name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (branch_name[0] == '-') return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS); if (strncmp(branch_name, "refs/heads/", 11) == 0) branch_name += 11; if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_ref_open(&ref, repo, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_BRANCH_EXISTS); goto done; } else if (err->code != GOT_ERR_NOT_REF) goto done; err = got_ref_alloc(&ref, refname, base_commit_id); if (err) goto done; err = got_ref_write(ref, repo); done: if (ref) got_ref_close(ref); free(refname); return err; } static const struct got_error * cmd_branch(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch, do_list = 0, do_show = 0, do_update = 1, sort_by_time = 0; const char *delref = NULL, *commit_id_arg = NULL; struct got_reference *ref = NULL; struct got_pathlist_head paths; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL, *keyword_idstr = NULL;; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:d:lnr:t")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'd': delref = optarg; break; case 'l': do_list = 1; break; case 'n': do_update = 0; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 't': sort_by_time = 1; break; default: usage_branch(); /* NOTREACHED */ } } if (do_list && delref) option_conflict('l', 'd'); if (sort_by_time && !do_list) errx(1, "-t option requires -l option"); argc -= optind; argv += optind; if (!do_list && !delref && argc == 0) do_show = 1; if ((do_list || delref || do_show) && commit_id_arg != NULL) errx(1, "-c option can only be used when creating a branch"); if (do_list || delref) { if (argc > 0) usage_branch(); } else if (!do_show && argc != 1) usage_branch(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; #ifndef PROFILE if (do_list || do_show) { /* Remove "cpath" promise. */ if (pledge("stdio rpath wpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); } #endif error = apply_unveil(got_repo_get_path(repo), do_list, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (do_show) error = show_current_branch(repo, worktree); else if (do_list) error = list_branches(repo, worktree, sort_by_time); else if (delref) error = delete_branch(repo, worktree, delref); else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_arg == NULL) commit_id_arg = worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD; else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_arg = keyword_idstr; } error = got_repo_match_object_id(&commit_id, NULL, commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; error = add_branch(repo, argv[0], commit_id); if (error) goto done; if (worktree && do_update) { struct got_update_progress_arg upa; char *branch_refname = NULL; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = get_worktree_paths_from_argv(&paths, 0, NULL, worktree); if (error) goto done; if (asprintf(&branch_refname, "refs/heads/%s", argv[0]) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_ref_open(&ref, repo, branch_refname, 0); free(branch_refname); if (error) goto done; error = switch_head_ref(ref, commit_id, worktree, repo); if (error) goto done; error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; memset(&upa, 0, sizeof(upa)); error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); if (error) goto done; if (upa.did_something) { printf("Updated to %s: %s\n", got_worktree_get_head_ref_name(worktree), commit_id_str); } print_update_progress_stats(&upa); } } done: free(keyword_idstr); if (ref) got_ref_close(ref); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); free(repo_path); free(commit_id); free(commit_id_str); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); return error; } __dead static void usage_tag(void) { fprintf(stderr, "usage: %s tag [-lsVv] [-c commit] [-m message] " "[-r repository-path] [-S signer-id] name\n", getprogname()); exit(1); } #if 0 static const struct got_error * sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags) { const struct got_error *err = NULL; struct got_reflist_entry *re, *se, *new; struct got_object_id *re_id, *se_id; struct got_tag_object *re_tag, *se_tag; time_t re_time, se_time; STAILQ_FOREACH(re, tags, entry) { se = STAILQ_FIRST(sorted); if (se == NULL) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_HEAD(sorted, new, entry); continue; } else { err = got_ref_resolve(&re_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&re_tag, repo, re_id); free(re_id); if (err) break; re_time = got_object_tag_get_tagger_time(re_tag); got_object_tag_close(re_tag); } while (se) { err = got_ref_resolve(&se_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&se_tag, repo, se_id); free(se_id); if (err) break; se_time = got_object_tag_get_tagger_time(se_tag); got_object_tag_close(se_tag); if (se_time > re_time) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_AFTER(sorted, se, new, entry); break; } se = STAILQ_NEXT(se, entry); continue; } } done: return err; } #endif static const struct got_error * get_tag_refname(char **refname, const char *tag_name) { const struct got_error *err; if (strncmp("refs/tags/", tag_name, 10) == 0) { *refname = strdup(tag_name); if (*refname == NULL) return got_error_from_errno("strdup"); } else if (asprintf(refname, "refs/tags/%s", tag_name) == -1) { err = got_error_from_errno("asprintf"); *refname = NULL; return err; } return NULL; } static const struct got_error * print_tag_oneline(struct got_tag_object *tag, struct got_commit_object *commit, const char *refname, const char *refstr, time_t tagger_time, const char *id_str) { static const struct got_error *err = NULL; const char *label = NULL; struct tm tm; char *tagmsg0 = NULL, *tagmsg; char datebuf[11]; if (gmtime_r(&tagger_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(datebuf, sizeof(datebuf), "%F", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); if (commit) { err = got_object_commit_get_logmsg(&tagmsg0, commit); if (err) return err; } else { tagmsg0 = strdup(got_object_tag_get_message(tag)); if (tagmsg0 == NULL) return got_error_from_errno("strdup"); } tagmsg = tagmsg0; while (isspace((unsigned char)*tagmsg)) tagmsg++; tagmsg[strcspn(tagmsg, "\n")] = '\0'; if (commit) label = GOT_OBJ_LABEL_COMMIT; else { switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: label = GOT_OBJ_LABEL_BLOB; break; case GOT_OBJ_TYPE_TREE: label = GOT_OBJ_LABEL_TREE; break; case GOT_OBJ_TYPE_COMMIT: label = GOT_OBJ_LABEL_COMMIT; break; case GOT_OBJ_TYPE_TAG: label = GOT_OBJ_LABEL_TAG; break; default: break; } } if (label) printf("%s %s:%.10s %s: %s\n", datebuf, label, id_str, refname, tagmsg); else printf("%s tag:%.10s %s: %s\n", datebuf, refstr, refname, tagmsg); free(tagmsg0); return err; } static const struct got_error * print_tag(struct got_tag_object *tag, struct got_commit_object *commit, const char *refname, const char *refstr, const char *tagger, time_t tagger_time, const char *id_str, const char *ssh_sig, const char *allowed_signers, const char *revoked_signers, int verbosity, int *bad_sigs) { static const struct got_error *err = NULL; char datebuf[26]; char *sig_msg = NULL, *tagmsg0 = NULL, *tagmsg, *line, *datestr; printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); printf("from: %s\n", tagger); datestr = get_datestr(&tagger_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (commit) printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); else { switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); break; case GOT_OBJ_TYPE_TREE: printf("object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); break; case GOT_OBJ_TYPE_COMMIT: printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); break; case GOT_OBJ_TYPE_TAG: printf("object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); break; default: break; } } if (ssh_sig) { err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, allowed_signers, revoked_signers, verbosity); if (err) { if (err->code != GOT_ERR_BAD_TAG_SIGNATURE) goto done; *bad_sigs = 1; err = NULL; } if (sig_msg) printf("signature: %s", sig_msg); else printf("bad signature\n"); free(sig_msg); } if (commit) { err = got_object_commit_get_logmsg(&tagmsg0, commit); if (err) goto done; } else { tagmsg0 = strdup(got_object_tag_get_message(tag)); if (tagmsg0 == NULL) { err = got_error_from_errno("strdup"); goto done; } } tagmsg = tagmsg0; while ((line = strsep(&tagmsg, "\n")) != NULL) printf(" %s\n", line); done: free(tagmsg0); return err; } static const struct got_error * list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, const char *allowed_signers, const char *revoked_signers, int verbosity, int oneline) { static const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; char *wanted_refname = NULL; int bad_sigs = 0; TAILQ_INIT(&refs); err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo); if (err) return err; if (tag_name) { struct got_reference *ref; err = get_tag_refname(&wanted_refname, tag_name); if (err) goto done; /* Wanted tag reference should exist. */ err = got_ref_open(&ref, repo, wanted_refname, 0); if (err) goto done; got_ref_close(ref); } TAILQ_FOREACH(re, &refs, entry) { const char *refname; char *refstr, *id_str; const char *tagger, *ssh_sig = NULL; time_t tagger_time; struct got_object_id *id; struct got_tag_object *tag; struct got_commit_object *commit = NULL; refname = got_ref_get_name(re->ref); if (strncmp(refname, "refs/tags/", 10) != 0 || (wanted_refname && strcmp(refname, wanted_refname) != 0)) continue; refname += 10; refstr = got_ref_to_str(re->ref); if (refstr == NULL) { err = got_error_from_errno("got_ref_to_str"); break; } err = got_ref_resolve(&id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&tag, repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(id); break; } /* "lightweight" tag */ err = got_object_open_as_commit(&commit, repo, id); if (err) { free(id); break; } tagger = got_object_commit_get_committer(commit); tagger_time = got_object_commit_get_committer_time(commit); err = got_object_id_str(&id_str, id); free(id); if (err) break; } else { free(id); tagger = got_object_tag_get_tagger(tag); tagger_time = got_object_tag_get_tagger_time(tag); err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) break; } if (tag && verify_tags) { ssh_sig = got_sigs_get_tagmsg_ssh_signature( got_object_tag_get_message(tag)); if (ssh_sig && allowed_signers == NULL) { err = got_error_msg( GOT_ERR_VERIFY_TAG_SIGNATURE, "SSH signature verification requires " "setting allowed_signers in " "got.conf(5)"); break; } } if (oneline) err = print_tag_oneline(tag, commit, refname, refstr, tagger_time, id_str); else err = print_tag(tag, commit, refname, refstr, tagger, tagger_time, id_str, ssh_sig, allowed_signers, revoked_signers, verbosity, &bad_sigs); if (commit) got_object_commit_close(commit); if (tag) got_object_tag_close(tag); free(id_str); free(refstr); if (err) break; } done: got_ref_list_free(&refs); free(wanted_refname); if (err == NULL && bad_sigs) err = got_error(GOT_ERR_BAD_TAG_SIGNATURE); return err; } static const struct got_error * get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str, const char *tag_name, const char *editor, const char *repo_path) { const struct got_error *err = NULL; char *template = NULL, *initial_content = NULL; int initial_content_len; int fd = -1; if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) { err = got_error_from_errno("asprintf"); goto done; } initial_content_len = asprintf(&initial_content, "\n# tagging commit %s as %s\n", commit_id_str, tag_name); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(tagmsg_path, &fd, template, ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *tagmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *tagmsg_path); goto done; } fd = -1; err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content, initial_content_len, 1); done: free(initial_content); free(template); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *tagmsg_path); if (err) { free(*tagmsg); *tagmsg = NULL; } return err; } static const struct got_error * add_tag(struct got_repository *repo, const char *tagger, const char *tag_name, const char *commit_arg, const char *tagmsg_arg, const char *signer_id, const char *editor, int verbosity) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL, *tag_id = NULL; char *label = NULL, *commit_id_str = NULL; struct got_reference *ref = NULL; char *refname = NULL, *tagmsg = NULL; char *tagmsg_path = NULL, *tag_id_str = NULL; int preserve_tagmsg = 0; struct got_reflist_head refs; TAILQ_INIT(&refs); /* * Don't let the user create a tag name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (tag_name[0] == '-') return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; err = got_repo_match_object_id(&commit_id, &label, commit_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (err) goto done; err = got_object_id_str(&commit_id_str, commit_id); if (err) goto done; err = get_tag_refname(&refname, tag_name); if (err) goto done; if (strncmp("refs/tags/", tag_name, 10) == 0) tag_name += 10; err = got_ref_open(&ref, repo, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_TAG_EXISTS); goto done; } else if (err->code != GOT_ERR_NOT_REF) goto done; if (tagmsg_arg == NULL) { err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str, tag_name, editor, got_repo_get_path(repo)); if (err) { if (err->code != GOT_ERR_COMMIT_MSG_EMPTY && tagmsg_path != NULL) preserve_tagmsg = 1; goto done; } } err = got_object_tag_create(&tag_id, tag_name, commit_id, tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, signer_id, repo, verbosity); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_alloc(&ref, refname, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_write(ref, repo); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_object_id_str(&tag_id_str, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } printf("Created tag %s\n", tag_id_str); done: if (preserve_tagmsg) { fprintf(stderr, "%s: tag message preserved in %s\n", getprogname(), tagmsg_path); } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", tagmsg_path); free(tag_id_str); if (ref) got_ref_close(ref); free(commit_id); free(commit_id_str); free(refname); free(tagmsg); free(tagmsg_path); got_ref_list_free(&refs); return err; } static const struct got_error * cmd_tag(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL; char *gitconfig_path = NULL, *tagger = NULL, *keyword_idstr = NULL; char *allowed_signers = NULL, *revoked_signers = NULL, *editor = NULL; const char *signer_id = NULL; const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; int ch, do_list = 0, oneline = 0, verify_tags = 0, verbosity = 0; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:lm:r:S:sVv")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'l': do_list = 1; break; case 'm': tagmsg = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } got_path_strip_trailing_slashes(repo_path); break; case 'S': signer_id = optarg; break; case 's': oneline = 1; break; case 'V': verify_tags = 1; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_tag(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (oneline && !do_list) errx(1, "-s option can only be used when listing tags"); else if (do_list || verify_tags) { if (commit_id_arg != NULL) errx(1, "-c option can only be used when creating a tag"); if (tagmsg) { if (do_list) option_conflict('l', 'm'); else option_conflict('V', 'm'); } if (signer_id) { if (do_list) option_conflict('l', 'S'); else option_conflict('V', 'S'); } if (argc > 1) usage_tag(); } else if (argc != 1) usage_tag(); if (argc == 1) tag_name = argv[0]; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } if (do_list || verify_tags) { error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_allowed_signers(&allowed_signers, repo, worktree); if (error) goto done; error = get_revoked_signers(&revoked_signers, repo, worktree); if (error) goto done; if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } /* * Remove "cpath" promise unless needed for signature tmpfile * creation. */ if (verify_tags) got_sigs_apply_unveil(); else { #ifndef PROFILE if (pledge("stdio rpath wpath flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif } error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = list_tags(repo, tag_name, verify_tags, allowed_signers, revoked_signers, verbosity, oneline); } else { error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds); if (error != NULL) goto done; error = get_author(&tagger, repo, worktree); if (error) goto done; if (signer_id == NULL) signer_id = get_signer_id(repo, worktree); if (tagmsg == NULL) { error = get_editor(&editor); if (error) goto done; if (unveil(editor, "x") != 0) { error = got_error_from_errno2("unveil", editor); goto done; } } if (signer_id) { error = got_sigs_apply_unveil(); if (error) goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; if (commit_id_arg == NULL) { struct got_reference *head_ref; struct got_object_id *commit_id; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); free(commit_id); if (error) goto done; } else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_arg, repo, worktree); if (error != NULL) goto done; commit_id_str = keyword_idstr; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = add_tag(repo, tagger, tag_name, commit_id_str ? commit_id_str : commit_id_arg, tagmsg, signer_id, editor, verbosity); } done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); free(editor); free(repo_path); free(gitconfig_path); free(commit_id_str); free(tagger); free(allowed_signers); free(revoked_signers); return error; } __dead static void usage_add(void) { fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname()); exit(1); } static const struct got_error * add_progress(void *arg, unsigned char status, const char *path) { while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } static const struct got_error * cmd_add(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, no_ignores = 0; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IR")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'R': can_recurse = 1; break; default: usage_add(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_add(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "add", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "adding directories requires -R option"); goto done; } } } error = got_worktree_schedule_add(worktree, &paths, add_progress, NULL, repo, no_ignores); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_remove(void) { fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n", getprogname()); exit(1); } static const struct got_error * print_remove_status(void *arg, unsigned char status, unsigned char staged_status, const char *path) { while (path[0] == '/') path++; if (status == GOT_STATUS_NONEXISTENT) return NULL; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * cmd_remove(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; const char *status_codes = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i; int ignore_missing_paths = 0; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "fkRs:")) != -1) { switch (ch) { case 'f': delete_local_mods = 1; ignore_missing_paths = 1; break; case 'k': keep_on_disk = 1; break; case 'R': can_recurse = 1; break; case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: delete_local_mods = 1; break; case GOT_STATUS_MISSING: ignore_missing_paths = 1; break; default: errx(1, "invalid status code '%c'", optarg[i]); } } status_codes = optarg; break; default: usage_remove(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_remove(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "remove", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "removing directories requires -R option"); goto done; } } } error = got_worktree_schedule_delete(worktree, &paths, delete_local_mods, status_codes, print_remove_status, NULL, repo, keep_on_disk, ignore_missing_paths); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_patch(void) { fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] " "[patchfile]\n", getprogname()); exit(1); } static const struct got_error * patch_from_stdin(int *patchfd) { const struct got_error *err = NULL; ssize_t r; char buf[BUFSIZ]; sig_t sighup, sigint, sigquit; *patchfd = got_opentempfd(); if (*patchfd == -1) return got_error_from_errno("got_opentempfd"); sighup = signal(SIGHUP, SIG_DFL); sigint = signal(SIGINT, SIG_DFL); sigquit = signal(SIGQUIT, SIG_DFL); for (;;) { r = read(0, buf, sizeof(buf)); if (r == -1) { err = got_error_from_errno("read"); break; } if (r == 0) break; if (write(*patchfd, buf, r) == -1) { err = got_error_from_errno("write"); break; } } signal(SIGHUP, sighup); signal(SIGINT, sigint); signal(SIGQUIT, sigquit); if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1) err = got_error_from_errno("lseek"); if (err != NULL) { close(*patchfd); *patchfd = -1; } return err; } struct got_patch_progress_arg { int did_something; int conflicts; int rejects; }; static const struct got_error * patch_progress(void *arg, const char *old, const char *new, unsigned char status, const struct got_error *error, int old_from, int old_lines, int new_from, int new_lines, int offset, int ws_mangled, const struct got_error *hunk_err) { const char *path = new == NULL ? old : new; struct got_patch_progress_arg *a = arg; while (*path == '/') path++; if (status != GOT_STATUS_NO_CHANGE && status != 0 /* per-hunk progress */) { printf("%c %s\n", status, path); a->did_something = 1; } if (hunk_err == NULL) { if (status == GOT_STATUS_CANNOT_UPDATE) a->rejects++; else if (status == GOT_STATUS_CONFLICT) a->conflicts++; } if (error != NULL) fprintf(stderr, "%s: %s\n", getprogname(), error->msg); if (offset != 0 || hunk_err != NULL || ws_mangled) { printf("@@ -%d,%d +%d,%d @@ ", old_from, old_lines, new_from, new_lines); if (hunk_err != NULL) printf("%s\n", hunk_err->msg); else if (offset != 0) printf("applied with offset %d\n", offset); else printf("hunk contains mangled whitespace\n"); } return NULL; } static void print_patch_progress_stats(struct got_patch_progress_arg *ppa) { if (!ppa->did_something) return; if (ppa->conflicts > 0) printf("Files with merge conflicts: %d\n", ppa->conflicts); if (ppa->rejects > 0) { printf("Files where patch failed to apply: %d\n", ppa->rejects); } } static const struct got_error * cmd_patch(int argc, char *argv[]) { const struct got_error *error = NULL, *close_error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; struct got_reflist_head refs; struct got_object_id *commit_id = NULL; const char *commit_id_str = NULL; struct stat sb; const char *errstr; char *cwd = NULL, *keyword_idstr = NULL; int ch, nop = 0, strip = -1, reverse = 0; int patchfd; int *pack_fds = NULL; struct got_patch_progress_arg ppa; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:np:R")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'n': nop = 1; break; case 'p': strip = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "pathname strip count is %s: %s", errstr, optarg); break; case 'R': reverse = 1; break; default: usage_patch(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 0) { error = patch_from_stdin(&patchfd); if (error) return error; } else if (argc == 1) { patchfd = open(argv[0], O_RDONLY); if (patchfd == -1) return got_error_from_errno2("open", argv[0]); if (fstat(patchfd, &sb) == -1) { error = got_error_from_errno2("fstat", argv[0]); goto done; } if (!S_ISREG(sb.st_mode)) { error = got_error_path(argv[0], GOT_ERR_BAD_FILETYPE); goto done; } } else usage_patch(); if ((cwd = getcwd(NULL, 0)) == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error != NULL) goto done; const char *repo_path = got_worktree_get_repo_path(worktree); error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error != NULL) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str != NULL) { error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; error = got_repo_match_object_id(&commit_id, NULL, keyword_idstr != NULL ? keyword_idstr : commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; } memset(&ppa, 0, sizeof(ppa)); error = got_patch(patchfd, worktree, repo, nop, strip, reverse, commit_id, patch_progress, &ppa, check_cancelled, NULL); print_patch_progress_stats(&ppa); done: got_ref_list_free(&refs); free(keyword_idstr); free(commit_id); if (repo) { close_error = got_repo_close(repo); if (error == NULL) error = close_error; } if (worktree != NULL) { close_error = got_worktree_close(worktree); if (error == NULL) error = close_error; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); return error; } __dead static void usage_revert(void) { fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n", getprogname()); exit(1); } static const struct got_error * revert_progress(void *arg, unsigned char status, const char *path) { if (status == GOT_STATUS_UNVERSIONED) return NULL; while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } struct choose_patch_arg { FILE *patch_script_file; const char *action; }; static const struct got_error * show_change(unsigned char status, const char *path, FILE *patch_file, int n, int nchanges, const char *action) { const struct got_error *err; char *line = NULL; size_t linesize = 0; ssize_t linelen; switch (status) { case GOT_STATUS_ADD: printf("A %s\n%s this addition? [y/n] ", path, action); break; case GOT_STATUS_DELETE: printf("D %s\n%s this deletion? [y/n] ", path, action); break; case GOT_STATUS_MODIFY: if (fseek(patch_file, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); printf(GOT_COMMIT_SEP_STR); while ((linelen = getline(&line, &linesize, patch_file)) != -1) printf("%s", line); if (linelen == -1 && ferror(patch_file)) { err = got_error_from_errno("getline"); free(line); return err; } free(line); printf(GOT_COMMIT_SEP_STR); printf("M %s (change %d of %d)\n%s this change? [y/n/q] ", path, n, nchanges, action); break; default: return got_error_path(path, GOT_ERR_FILE_STATUS); } fflush(stdout); return NULL; } #define CHOOSE_PATCH_VALID_RESPONSES "ynq" static const struct got_error * choose_patch(int *choice, void *arg, unsigned char status, const char *path, FILE *patch_file, int n, int nchanges) { const struct got_error *err = NULL; char *nl, *line = NULL; FILE *fp = stdin; size_t linesize = 0; ssize_t linelen; int interactive = 1; struct choose_patch_arg *a = arg; *choice = GOT_PATCH_CHOICE_NONE; if (a->patch_script_file) { interactive = 0; fp = a->patch_script_file; } for (;;) { err = show_change(status, path, patch_file, n, nchanges, a->action); if (err) return err; linelen = getline(&line, &linesize, fp); if (linelen == -1) { free(line); if (ferror(fp)) return got_error_from_errno("getline"); if (feof(fp)) return got_error(GOT_ERR_EOF); return NULL; } nl = strchr(line, '\n'); if (nl) *nl = '\0'; if (strlen(line) != 1 || !strchr(CHOOSE_PATCH_VALID_RESPONSES, line[0])) { printf("invalid response '%s'\n", line); if (interactive) continue; } /* ADD and DELETE do not accept 'q' response currently. */ if (status != GOT_STATUS_MODIFY && line[0] == 'q') { printf("invalid response '%s'\n", line); continue; } break; } switch (line[0]) { case 'y': *choice = GOT_PATCH_CHOICE_YES; break; case 'n': *choice = GOT_PATCH_CHOICE_NO; break; case 'q': if (status == GOT_STATUS_MODIFY) *choice = GOT_PATCH_CHOICE_QUIT; break; default: printf("invalid response '%s'\n", line); free(line); return NULL; } if (!interactive) printf("%c\n", line[0]); free(line); return NULL; } struct wt_commitable_path_arg { struct got_pathlist_head *commit_paths; int *has_changes; }; /* * Shortcut work tree status callback to determine if the set of paths scanned * has at least one versioned path that is being modified and, if not NULL, is * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as * soon as a path is passed with a status that satisfies this criteria. */ static const struct got_error * worktree_has_commitable_path(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct wt_commitable_path_arg *a = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (!(status == GOT_STATUS_NO_CHANGE || status == GOT_STATUS_UNVERSIONED) || staged_status != GOT_STATUS_NO_CHANGE) { if (a->commit_paths != NULL) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, a->commit_paths) { if (strncmp(path, pe->path, pe->path_len) == 0) { *a->has_changes = 1; break; } } } else *a->has_changes = 1; if (*a->has_changes) return got_error(GOT_ERR_FILE_MODIFIED); } return NULL; } /* * Check that the changeset of the commit identified by id is * comprised of at least one modified path that is being committed. */ static const struct got_error * commit_path_changed_in_worktree(struct wt_commitable_path_arg *wcpa, struct got_object_id *id, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_tree_object *tree = NULL, *ptree = NULL; struct got_object_qid *pid; RB_INIT(&paths); err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; err = got_object_open_as_tree(&tree, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &pid->id); if (err) goto done; err = got_object_open_as_tree(&ptree, repo, got_object_commit_get_tree_id(pcommit)); if (err) goto done; } err = got_diff_tree(ptree, tree, NULL, NULL, -1, -1, "", "", repo, got_diff_tree_collect_changed_paths, &paths, 0); if (err) goto done; err = got_worktree_status(worktree, &paths, repo, 0, worktree_has_commitable_path, wcpa, check_cancelled, NULL); if (err && err->code == GOT_ERR_FILE_MODIFIED) { /* * At least one changed path in the referenced commit is * modified in the work tree, that's all we need to know! */ err = NULL; } done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); if (tree) got_object_tree_close(tree); if (ptree) got_object_tree_close(ptree); return err; } /* * Remove any "logmsg" reference comprised entirely of paths that have * been reverted in this work tree. If any path in the logmsg ref changeset * remains in a changed state in the worktree, do not remove the reference. */ static const struct got_error * rm_logmsg_ref(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct wt_commitable_path_arg wcpa; char *uuidstr = NULL; TAILQ_INIT(&refs); err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname; int has_changes = 0; refname = got_ref_get_name(re->ref); if (!strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN)) refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; else if (!strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN)) refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&commit_id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; wcpa.commit_paths = NULL; wcpa.has_changes = &has_changes; err = commit_path_changed_in_worktree(&wcpa, commit_id, worktree, repo); if (err) goto done; if (!has_changes) { err = got_ref_delete(re->ref, repo); if (err) goto done; } got_object_commit_close(commit); commit = NULL; free(commit_id); commit_id = NULL; } done: free(uuidstr); free(commit_id); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * cmd_revert(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *path = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, pflag = 0; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "F:pR")) != -1) { switch (ch) { case 'F': patch_script_path = optarg; break; case 'p': pflag = 1; break; case 'R': can_recurse = 1; break; default: usage_revert(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_revert(); if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "revert", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; if (patch_script_path) { patch_script_file = fopen(patch_script_path, "re"); if (patch_script_file == NULL) { error = got_error_from_errno2("fopen", patch_script_path); goto done; } } /* * XXX "c" perm needed on repo dir to delete merge references. */ error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "reverting directories requires -R option"); goto done; } } } cpa.patch_script_file = patch_script_file; cpa.action = "revert"; error = got_worktree_revert(worktree, &paths, revert_progress, NULL, pflag ? choose_patch : NULL, &cpa, repo); error = rm_logmsg_ref(worktree, repo); done: if (patch_script_file && fclose(patch_script_file) == EOF && error == NULL) error = got_error_from_errno2("fclose", patch_script_path); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(path); free(cwd); return error; } __dead static void usage_commit(void) { fprintf(stderr, "usage: %s commit [-CNnS] [-A author] [-F path] " "[-m message] [path ...]\n", getprogname()); exit(1); } struct collect_commit_logmsg_arg { const char *cmdline_log; const char *prepared_log; const char *merged_log; int non_interactive; const char *editor; const char *worktree_path; const char *branch_name; const char *repo_path; char *logmsg_path; }; static const struct got_error * read_prepared_logmsg(char **logmsg, const char *path) { const struct got_error *err = NULL; FILE *f = NULL; struct stat sb; size_t r; *logmsg = NULL; memset(&sb, 0, sizeof(sb)); f = fopen(path, "re"); if (f == NULL) return got_error_from_errno2("fopen", path); if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", path); goto done; } if (sb.st_size == 0) { err = got_error(GOT_ERR_COMMIT_MSG_EMPTY); goto done; } *logmsg = malloc(sb.st_size + 1); if (*logmsg == NULL) { err = got_error_from_errno("malloc"); goto done; } r = fread(*logmsg, 1, sb.st_size, f); if (r != sb.st_size) { if (ferror(f)) err = got_error_from_errno2("fread", path); else err = got_error(GOT_ERR_IO); goto done; } (*logmsg)[sb.st_size] = '\0'; done: if (fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_commit_logmsg(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) { char *initial_content = NULL; struct got_pathlist_entry *pe; const struct got_error *err = NULL; char *template = NULL; char *prepared_msg = NULL, *merged_msg = NULL; struct collect_commit_logmsg_arg *a = arg; int initial_content_len; int fd = -1; size_t len; /* if a message was specified on the command line, just use it */ if (a->cmdline_log != NULL && *a->cmdline_log != '\0') { len = strlen(a->cmdline_log) + 1; *logmsg = malloc(len + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); strlcpy(*logmsg, a->cmdline_log, len); return NULL; } else if (a->prepared_log != NULL && a->non_interactive) return read_prepared_logmsg(logmsg, a->prepared_log); if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(&a->logmsg_path, &fd, template, ""); if (err) goto done; if (a->prepared_log) { err = read_prepared_logmsg(&prepared_msg, a->prepared_log); if (err) goto done; } else if (a->merged_log) { err = read_prepared_logmsg(&merged_msg, a->merged_log); if (err) goto done; } initial_content_len = asprintf(&initial_content, "%s%s\n# changes to be committed on branch %s:\n", prepared_msg ? prepared_msg : "", merged_msg ? merged_msg : "", a->branch_name); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", a->logmsg_path); goto done; } RB_FOREACH(pe, got_pathlist_head, commitable_paths) { struct got_commitable *ct = pe->data; dprintf(fd, "# %c %s\n", got_commitable_get_status(ct), got_commitable_get_path(ct)); } if (diff_path) { dprintf(fd, "# detailed changes can be viewed in %s\n", diff_path); } if (close(fd) == -1) { err = got_error_from_errno2("close", a->logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content, initial_content_len, a->prepared_log ? 0 : 1); done: free(initial_content); free(template); free(prepared_msg); free(merged_msg); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", a->logmsg_path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * cat_logmsg(FILE *f, struct got_commit_object *commit, const char *idstr, const char *type, int has_content) { const struct got_error *err = NULL; char *logmsg = NULL; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) return err; if (fprintf(f, "%s# log message of %s commit %s:%s", has_content ? "\n" : "", type, idstr, logmsg) < 0) err = got_ferror(f, GOT_ERR_IO); free(logmsg); return err; } /* * Lookup "logmsg" references of backed-out and cherrypicked commits * belonging to the current work tree. If found, and the worktree has * at least one modified file that was changed in the referenced commit, * add its log message to a new temporary file at *logmsg_path. * Add all refs found to matched_refs to be scheduled for removal on * successful commit. */ static const struct got_error * lookup_logmsg_ref(char **logmsg_path, struct got_pathlist_head *paths, struct got_reflist_head *matched_refs, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; struct got_reflist_head refs; struct got_reflist_entry *re, *re_match; FILE *f = NULL; char *uuidstr = NULL; int added_logmsg = 0; TAILQ_INIT(&refs); *logmsg_path = NULL; err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *type; struct wt_commitable_path_arg wcpa; int add_logmsg = 0; refname = got_ref_get_name(re->ref); if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; type = "cherrypicked"; } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; type = "backed-out"; } else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; wcpa.commit_paths = paths; wcpa.has_changes = &add_logmsg; err = commit_path_changed_in_worktree(&wcpa, id, worktree, repo); if (err) goto done; if (add_logmsg) { if (f == NULL) { err = got_opentemp_named(logmsg_path, &f, "got-commit-logmsg", ""); if (err) goto done; } err = cat_logmsg(f, commit, refname, type, added_logmsg); if (err) goto done; if (!added_logmsg) ++added_logmsg; err = got_reflist_entry_dup(&re_match, re); if (err) goto done; TAILQ_INSERT_HEAD(matched_refs, re_match, entry); } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } done: free(id); free(uuidstr); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (!added_logmsg) { if (*logmsg_path && unlink(*logmsg_path) != 0 && err == NULL) err = got_error_from_errno2("unlink", *logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * cmd_commit(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *id_str = NULL; struct got_object_id *id = NULL; const char *logmsg = NULL; char *prepared_logmsg = NULL, *merged_logmsg = NULL; struct collect_commit_logmsg_arg cl_arg; const char *author = NULL; char *gitconfig_path = NULL, *editor = NULL, *committer = NULL; int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0; int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0; int show_diff = 1, commit_conflicts = 0; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; int *pack_fds = NULL; TAILQ_INIT(&refs); RB_INIT(&paths); cl_arg.logmsg_path = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "A:CF:m:NnS")) != -1) { switch (ch) { case 'A': author = optarg; error = valid_author(author); if (error) return error; break; case 'C': commit_conflicts = 1; break; case 'F': if (logmsg != NULL) option_conflict('F', 'm'); prepared_logmsg = realpath(optarg, NULL); if (prepared_logmsg == NULL) return got_error_from_errno2("realpath", optarg); break; case 'm': if (prepared_logmsg) option_conflict('m', 'F'); logmsg = optarg; break; case 'N': non_interactive = 1; break; case 'n': show_diff = 0; break; case 'S': allow_bad_symlinks = 1; break; default: usage_commit(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "commit", cwd); goto done; } error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (error) goto done; if (rebase_in_progress) { error = got_error(GOT_ERR_REBASING); goto done; } error = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (error) goto done; error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), gitconfig_path, pack_fds); if (error != NULL) goto done; error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } error = get_author(&committer, repo, worktree); if (error) goto done; if (author == NULL) author = committer; if (logmsg == NULL || strlen(logmsg) == 0) { error = get_editor(&editor); if (error) goto done; if (unveil(editor, "x") != 0) { error = got_error_from_errno2("unveil", editor); goto done; } } if (prepared_logmsg) { if (unveil(prepared_logmsg, "r") != 0) { error = got_error_from_errno2("unveil", prepared_logmsg); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (prepared_logmsg == NULL) { error = lookup_logmsg_ref(&merged_logmsg, argc > 0 ? &paths : NULL, &refs, worktree, repo); if (error) goto done; } cl_arg.editor = editor; cl_arg.cmdline_log = logmsg; cl_arg.prepared_log = prepared_logmsg; cl_arg.merged_log = merged_logmsg; cl_arg.non_interactive = non_interactive; cl_arg.worktree_path = got_worktree_get_root_path(worktree); cl_arg.branch_name = got_worktree_get_head_ref_name(worktree); if (!histedit_in_progress) { if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) { error = got_error(GOT_ERR_COMMIT_BRANCH); goto done; } cl_arg.branch_name += 11; } cl_arg.repo_path = got_repo_get_path(repo); error = got_worktree_commit(&id, worktree, &paths, author, 0, committer, allow_bad_symlinks, show_diff, commit_conflicts, collect_commit_logmsg, &cl_arg, print_status, NULL, repo); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && cl_arg.logmsg_path != NULL) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, id); if (error) goto done; printf("Created commit %s\n", id_str); TAILQ_FOREACH(re, &refs, entry) { error = got_ref_delete(re->ref, repo); if (error) goto done; } done: if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), cl_arg.logmsg_path); } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", cl_arg.logmsg_path); free(cl_arg.logmsg_path); if (merged_logmsg && unlink(merged_logmsg) == -1 && error == NULL) error = got_error_from_errno2("unlink", merged_logmsg); free(merged_logmsg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(gitconfig_path); free(editor); free(committer); free(prepared_logmsg); return error; } __dead static void usage_send(void) { fprintf(stderr, "usage: %s send [-afqTv] [-b branch] [-d branch] " "[-i identity-file] [-J jumphost] [-r repository-path] [-t tag] " "[remote-repository]\n", getprogname()); exit(1); } static void print_load_info(int print_colored, int print_found, int print_trees, int ncolored, int nfound, int ntrees) { if (print_colored) { printf("%d commit%s colored", ncolored, ncolored == 1 ? "" : "s"); } if (print_found) { printf("%s%d object%s found", ncolored > 0 ? "; " : "", nfound, nfound == 1 ? "" : "s"); } if (print_trees) { printf("; %d tree%s scanned", ntrees, ntrees == 1 ? "" : "s"); } } struct got_send_progress_arg { char last_scaled_packsize[FMT_SCALED_STRSIZE]; int verbosity; int last_ncolored; int last_nfound; int last_ntrees; int loading_done; int last_ncommits; int last_nobj_total; int last_p_deltify; int last_p_written; int last_p_sent; int printed_something; int sent_something; struct got_pathlist_head *delete_branches; }; static const struct got_error * send_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, off_t bytes_sent, const char *refname, const char *errmsg, int success) { struct got_send_progress_arg *a = arg; char scaled_packsize[FMT_SCALED_STRSIZE]; char scaled_sent[FMT_SCALED_STRSIZE]; int p_deltify = 0, p_written = 0, p_sent = 0; int print_colored = 0, print_found = 0, print_trees = 0; int print_searching = 0, print_total = 0; int print_deltify = 0, print_written = 0, print_sent = 0; if (a->verbosity < 0) return NULL; if (refname) { const char *status = success ? "accepted" : "rejected"; if (success) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, a->delete_branches) { const char *branchname = pe->path; if (got_path_cmp(branchname, refname, strlen(branchname), strlen(refname)) == 0) { status = "deleted"; a->sent_something = 1; break; } } } if (a->printed_something) putchar('\n'); printf("Server has %s %s", status, refname); if (errmsg) printf(": %s", errmsg); a->printed_something = 1; return NULL; } if (a->last_ncolored != ncolored) { print_colored = 1; a->last_ncolored = ncolored; } if (a->last_nfound != nfound) { print_colored = 1; print_found = 1; a->last_nfound = nfound; } if (a->last_ntrees != ntrees) { print_colored = 1; print_found = 1; print_trees = 1; a->last_ntrees = ntrees; } if ((print_colored || print_found || print_trees) && !a->loading_done) { printf("\r"); print_load_info(print_colored, print_found, print_trees, ncolored, nfound, ntrees); a->printed_something = 1; fflush(stdout); return NULL; } else if (!a->loading_done) { printf("\r"); print_load_info(1, 1, 1, ncolored, nfound, ntrees); printf("\n"); a->loading_done = 1; } if (fmt_scaled(packfile_size, scaled_packsize) == -1) return got_error_from_errno("fmt_scaled"); if (fmt_scaled(bytes_sent, scaled_sent) == -1) return got_error_from_errno("fmt_scaled"); if (a->last_ncommits != ncommits) { print_searching = 1; a->last_ncommits = ncommits; } if (a->last_nobj_total != nobj_total) { print_searching = 1; print_total = 1; a->last_nobj_total = nobj_total; } if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' || strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) { if (strlcpy(a->last_scaled_packsize, scaled_packsize, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_deltify > 0 || nobj_written > 0) { if (nobj_deltify > 0) { p_deltify = (nobj_deltify * 100) / nobj_total; if (p_deltify != a->last_p_deltify) { a->last_p_deltify = p_deltify; print_searching = 1; print_total = 1; print_deltify = 1; } } if (nobj_written > 0) { p_written = (nobj_written * 100) / nobj_total; if (p_written != a->last_p_written) { a->last_p_written = p_written; print_searching = 1; print_total = 1; print_deltify = 1; print_written = 1; } } } if (bytes_sent > 0) { p_sent = (bytes_sent * 100) / packfile_size; if (p_sent != a->last_p_sent) { a->last_p_sent = p_sent; print_searching = 1; print_total = 1; print_deltify = 1; print_written = 1; print_sent = 1; } a->sent_something = 1; } if (print_searching || print_total || print_deltify || print_written || print_sent) printf("\r"); if (print_searching) printf("packing %d reference%s", ncommits, ncommits == 1 ? "" : "s"); if (print_total) printf("; %d object%s", nobj_total, nobj_total == 1 ? "" : "s"); if (print_deltify) printf("; deltify: %d%%", p_deltify); if (print_sent) printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2, scaled_packsize, p_sent); else if (print_written) printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2, scaled_packsize, p_written); if (print_searching || print_total || print_deltify || print_written || print_sent) { a->printed_something = 1; fflush(stdout); } return NULL; } static const struct got_error * cmd_send(int argc, char *argv[]) { const struct got_error *error = NULL; char *cwd = NULL, *repo_path = NULL; const char *remote_name; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const struct got_remote_repo *remotes; struct got_remote_repo *remote = NULL; int nremotes, nbranches = 0, ndelete_branches = 0; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; struct got_pathlist_head branches; struct got_pathlist_head tags; struct got_reflist_head all_branches; struct got_reflist_head all_tags; struct got_pathlist_head delete_args; struct got_pathlist_head delete_branches; struct got_reflist_entry *re; struct got_pathlist_entry *pe; int i, ch, sendfd = -1, sendstatus; pid_t sendpid = -1; struct got_send_progress_arg spa; int verbosity = 0, overwrite_refs = 0; int send_all_branches = 0, send_all_tags = 0; struct got_reference *ref = NULL; int *pack_fds = NULL; const char *jumphost = NULL, *identity_file = NULL; RB_INIT(&branches); RB_INIT(&tags); TAILQ_INIT(&all_branches); TAILQ_INIT(&all_tags); RB_INIT(&delete_args); RB_INIT(&delete_branches); while ((ch = getopt(argc, argv, "ab:d:fi:J:qr:Tt:v")) != -1) { switch (ch) { case 'a': send_all_branches = 1; break; case 'b': error = got_pathlist_insert(NULL, &branches, optarg, NULL); if (error) return error; nbranches++; break; case 'd': error = got_pathlist_insert(NULL, &delete_args, optarg, NULL); if (error) return error; break; case 'f': overwrite_refs = 1; break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 'q': verbosity = -1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'T': send_all_tags = 1; break; case 't': error = got_pathlist_insert(NULL, &tags, optarg, NULL); if (error) return error; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_send(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (send_all_branches && !RB_EMPTY(&branches)) option_conflict('a', 'b'); if (send_all_tags && !RB_EMPTY(&tags)) option_conflict('T', 't'); if (argc == 0) remote_name = GOT_SEND_DEFAULT_REMOTE_NAME; else if (argc == 1) remote_name = argv[0]; else usage_send(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; if (worktree) { worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { error = got_repo_remote_repo_dup(&remote, &remotes[i]); if (error) goto done; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->send_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; if (send_all_branches) { error = got_ref_list(&all_branches, repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) goto done; TAILQ_FOREACH(re, &all_branches, entry) { const char *branchname = got_ref_get_name(re->ref); error = got_pathlist_insert(NULL, &branches, branchname, NULL); if (error) goto done; nbranches++; } } else if (nbranches == 0) { for (i = 0; i < remote->nsend_branches; i++) { error = got_pathlist_insert(NULL, &branches, remote->send_branches[i], NULL); if (error) goto done; } } if (send_all_tags) { error = got_ref_list(&all_tags, repo, "refs/tags", got_ref_cmp_by_name, NULL); if (error) goto done; TAILQ_FOREACH(re, &all_tags, entry) { const char *tagname = got_ref_get_name(re->ref); error = got_pathlist_insert(NULL, &tags, tagname, NULL); if (error) goto done; } } /* * To prevent accidents only branches in refs/heads/ can be deleted * with 'got send -d'. * Deleting anything else requires local repository access or Git. */ RB_FOREACH(pe, got_pathlist_head, &delete_args) { const char *branchname = pe->path; char *s; struct got_pathlist_entry *new; if (strncmp(branchname, "refs/heads/", 11) == 0) { s = strdup(branchname); if (s == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { if (asprintf(&s, "refs/heads/%s", branchname) == -1) { error = got_error_from_errno("asprintf"); goto done; } } error = got_pathlist_insert(&new, &delete_branches, s, NULL); if (error || new == NULL /* duplicate */) free(s); if (error) goto done; ndelete_branches++; } if (nbranches == 0 && ndelete_branches == 0) { struct got_reference *head_ref; if (worktree) error = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); else error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error) goto done; if (got_ref_is_symbolic(head_ref)) { error = got_ref_resolve_symbolic(&ref, repo, head_ref); got_ref_close(head_ref); if (error) goto done; } else ref = head_ref; error = got_pathlist_insert(NULL, &branches, got_ref_get_name(ref), NULL); if (error) goto done; nbranches++; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); } error = got_send_connect(&sendpid, &sendfd, proto, host, port, server_path, jumphost, identity_file, verbosity); if (error) goto done; memset(&spa, 0, sizeof(spa)); spa.last_scaled_packsize[0] = '\0'; spa.last_p_deltify = -1; spa.last_p_written = -1; spa.verbosity = verbosity; spa.delete_branches = &delete_branches; error = got_send_pack(remote_name, &branches, &tags, &delete_branches, verbosity, overwrite_refs, sendfd, repo, send_progress, &spa, check_cancelled, NULL); if (spa.printed_something) putchar('\n'); if (error) goto done; if (!spa.sent_something && verbosity >= 0) printf("Already up-to-date\n"); done: if (sendpid > 0) { if (kill(sendpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (sendfd != -1 && close(sendfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (ref) got_ref_close(ref); got_repo_free_remote_repo_data(remote); free(remote); got_pathlist_free(&branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&tags, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&all_branches); got_ref_list_free(&all_tags); got_pathlist_free(&delete_args, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&delete_branches, GOT_PATHLIST_FREE_PATH); free(cwd); free(repo_path); free(proto); free(host); free(port); free(server_path); free(repo_name); return error; } /* * Print and if delete is set delete all ref_prefix references. * If wanted_ref is not NULL, only print or delete this reference. */ static const struct got_error * process_logmsg_refs(const char *ref_prefix, size_t prefix_len, const char *wanted_ref, int delete, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_reflist_object_id_map *refs_idmap = NULL; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; const char *header_prefix; char *uuidstr = NULL; int found = 0; TAILQ_INIT(&refs); RB_INIT(&paths); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo); if (err) goto done; err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (err) goto done; if (worktree != NULL) { err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; } if (wanted_ref) { if (strncmp(wanted_ref, "refs/heads/", 11) == 0) wanted_ref += 11; } if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0) header_prefix = "backout"; else header_prefix = "cherrypick"; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *wt; refname = got_ref_get_name(re->ref); err = check_cancelled(NULL); if (err) goto done; if (strncmp(refname, ref_prefix, prefix_len) == 0) refname += prefix_len + 1; /* skip '-' delimiter */ else continue; wt = refname; if (worktree == NULL || strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; if (wanted_ref) found = strncmp(wanted_ref, refname, strlen(wanted_ref)) == 0; if (wanted_ref && !found) { struct got_reflist_head *ci_refs; ci_refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (ci_refs) { char *refs_str = NULL; char const *r = NULL; err = build_refs_str(&refs_str, ci_refs, id, repo, 1); if (err) goto done; r = refs_str; while (r) { if (strncmp(r, wanted_ref, strlen(wanted_ref)) == 0) { found = 1; break; } r = strchr(r, ' '); if (r) ++r; } free(refs_str); } } if (wanted_ref == NULL || found) { if (delete) { err = got_ref_delete(re->ref, repo); if (err) goto done; printf("Deleted: "); err = print_commit_oneline(commit, id, repo, refs_idmap); } else { /* * Print paths modified by commit to help * associate commits with worktree changes. */ err = get_changed_paths(&paths, commit, repo, NULL); if (err) goto done; err = print_commit(commit, id, repo, NULL, &paths, NULL, 0, 0, refs_idmap, NULL, header_prefix); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (worktree == NULL) printf("work tree: %.*s\n\n", GOT_WORKTREE_UUID_STRLEN, wt); } if (err || found) goto done; } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } if (wanted_ref != NULL && !found) err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref); done: free(id); free(uuidstr); got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (commit) got_object_commit_close(commit); return err; } /* * Create new temp "logmsg" ref of the backed-out or cherrypicked commit * identified by id for log messages to prepopulate the editor on commit. */ static const struct got_error * logmsg_ref(struct got_object_id *id, const char *prefix, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *idstr, *ref = NULL, *refname = NULL; int histedit_in_progress; int rebase_in_progress, merge_in_progress; /* * Silently refuse to create merge reference if any histedit, merge, * or rebase operation is in progress. */ err = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (err) return err; if (histedit_in_progress) return NULL; err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (err) return err; if (rebase_in_progress) return NULL; err = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (err) return err; if (merge_in_progress) return NULL; err = got_object_id_str(&idstr, id); if (err) return err; err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix); if (err) goto done; if (asprintf(&ref, "%s-%s", refname, idstr) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = create_ref(ref, got_worktree_get_base_commit_id(worktree), -1, repo); done: free(ref); free(idstr); free(refname); return err; } __dead static void usage_cherrypick(void) { fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_cherrypick(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL, *keyword_idstr = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_cherrypick(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_cherrypick(); } else if (argc != 1) usage_cherrypick(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "cherrypick", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_keyword_to_idstr(&keyword_idstr, argv[0], repo, worktree); if (error != NULL) goto done; error = got_repo_match_object_id(&commit_id, NULL, keyword_idstr != NULL ? keyword_idstr : argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL, commit_id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo); if (error) goto done; printf("Merged commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); free(keyword_idstr); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_backout(void) { fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_backout(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL, *keyword_idstr = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_backout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_backout(); } else if (argc != 1) usage_backout(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "backout", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_keyword_to_idstr(&keyword_idstr, argv[0], repo, worktree); if (error != NULL) goto done; error = got_repo_match_object_id(&commit_id, NULL, keyword_idstr != NULL ? keyword_idstr : argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid == NULL) { error = got_error(GOT_ERR_ROOT_COMMIT); goto done; } memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, commit_id, &pid->id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX, worktree, repo); if (error) goto done; printf("Backed out commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); free(keyword_idstr); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_rebase(void) { fprintf(stderr, "usage: %s rebase [-aCclX] [branch]\n", getprogname()); exit(1); } static void trim_logmsg(char *logmsg, int limit) { char *nl; size_t len; len = strlen(logmsg); if (len > limit) len = limit; logmsg[len] = '\0'; nl = strchr(logmsg, '\n'); if (nl) *nl = '\0'; } static const struct got_error * get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit) { const struct got_error *err; char *logmsg0 = NULL; const char *s; err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) return err; s = logmsg0; while (isspace((unsigned char)s[0])) s++; *logmsg = strdup(s); if (*logmsg == NULL) { err = got_error_from_errno("strdup"); goto done; } trim_logmsg(*logmsg, limit); done: free(logmsg0); return err; } static const struct got_error * show_rebase_merge_conflict(struct got_object_id *id, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit = NULL; char *id_str = NULL, *logmsg = NULL; err = got_object_open_as_commit(&commit, repo, id); if (err) return err; err = got_object_id_str(&id_str, id); if (err) goto done; id_str[12] = '\0'; err = get_short_logmsg(&logmsg, 42, commit); if (err) goto done; printf("%s -> merge conflict: %s\n", id_str, logmsg); done: free(id_str); got_object_commit_close(commit); free(logmsg); return err; } static const struct got_error * show_rebase_progress(struct got_commit_object *commit, struct got_object_id *old_id, struct got_object_id *new_id) { const struct got_error *err; char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL; err = got_object_id_str(&old_id_str, old_id); if (err) goto done; if (new_id) { err = got_object_id_str(&new_id_str, new_id); if (err) goto done; } old_id_str[12] = '\0'; if (new_id_str) new_id_str[12] = '\0'; err = get_short_logmsg(&logmsg, 42, commit); if (err) goto done; printf("%s -> %s: %s\n", old_id_str, new_id_str ? new_id_str : "no-op change", logmsg); done: free(old_id_str); free(new_id_str); free(logmsg); return err; } static const struct got_error * rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *branch, struct got_reference *tmp_branch, struct got_repository *repo, int create_backup) { printf("Switching work tree to %s\n", got_ref_get_name(branch)); return got_worktree_rebase_complete(worktree, fileindex, tmp_branch, branch, repo, create_backup); } static const struct got_error * rebase_commit(struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, const char *committer, struct got_object_id *commit_id, int allow_conflict, struct got_repository *repo) { const struct got_error *error; struct got_commit_object *commit; struct got_object_id *new_commit_id; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) return error; error = got_worktree_rebase_commit(&new_commit_id, merged_paths, worktree, fileindex, tmp_branch, committer, commit, commit_id, allow_conflict, repo); if (error) { if (error->code != GOT_ERR_COMMIT_NO_CHANGES) goto done; error = show_rebase_progress(commit, commit_id, NULL); } else { error = show_rebase_progress(commit, commit_id, new_commit_id); free(new_commit_id); } done: got_object_commit_close(commit); return error; } struct check_path_prefix_arg { const char *path_prefix; size_t len; int errcode; }; static const struct got_error * check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1, struct got_blob_object *blob2, FILE *f1, FILE *f2, struct got_object_id *id1, struct got_object_id *id2, const char *path1, const char *path2, mode_t mode1, mode_t mode2, struct got_repository *repo) { struct check_path_prefix_arg *a = arg; if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) || (path2 && !got_path_is_child(path2, a->path_prefix, a->len))) return got_error(a->errcode); return NULL; } static const struct got_error * check_path_prefix(struct got_object_id *parent_id, struct got_object_id *commit_id, const char *path_prefix, int errcode, struct got_repository *repo) { const struct got_error *err; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_commit_object *commit = NULL, *parent_commit = NULL; struct check_path_prefix_arg cpp_arg; if (got_path_is_root_dir(path_prefix)) return NULL; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; err = got_object_open_as_commit(&parent_commit, repo, parent_id); if (err) goto done; err = got_object_open_as_tree(&tree1, repo, got_object_commit_get_tree_id(parent_commit)); if (err) goto done; err = got_object_open_as_tree(&tree2, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; cpp_arg.path_prefix = path_prefix; while (cpp_arg.path_prefix[0] == '/') cpp_arg.path_prefix++; cpp_arg.len = strlen(cpp_arg.path_prefix); cpp_arg.errcode = errcode; err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo, check_path_prefix_in_diff, &cpp_arg, 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (commit) got_object_commit_close(commit); if (parent_commit) got_object_commit_close(parent_commit); return err; } static const struct got_error * collect_commits(struct got_object_id_queue *commits, struct got_object_id *initial_commit_id, struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id, const char *path_prefix, int path_prefix_errcode, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL; struct got_object_id parent_id, commit_id; struct got_object_qid *qid; err = got_commit_graph_open(&graph, "/", 1); if (err) return err; err = got_commit_graph_bfsort(graph, iter_start_id, repo, check_cancelled, NULL); if (err) goto done; memcpy(&commit_id, initial_commit_id, sizeof(commit_id)); while (got_object_id_cmp(&commit_id, iter_stop_id) != 0) { err = got_commit_graph_iter_next(&parent_id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) { err = got_error_msg(GOT_ERR_ANCESTRY, "ran out of commits to rebase before " "youngest common ancestor commit has " "been reached?!?"); } goto done; } else { err = check_path_prefix(&parent_id, &commit_id, path_prefix, path_prefix_errcode, repo); if (err) goto done; err = got_object_qid_alloc(&qid, &commit_id); if (err) goto done; STAILQ_INSERT_HEAD(commits, qid, entry); memcpy(&commit_id, &parent_id, sizeof(commit_id)); } } done: got_commit_graph_close(graph); return err; } static const struct got_error * get_commit_brief_str(char **brief_str, struct got_commit_object *commit) { const struct got_error *err = NULL; time_t committer_time; struct tm tm; char datebuf[11]; /* YYYY-MM-DD + NUL */ char *author0 = NULL, *author, *smallerthan; char *logmsg0 = NULL, *logmsg, *newline; committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(datebuf, sizeof(datebuf), "%F", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); author0 = strdup(got_object_commit_get_author(commit)); if (author0 == NULL) return got_error_from_errno("strdup"); author = author0; smallerthan = strchr(author, '<'); if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; while (*logmsg == '\n') logmsg++; newline = strchr(logmsg, '\n'); if (newline) *newline = '\0'; if (asprintf(brief_str, "%s %s %s", datebuf, author, logmsg) == -1) err = got_error_from_errno("asprintf"); done: free(author0); free(logmsg0); return err; } static const struct got_error * delete_backup_ref(struct got_reference *ref, struct got_object_id *id, struct got_repository *repo) { const struct got_error *err; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_delete(ref, repo); if (err) goto done; printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str); done: free(id_str); return err; } static const struct got_error * print_backup_ref(const char *branch_name, const char *new_id_str, struct got_object_id *old_commit_id, struct got_commit_object *old_commit, struct got_reflist_object_id_map *refs_idmap, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reflist_head *refs; char *refs_str = NULL; struct got_object_id *new_commit_id = NULL; struct got_commit_object *new_commit = NULL; char *new_commit_brief_str = NULL; struct got_object_id *yca_id = NULL; struct got_commit_object *yca_commit = NULL; char *yca_id_str = NULL, *yca_brief_str = NULL; char *custom_refs_str; if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1) return got_error_from_errno("asprintf"); err = print_commit(old_commit, old_commit_id, repo, NULL, NULL, NULL, 0, 0, refs_idmap, custom_refs_str, NULL); if (err) goto done; err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str); if (err) goto done; refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id); if (refs) { err = build_refs_str(&refs_str, refs, new_commit_id, repo, 0); if (err) goto done; } err = got_object_open_as_commit(&new_commit, repo, new_commit_id); if (err) goto done; err = get_commit_brief_str(&new_commit_brief_str, new_commit); if (err) goto done; err = got_commit_graph_find_youngest_common_ancestor(&yca_id, old_commit_id, new_commit_id, 1, 0, repo, check_cancelled, NULL); if (err) goto done; printf("has become commit %s%s%s%s\n %s\n", new_id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : "", new_commit_brief_str); if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 && got_object_id_cmp(yca_id, old_commit_id) != 0) { free(refs_str); refs_str = NULL; err = got_object_open_as_commit(&yca_commit, repo, yca_id); if (err) goto done; err = get_commit_brief_str(&yca_brief_str, yca_commit); if (err) goto done; err = got_object_id_str(&yca_id_str, yca_id); if (err) goto done; refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id); if (refs) { err = build_refs_str(&refs_str, refs, yca_id, repo, 0); if (err) goto done; } printf("history forked at %s%s%s%s\n %s\n", yca_id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : "", yca_brief_str); } done: free(custom_refs_str); free(new_commit_id); free(refs_str); free(yca_id); free(yca_id_str); free(yca_brief_str); if (new_commit) got_object_commit_close(new_commit); if (yca_commit) got_object_commit_close(yca_commit); return err; } static const struct got_error * worktree_has_logmsg_ref(const char *caller, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_reflist_head refs; struct got_reflist_entry *re; char *uuidstr = NULL; static char msg[160]; TAILQ_INIT(&refs); err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *cmd, *refname, *type; refname = got_ref_get_name(re->ref); if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; cmd = "cherrypick"; type = "cherrypicked"; } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; cmd = "backout"; type = "backed-out"; } else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) != 0) continue; snprintf(msg, sizeof(msg), "work tree has references created by %s commits which " "must be removed with 'got %s -X' before running the %s " "command", type, cmd, caller); err = got_error_msg(GOT_ERR_WORKTREE_META, msg); goto done; } done: free(uuidstr); got_ref_list_free(&refs); return err; } static const struct got_error * process_backup_refs(const char *backup_ref_prefix, const char *wanted_branch_name, int delete, struct got_repository *repo) { const struct got_error *err; struct got_reflist_head refs, backup_refs; struct got_reflist_entry *re; const size_t backup_ref_prefix_len = strlen(backup_ref_prefix); struct got_object_id *old_commit_id = NULL; char *branch_name = NULL; struct got_commit_object *old_commit = NULL; struct got_reflist_object_id_map *refs_idmap = NULL; int wanted_branch_found = 0; TAILQ_INIT(&refs); TAILQ_INIT(&backup_refs); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) return err; err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (err) goto done; if (wanted_branch_name) { if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0) wanted_branch_name += 11; } err = got_ref_list(&backup_refs, repo, backup_ref_prefix, got_ref_cmp_by_commit_timestamp_descending, repo); if (err) goto done; TAILQ_FOREACH(re, &backup_refs, entry) { const char *refname = got_ref_get_name(re->ref); char *slash; err = check_cancelled(NULL); if (err) break; err = got_ref_resolve(&old_commit_id, repo, re->ref); if (err) break; err = got_object_open_as_commit(&old_commit, repo, old_commit_id); if (err) break; if (strncmp(backup_ref_prefix, refname, backup_ref_prefix_len) == 0) refname += backup_ref_prefix_len; while (refname[0] == '/') refname++; branch_name = strdup(refname); if (branch_name == NULL) { err = got_error_from_errno("strdup"); break; } slash = strrchr(branch_name, '/'); if (slash) { *slash = '\0'; refname += strlen(branch_name) + 1; } if (wanted_branch_name == NULL || strcmp(wanted_branch_name, branch_name) == 0) { wanted_branch_found = 1; if (delete) { err = delete_backup_ref(re->ref, old_commit_id, repo); } else { err = print_backup_ref(branch_name, refname, old_commit_id, old_commit, refs_idmap, repo); } if (err) break; } free(old_commit_id); old_commit_id = NULL; free(branch_name); branch_name = NULL; got_object_commit_close(old_commit); old_commit = NULL; } if (wanted_branch_name && !wanted_branch_found) { err = got_error_fmt(GOT_ERR_NOT_REF, "%s/%s/", backup_ref_prefix, wanted_branch_name); } done: if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); got_ref_list_free(&refs); got_ref_list_free(&backup_refs); free(old_commit_id); free(branch_name); if (old_commit) got_object_commit_close(old_commit); return err; } static const struct got_error * abort_progress(void *arg, unsigned char status, const char *path) { /* * Unversioned files should not clutter progress output when * an operation is aborted. */ if (status == GOT_STATUS_UNVERSIONED) return NULL; return update_progress(arg, status, path); } static const struct got_error * find_merge_commit_yca(struct got_object_id **new_yca_id, struct got_object_id *branch_head_commit_id, struct got_object_id *yca_id, struct got_object_id *base_commit_id, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL; struct got_commit_object *commit = NULL; *new_yca_id = NULL; err = got_commit_graph_open(&graph, "/", 1); if (err) return err; err = got_commit_graph_bfsort(graph, base_commit_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if (got_object_commit_get_nparents(commit) > 1) { /* Search for a better YCA using toposort. */ err = got_commit_graph_find_youngest_common_ancestor( new_yca_id, base_commit_id, branch_head_commit_id, 0, 1, repo, check_cancelled, NULL); break; } if (got_object_id_cmp(&id, yca_id) == 0) break; got_object_commit_close(commit); commit = NULL; } done: got_commit_graph_close(graph); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * cmd_rebase(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; struct got_fileindex *fileindex = NULL; char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL; struct got_reference *branch = NULL; struct got_reference *new_base_branch = NULL, *tmp_branch = NULL; struct got_object_id *commit_id = NULL, *parent_id = NULL; struct got_object_id *resume_commit_id = NULL; struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL; struct got_object_id *head_commit_id = NULL; struct got_reference *head_ref = NULL; struct got_commit_object *commit = NULL; int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0; int histedit_in_progress = 0, merge_in_progress = 0; int create_backup = 1, list_backups = 0, delete_backups = 0; int allow_conflict = 0; struct got_object_id_queue commits; struct got_pathlist_head merged_paths; const struct got_object_id_queue *parent_ids; struct got_object_qid *qid, *pid; struct got_update_progress_arg upa; int *pack_fds = NULL; STAILQ_INIT(&commits); RB_INIT(&merged_paths); memset(&upa, 0, sizeof(upa)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aCclX")) != -1) { switch (ch) { case 'a': abort_rebase = 1; break; case 'C': allow_conflict = 1; break; case 'c': continue_rebase = 1; break; case 'l': list_backups = 1; break; case 'X': delete_backups = 1; break; default: usage_rebase(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_backups) { if (abort_rebase) option_conflict('l', 'a'); if (allow_conflict) option_conflict('l', 'C'); if (continue_rebase) option_conflict('l', 'c'); if (delete_backups) option_conflict('l', 'X'); if (argc != 0 && argc != 1) usage_rebase(); } else if (delete_backups) { if (abort_rebase) option_conflict('X', 'a'); if (allow_conflict) option_conflict('X', 'C'); if (continue_rebase) option_conflict('X', 'c'); if (list_backups) option_conflict('l', 'X'); if (argc != 0 && argc != 1) usage_rebase(); } else if (allow_conflict) { if (abort_rebase) option_conflict('C', 'a'); if (!continue_rebase) errx(1, "-C option requires -c"); } else { if (abort_rebase && continue_rebase) usage_rebase(); else if (abort_rebase || continue_rebase) { if (argc != 0) usage_rebase(); } else if (argc != 1) usage_rebase(); } cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (list_backups || delete_backups) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "rebase", cwd); goto done; } } error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, gitconfig_path, pack_fds); if (error != NULL) goto done; if (worktree != NULL && !list_backups && !delete_backups) { error = worktree_has_logmsg_ref("rebase", worktree, repo); if (error) goto done; } error = get_author(&committer, repo, worktree); if (error && error->code != GOT_ERR_COMMIT_NO_AUTHOR) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_backups || delete_backups) { error = process_backup_refs( GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX, argc == 1 ? argv[0] : NULL, delete_backups, repo); goto done; /* nothing else to do */ } error = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (error) goto done; if (histedit_in_progress) { error = got_error(GOT_ERR_HISTEDIT_BUSY); goto done; } error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (error) goto done; if (abort_rebase) { if (!rebase_in_progress) { error = got_error(GOT_ERR_NOT_REBASING); goto done; } error = got_worktree_rebase_continue(&resume_commit_id, &new_base_branch, &tmp_branch, &branch, &fileindex, worktree, repo); if (error) goto done; printf("Switching work tree to %s\n", got_ref_get_symref_target(new_base_branch)); error = got_worktree_rebase_abort(worktree, fileindex, repo, new_base_branch, abort_progress, &upa); if (error) goto done; printf("Rebase of %s aborted\n", got_ref_get_name(branch)); print_merge_progress_stats(&upa); goto done; /* nothing else to do */ } if (continue_rebase) { if (!rebase_in_progress) { error = got_error(GOT_ERR_NOT_REBASING); goto done; } error = got_worktree_rebase_continue(&resume_commit_id, &new_base_branch, &tmp_branch, &branch, &fileindex, worktree, repo); if (error) goto done; error = rebase_commit(NULL, worktree, fileindex, tmp_branch, committer, resume_commit_id, allow_conflict, repo); if (error) goto done; yca_id = got_object_id_dup(resume_commit_id); if (yca_id == NULL) { error = got_error_from_errno("got_object_id_dup"); goto done; } } else { error = got_ref_open(&branch, repo, argv[0], 0); if (error != NULL) goto done; if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) { error = got_error_msg(GOT_ERR_COMMIT_BRANCH, "will not rebase a branch which lives outside " "the \"refs/heads/\" reference namespace"); goto done; } } error = got_ref_resolve(&branch_head_commit_id, repo, branch); if (error) goto done; if (!continue_rebase) { struct got_object_id *base_commit_id; error = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (error) goto done; error = got_ref_resolve(&head_commit_id, repo, head_ref); if (error) goto done; base_commit_id = got_worktree_get_base_commit_id(worktree); if (got_object_id_cmp(base_commit_id, head_commit_id) != 0) { error = got_error(GOT_ERR_REBASE_OUT_OF_DATE); goto done; } error = got_commit_graph_find_youngest_common_ancestor(&yca_id, base_commit_id, branch_head_commit_id, 1, 0, repo, check_cancelled, NULL); if (error) { if (error->code == GOT_ERR_ANCESTRY) { error = got_error_msg(GOT_ERR_ANCESTRY, "specified branch shares no common " "ancestry with work tree's branch"); } goto done; } /* * If a merge commit appears between the new base branch tip * and a YCA found via first-parent traversal then we might * find a better YCA using topologically sorted commits. */ if (got_object_id_cmp(base_commit_id, yca_id) != 0) { struct got_object_id *better_yca_id; error = find_merge_commit_yca(&better_yca_id, branch_head_commit_id, yca_id, base_commit_id, repo); if (error) goto done; if (better_yca_id) { free(yca_id); yca_id = better_yca_id; } } if (got_object_id_cmp(base_commit_id, yca_id) == 0) { struct got_pathlist_head paths; const char *branch_name = got_ref_get_name(branch); const char *base = got_worktree_get_head_ref_name(worktree); if (strcmp(branch_name, base) == 0) { error = got_error_fmt(GOT_ERR_WRONG_BRANCH, "cannot rebase %s onto itself", branch_name); goto done; } else { printf("%s is already based on %s\n", branch_name, base); } error = switch_head_ref(branch, branch_head_commit_id, worktree, repo); if (error) goto done; error = got_worktree_set_base_commit_id(worktree, repo, branch_head_commit_id); if (error) goto done; RB_INIT(&paths); error = got_pathlist_insert(NULL, &paths, "", NULL); if (error) goto done; error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); if (error) goto done; if (upa.did_something) { char *id_str; error = got_object_id_str(&id_str, branch_head_commit_id); if (error) goto done; printf("Updated to %s: %s\n", got_worktree_get_head_ref_name(worktree), id_str); free(id_str); } else printf("Already up-to-date\n"); print_update_progress_stats(&upa); goto done; } } commit_id = branch_head_commit_id; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; parent_ids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(parent_ids); if (pid) { error = collect_commits(&commits, commit_id, &pid->id, yca_id, got_worktree_get_path_prefix(worktree), GOT_ERR_REBASE_PATH, repo); if (error) goto done; } got_object_commit_close(commit); commit = NULL; if (!continue_rebase) { error = got_worktree_rebase_prepare(&new_base_branch, &tmp_branch, &fileindex, worktree, branch, repo); if (error) goto done; } if (STAILQ_EMPTY(&commits)) { if (continue_rebase) { error = rebase_complete(worktree, fileindex, branch, tmp_branch, repo, create_backup); goto done; } else { /* Fast-forward the reference of the branch. */ struct got_object_id *new_head_commit_id; char *id_str; error = got_ref_resolve(&new_head_commit_id, repo, new_base_branch); if (error) goto done; error = got_object_id_str(&id_str, new_head_commit_id); if (error) goto done; printf("Forwarding %s to commit %s\n", got_ref_get_name(branch), id_str); free(id_str); error = got_ref_change_ref(branch, new_head_commit_id); if (error) goto done; /* No backup needed since objects did not change. */ create_backup = 0; } } pid = NULL; STAILQ_FOREACH(qid, &commits, entry) { commit_id = &qid->id; parent_id = pid ? &pid->id : yca_id; pid = qid; memset(&upa, 0, sizeof(upa)); error = got_worktree_rebase_merge_files(&merged_paths, worktree, fileindex, parent_id, commit_id, repo, update_progress, &upa, check_cancelled, NULL); if (error) goto done; print_merge_progress_stats(&upa); if (upa.conflicts > 0 || upa.missing > 0 || upa.not_deleted > 0 || upa.unversioned > 0) { if (upa.conflicts > 0) { error = show_rebase_merge_conflict(&qid->id, repo); if (error) goto done; } got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH); break; } error = rebase_commit(&merged_paths, worktree, fileindex, tmp_branch, committer, commit_id, 0, repo); got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH); if (error) goto done; } if (upa.conflicts > 0 || upa.missing > 0 || upa.not_deleted > 0 || upa.unversioned > 0) { error = got_worktree_rebase_postpone(worktree, fileindex); if (error) goto done; if (upa.conflicts > 0 && upa.missing == 0 && upa.not_deleted == 0 && upa.unversioned == 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before rebasing " "can continue"); } else if (upa.conflicts > 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before rebasing " "can continue; changes destined for some " "files were not yet merged and should be " "merged manually if required before the " "rebase operation is continued"); } else { error = got_error_msg(GOT_ERR_CONFLICTS, "changes destined for some files were not " "yet merged and should be merged manually " "if required before the rebase operation " "is continued"); } } else error = rebase_complete(worktree, fileindex, branch, tmp_branch, repo, create_backup); done: free(cwd); free(committer); free(gitconfig_path); got_object_id_queue_free(&commits); free(branch_head_commit_id); free(resume_commit_id); free(head_commit_id); free(yca_id); if (commit) got_object_commit_close(commit); if (branch) got_ref_close(branch); if (new_base_branch) got_ref_close(new_base_branch); if (tmp_branch) got_ref_close(tmp_branch); if (head_ref) got_ref_close(head_ref); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_histedit(void) { fprintf(stderr, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] " "[branch]\n", getprogname()); exit(1); } #define GOT_HISTEDIT_PICK 'p' #define GOT_HISTEDIT_EDIT 'e' #define GOT_HISTEDIT_FOLD 'f' #define GOT_HISTEDIT_DROP 'd' #define GOT_HISTEDIT_MESG 'm' static const struct got_histedit_cmd { unsigned char code; const char *name; const char *desc; } got_histedit_cmds[] = { { GOT_HISTEDIT_PICK, "pick", "use commit" }, { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" }, { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will " "be used" }, { GOT_HISTEDIT_DROP, "drop", "remove commit from history" }, { GOT_HISTEDIT_MESG, "mesg", "open editor to edit the log message" }, }; struct got_histedit_list_entry { TAILQ_ENTRY(got_histedit_list_entry) entry; struct got_object_id *commit_id; const struct got_histedit_cmd *cmd; char *logmsg; }; TAILQ_HEAD(got_histedit_list, got_histedit_list_entry); static const struct got_error * histedit_write_commit(struct got_object_id *commit_id, const char *cmdname, FILE *f, struct got_repository *repo) { const struct got_error *err = NULL; char *logmsg = NULL, *id_str = NULL; struct got_commit_object *commit = NULL; int n; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; err = get_short_logmsg(&logmsg, 34, commit); if (err) goto done; err = got_object_id_str(&id_str, commit_id); if (err) goto done; n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg); if (n < 0) err = got_ferror(f, GOT_ERR_IO); done: if (commit) got_object_commit_close(commit); free(id_str); free(logmsg); return err; } static const struct got_error * histedit_write_commit_list(struct got_object_id_queue *commits, FILE *f, int edit_logmsg_only, int fold_only, int drop_only, int edit_only, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_qid *qid; const char *histedit_cmd = NULL; if (STAILQ_EMPTY(commits)) return got_error(GOT_ERR_EMPTY_HISTEDIT); STAILQ_FOREACH(qid, commits, entry) { histedit_cmd = got_histedit_cmds[0].name; if (drop_only) histedit_cmd = "drop"; else if (edit_only) histedit_cmd = "edit"; else if (fold_only && STAILQ_NEXT(qid, entry) != NULL) histedit_cmd = "fold"; else if (edit_logmsg_only) histedit_cmd = "mesg"; err = histedit_write_commit(&qid->id, histedit_cmd, f, repo); if (err) break; } return err; } static const struct got_error * write_cmd_list(FILE *f, const char *branch_name, struct got_object_id_queue *commits) { const struct got_error *err = NULL; size_t i; int n; char *id_str; struct got_object_qid *qid; qid = STAILQ_FIRST(commits); err = got_object_id_str(&id_str, &qid->id); if (err) return err; n = fprintf(f, "# Editing the history of branch '%s' starting at\n" "# commit %s\n" "# Commits will be processed in order from top to " "bottom of this file.\n", branch_name, id_str); if (n < 0) { err = got_ferror(f, GOT_ERR_IO); goto done; } n = fprintf(f, "# Available histedit commands:\n"); if (n < 0) { err = got_ferror(f, GOT_ERR_IO); goto done; } for (i = 0; i < nitems(got_histedit_cmds); i++) { const struct got_histedit_cmd *cmd = &got_histedit_cmds[i]; n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code, cmd->desc); if (n < 0) { err = got_ferror(f, GOT_ERR_IO); break; } } done: free(id_str); return err; } static const struct got_error * histedit_syntax_error(int lineno) { static char msg[42]; int ret; ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d", lineno); if (ret < 0 || (size_t)ret >= sizeof(msg)) return got_error(GOT_ERR_HISTEDIT_SYNTAX); return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg); } static const struct got_error * append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle, char *logmsg, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *folded_commit = NULL; char *id_str, *folded_logmsg = NULL; err = got_object_id_str(&id_str, hle->commit_id); if (err) return err; err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id); if (err) goto done; err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit); if (err) goto done; if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s", logmsg ? logmsg : "", logmsg ? "\n" : "", id_str, folded_logmsg) == -1) { err = got_error_from_errno("asprintf"); } done: if (folded_commit) got_object_commit_close(folded_commit); free(id_str); free(folded_logmsg); return err; } static struct got_histedit_list_entry * get_folded_commits(struct got_histedit_list_entry *hle) { struct got_histedit_list_entry *prev, *folded = NULL; prev = TAILQ_PREV(hle, got_histedit_list, entry); while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD || prev->cmd->code == GOT_HISTEDIT_DROP)) { if (prev->cmd->code == GOT_HISTEDIT_FOLD) folded = prev; prev = TAILQ_PREV(prev, got_histedit_list, entry); } return folded; } static const struct got_error * histedit_edit_logmsg(struct got_histedit_list_entry *hle, const char *editor, struct got_repository *repo) { char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL; char *logmsg = NULL, *new_msg = NULL; const struct got_error *err = NULL; struct got_commit_object *commit = NULL; int logmsg_len; int fd = -1; struct got_histedit_list_entry *folded = NULL; err = got_object_open_as_commit(&commit, repo, hle->commit_id); if (err) return err; folded = get_folded_commits(hle); if (folded) { while (folded != hle) { if (folded->cmd->code == GOT_HISTEDIT_DROP) { folded = TAILQ_NEXT(folded, entry); continue; } err = append_folded_commit_msg(&new_msg, folded, logmsg, repo); if (err) goto done; free(logmsg); logmsg = new_msg; folded = TAILQ_NEXT(folded, entry); } } err = got_object_id_str(&id_str, hle->commit_id); if (err) goto done; err = got_object_commit_get_logmsg(&orig_logmsg, commit); if (err) goto done; logmsg_len = asprintf(&new_msg, "%s\n# original log message of commit %s: %s", logmsg ? logmsg : "", id_str, orig_logmsg); if (logmsg_len == -1) { err = got_error_from_errno("asprintf"); goto done; } free(logmsg); logmsg = new_msg; err = got_object_id_str(&id_str, hle->commit_id); if (err) goto done; err = got_opentemp_named_fd(&logmsg_path, &fd, GOT_TMPDIR_STR "/got-logmsg", ""); if (err) goto done; if (write(fd, logmsg, logmsg_len) == -1) { err = got_error_from_errno2("write", logmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", logmsg_path); goto done; } fd = -1; err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg, logmsg_len, 0); if (err) { if (err->code != GOT_ERR_COMMIT_MSG_EMPTY) goto done; err = NULL; hle->logmsg = strdup(new_msg); if (hle->logmsg == NULL) err = got_error_from_errno("strdup"); } done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", logmsg_path); if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL) err = got_error_from_errno2("unlink", logmsg_path); free(logmsg_path); free(logmsg); free(orig_logmsg); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * histedit_parse_list(struct got_histedit_list *histedit_cmds, FILE *f, struct got_repository *repo) { const struct got_error *err = NULL; char *line = NULL, *p, *end; size_t i, linesize = 0; ssize_t linelen; int lineno = 0; const struct got_histedit_cmd *cmd; struct got_object_id *commit_id = NULL; struct got_histedit_list_entry *hle = NULL; for (;;) { linelen = getline(&line, &linesize, f); if (linelen == -1) { const struct got_error *getline_err; if (feof(f)) break; getline_err = got_error_from_errno("getline"); err = got_ferror(f, getline_err->code); break; } lineno++; p = line; while (isspace((unsigned char)p[0])) p++; if (p[0] == '#' || p[0] == '\0') continue; cmd = NULL; for (i = 0; i < nitems(got_histedit_cmds); i++) { cmd = &got_histedit_cmds[i]; if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 && isspace((unsigned char)p[strlen(cmd->name)])) { p += strlen(cmd->name); break; } if (p[0] == cmd->code && isspace((unsigned char)p[1])) { p++; break; } } if (i == nitems(got_histedit_cmds)) { err = histedit_syntax_error(lineno); break; } while (isspace((unsigned char)p[0])) p++; end = p; while (end[0] && !isspace((unsigned char)end[0])) end++; *end = '\0'; err = got_object_resolve_id_str(&commit_id, repo, p); if (err) { /* override error code */ err = histedit_syntax_error(lineno); break; } hle = malloc(sizeof(*hle)); if (hle == NULL) { err = got_error_from_errno("malloc"); break; } hle->cmd = cmd; hle->commit_id = commit_id; hle->logmsg = NULL; commit_id = NULL; TAILQ_INSERT_TAIL(histedit_cmds, hle, entry); } free(line); free(commit_id); return err; } static const struct got_error * histedit_check_script(struct got_histedit_list *histedit_cmds, struct got_object_id_queue *commits, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_qid *qid; struct got_histedit_list_entry *hle; static char msg[128]; char *id_str; if (TAILQ_EMPTY(histedit_cmds)) return got_error_msg(GOT_ERR_EMPTY_HISTEDIT, "histedit script contains no commands"); if (STAILQ_EMPTY(commits)) return got_error(GOT_ERR_EMPTY_HISTEDIT); TAILQ_FOREACH(hle, histedit_cmds, entry) { struct got_histedit_list_entry *hle2; TAILQ_FOREACH(hle2, histedit_cmds, entry) { if (hle == hle2) continue; if (got_object_id_cmp(hle->commit_id, hle2->commit_id) != 0) continue; err = got_object_id_str(&id_str, hle->commit_id); if (err) return err; snprintf(msg, sizeof(msg), "commit %s is listed " "more than once in histedit script", id_str); free(id_str); return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg); } } STAILQ_FOREACH(qid, commits, entry) { TAILQ_FOREACH(hle, histedit_cmds, entry) { if (got_object_id_cmp(&qid->id, hle->commit_id) == 0) break; } if (hle == NULL) { err = got_object_id_str(&id_str, &qid->id); if (err) return err; snprintf(msg, sizeof(msg), "commit %s missing from histedit script", id_str); free(id_str); return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg); } } hle = TAILQ_LAST(histedit_cmds, got_histedit_list); if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD) return got_error_msg(GOT_ERR_HISTEDIT_CMD, "last commit in histedit script cannot be folded"); return NULL; } static const struct got_error * histedit_run_editor(struct got_histedit_list *histedit_cmds, const char *editor, const char *path, struct got_object_id_queue *commits, struct got_repository *repo) { const struct got_error *err = NULL; struct stat st, st2; struct timespec timeout; FILE *f = NULL; if (stat(path, &st) == -1) { err = got_error_from_errno2("stat", path); goto done; } if (spawn_editor(editor, path) == -1) { err = got_error_from_errno("failed spawning editor"); goto done; } timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); if (stat(path, &st2) == -1) { err = got_error_from_errno2("stat", path); goto done; } if (st.st_size == st2.st_size && timespeccmp(&st.st_mtim, &st2.st_mtim, ==)) { err = got_error_msg(GOT_ERR_EMPTY_HISTEDIT, "no changes made to histedit script, aborting"); goto done; } f = fopen(path, "re"); if (f == NULL) { err = got_error_from_errno("fopen"); goto done; } err = histedit_parse_list(histedit_cmds, f, repo); if (err) goto done; err = histedit_check_script(histedit_cmds, commits, repo); done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *, struct got_object_id_queue *, const char *, const char *, const char *, struct got_repository *); static const struct got_error * histedit_edit_script(struct got_histedit_list *histedit_cmds, struct got_object_id_queue *commits, const char *branch_name, int edit_logmsg_only, int fold_only, int drop_only, int edit_only, const char *editor, struct got_repository *repo) { const struct got_error *err; FILE *f = NULL; char *path = NULL; err = got_opentemp_named(&path, &f, "got-histedit", ""); if (err) return err; err = write_cmd_list(f, branch_name, commits); if (err) goto done; err = histedit_write_commit_list(commits, f, edit_logmsg_only, fold_only, drop_only, edit_only, repo); if (err) goto done; if (drop_only || edit_logmsg_only || fold_only || edit_only) { rewind(f); err = histedit_parse_list(histedit_cmds, f, repo); } else { if (fclose(f) == EOF) { err = got_error_from_errno("fclose"); goto done; } f = NULL; err = histedit_run_editor(histedit_cmds, editor, path, commits, repo); if (err) { if (err->code != GOT_ERR_HISTEDIT_SYNTAX && err->code != GOT_ERR_HISTEDIT_CMD) goto done; err = histedit_edit_list_retry(histedit_cmds, err, commits, editor, path, branch_name, repo); } } done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (path && unlink(path) != 0 && err == NULL) err = got_error_from_errno2("unlink", path); free(path); return err; } static const struct got_error * histedit_save_list(struct got_histedit_list *histedit_cmds, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *path = NULL; FILE *f = NULL; struct got_histedit_list_entry *hle; err = got_worktree_get_histedit_script_path(&path, worktree); if (err) return err; f = fopen(path, "we"); if (f == NULL) { err = got_error_from_errno2("fopen", path); goto done; } TAILQ_FOREACH(hle, histedit_cmds, entry) { err = histedit_write_commit(hle->commit_id, hle->cmd->name, f, repo); if (err) break; } done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(path); return err; } static void histedit_free_list(struct got_histedit_list *histedit_cmds) { struct got_histedit_list_entry *hle; while ((hle = TAILQ_FIRST(histedit_cmds))) { TAILQ_REMOVE(histedit_cmds, hle, entry); free(hle); } } static const struct got_error * histedit_load_list(struct got_histedit_list *histedit_cmds, const char *path, struct got_repository *repo) { const struct got_error *err = NULL; FILE *f = NULL; f = fopen(path, "re"); if (f == NULL) { err = got_error_from_errno2("fopen", path); goto done; } err = histedit_parse_list(histedit_cmds, f, repo); done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * histedit_edit_list_retry(struct got_histedit_list *histedit_cmds, const struct got_error *edit_err, struct got_object_id_queue *commits, const char *editor, const char *path, const char *branch_name, struct got_repository *repo) { const struct got_error *err = NULL, *prev_err = edit_err; int resp = ' '; while (resp != 'c' && resp != 'r' && resp != 'a') { printf("%s: %s\n(c)ontinue editing, (r)estart editing, " "or (a)bort: ", getprogname(), prev_err->msg); resp = getchar(); if (resp == '\n') resp = getchar(); if (resp == 'c') { histedit_free_list(histedit_cmds); err = histedit_run_editor(histedit_cmds, editor, path, commits, repo); if (err) { if (err->code != GOT_ERR_HISTEDIT_SYNTAX && err->code != GOT_ERR_HISTEDIT_CMD) break; prev_err = err; resp = ' '; continue; } break; } else if (resp == 'r') { histedit_free_list(histedit_cmds); err = histedit_edit_script(histedit_cmds, commits, branch_name, 0, 0, 0, 0, editor, repo); if (err) { if (err->code != GOT_ERR_HISTEDIT_SYNTAX && err->code != GOT_ERR_HISTEDIT_CMD) break; prev_err = err; resp = ' '; continue; } break; } else if (resp == 'a') { err = got_error(GOT_ERR_HISTEDIT_CANCEL); break; } else printf("invalid response '%c'\n", resp); } return err; } static const struct got_error * histedit_complete(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, struct got_reference *branch, struct got_repository *repo) { printf("Switching work tree to %s\n", got_ref_get_symref_target(branch)); return got_worktree_histedit_complete(worktree, fileindex, tmp_branch, branch, repo); } static const struct got_error * show_histedit_progress(struct got_commit_object *commit, struct got_histedit_list_entry *hle, struct got_object_id *new_id) { const struct got_error *err; char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL; err = got_object_id_str(&old_id_str, hle->commit_id); if (err) goto done; if (new_id) { err = got_object_id_str(&new_id_str, new_id); if (err) goto done; } old_id_str[12] = '\0'; if (new_id_str) new_id_str[12] = '\0'; if (hle->logmsg) { logmsg = strdup(hle->logmsg); if (logmsg == NULL) { err = got_error_from_errno("strdup"); goto done; } trim_logmsg(logmsg, 42); } else { err = get_short_logmsg(&logmsg, 42, commit); if (err) goto done; } switch (hle->cmd->code) { case GOT_HISTEDIT_PICK: case GOT_HISTEDIT_EDIT: case GOT_HISTEDIT_MESG: printf("%s -> %s: %s\n", old_id_str, new_id_str ? new_id_str : "no-op change", logmsg); break; case GOT_HISTEDIT_DROP: case GOT_HISTEDIT_FOLD: printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name, logmsg); break; default: break; } done: free(old_id_str); free(new_id_str); return err; } static const struct got_error * histedit_commit(struct got_pathlist_head *merged_paths, struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_reference *tmp_branch, struct got_histedit_list_entry *hle, const char *committer, int allow_conflict, const char *editor, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit; struct got_object_id *new_commit_id; if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle)) && hle->logmsg == NULL) { err = histedit_edit_logmsg(hle, editor, repo); if (err) return err; } err = got_object_open_as_commit(&commit, repo, hle->commit_id); if (err) return err; err = got_worktree_histedit_commit(&new_commit_id, merged_paths, worktree, fileindex, tmp_branch, committer, commit, hle->commit_id, hle->logmsg, allow_conflict, repo); if (err) { if (err->code != GOT_ERR_COMMIT_NO_CHANGES) goto done; err = show_histedit_progress(commit, hle, NULL); } else { err = show_histedit_progress(commit, hle, new_commit_id); free(new_commit_id); } done: got_object_commit_close(commit); return err; } static const struct got_error * histedit_skip_commit(struct got_histedit_list_entry *hle, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *error; struct got_commit_object *commit; error = got_worktree_histedit_skip_commit(worktree, hle->commit_id, repo); if (error) return error; error = got_object_open_as_commit(&commit, repo, hle->commit_id); if (error) return error; error = show_histedit_progress(commit, hle, NULL); got_object_commit_close(commit); return error; } static const struct got_error * check_local_changes(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { int *have_local_changes = arg; switch (status) { case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_MODIFY: case GOT_STATUS_CONFLICT: *have_local_changes = 1; return got_error(GOT_ERR_CANCELLED); default: break; } switch (staged_status) { case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_MODIFY: *have_local_changes = 1; return got_error(GOT_ERR_CANCELLED); default: break; } return NULL; } static const struct got_error * cmd_histedit(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_fileindex *fileindex = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL; struct got_reference *branch = NULL; struct got_reference *tmp_branch = NULL; struct got_object_id *resume_commit_id = NULL; struct got_object_id *base_commit_id = NULL; struct got_object_id *head_commit_id = NULL; struct got_commit_object *commit = NULL; int ch, rebase_in_progress = 0, merge_in_progress = 0; struct got_update_progress_arg upa; int edit_in_progress = 0, abort_edit = 0, continue_edit = 0; int drop_only = 0, edit_logmsg_only = 0, fold_only = 0, edit_only = 0; int allow_conflict = 0, list_backups = 0, delete_backups = 0; const char *edit_script_path = NULL; char *editor = NULL; struct got_object_id_queue commits; struct got_pathlist_head merged_paths; const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; struct got_histedit_list histedit_cmds; struct got_histedit_list_entry *hle; int *pack_fds = NULL; STAILQ_INIT(&commits); TAILQ_INIT(&histedit_cmds); RB_INIT(&merged_paths); memset(&upa, 0, sizeof(upa)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aCcdeF:flmX")) != -1) { switch (ch) { case 'a': abort_edit = 1; break; case 'C': allow_conflict = 1; break; case 'c': continue_edit = 1; break; case 'd': drop_only = 1; break; case 'e': edit_only = 1; break; case 'F': edit_script_path = optarg; break; case 'f': fold_only = 1; break; case 'l': list_backups = 1; break; case 'm': edit_logmsg_only = 1; break; case 'X': delete_backups = 1; break; default: usage_histedit(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (abort_edit && allow_conflict) option_conflict('a', 'C'); if (abort_edit && continue_edit) option_conflict('a', 'c'); if (edit_script_path && allow_conflict) option_conflict('F', 'C'); if (edit_script_path && edit_logmsg_only) option_conflict('F', 'm'); if (abort_edit && edit_logmsg_only) option_conflict('a', 'm'); if (edit_logmsg_only && allow_conflict) option_conflict('m', 'C'); if (continue_edit && edit_logmsg_only) option_conflict('c', 'm'); if (abort_edit && fold_only) option_conflict('a', 'f'); if (fold_only && allow_conflict) option_conflict('f', 'C'); if (continue_edit && fold_only) option_conflict('c', 'f'); if (fold_only && edit_logmsg_only) option_conflict('f', 'm'); if (edit_script_path && fold_only) option_conflict('F', 'f'); if (abort_edit && edit_only) option_conflict('a', 'e'); if (continue_edit && edit_only) option_conflict('c', 'e'); if (edit_only && edit_logmsg_only) option_conflict('e', 'm'); if (edit_script_path && edit_only) option_conflict('F', 'e'); if (fold_only && edit_only) option_conflict('f', 'e'); if (drop_only && abort_edit) option_conflict('d', 'a'); if (drop_only && allow_conflict) option_conflict('d', 'C'); if (drop_only && continue_edit) option_conflict('d', 'c'); if (drop_only && edit_logmsg_only) option_conflict('d', 'm'); if (drop_only && edit_only) option_conflict('d', 'e'); if (drop_only && edit_script_path) option_conflict('d', 'F'); if (drop_only && fold_only) option_conflict('d', 'f'); if (list_backups) { if (abort_edit) option_conflict('l', 'a'); if (allow_conflict) option_conflict('l', 'C'); if (continue_edit) option_conflict('l', 'c'); if (edit_script_path) option_conflict('l', 'F'); if (edit_logmsg_only) option_conflict('l', 'm'); if (drop_only) option_conflict('l', 'd'); if (fold_only) option_conflict('l', 'f'); if (edit_only) option_conflict('l', 'e'); if (delete_backups) option_conflict('l', 'X'); if (argc != 0 && argc != 1) usage_histedit(); } else if (delete_backups) { if (abort_edit) option_conflict('X', 'a'); if (allow_conflict) option_conflict('X', 'C'); if (continue_edit) option_conflict('X', 'c'); if (drop_only) option_conflict('X', 'd'); if (edit_script_path) option_conflict('X', 'F'); if (edit_logmsg_only) option_conflict('X', 'm'); if (fold_only) option_conflict('X', 'f'); if (edit_only) option_conflict('X', 'e'); if (list_backups) option_conflict('X', 'l'); if (argc != 0 && argc != 1) usage_histedit(); } else if (allow_conflict && !continue_edit) errx(1, "-C option requires -c"); else if (argc != 0) usage_histedit(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (list_backups || delete_backups) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "histedit", cwd); goto done; } } if (list_backups || delete_backups) { error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; error = process_backup_refs( GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX, argc == 1 ? argv[0] : NULL, delete_backups, repo); goto done; /* nothing else to do */ } else { error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), gitconfig_path, pack_fds); if (error != NULL) goto done; error = get_editor(&editor); if (error) goto done; if (unveil(editor, "x") != 0) { error = got_error_from_errno2("unveil", editor); goto done; } if (edit_script_path) { if (unveil(edit_script_path, "r") != 0) { error = got_error_from_errno2("unveil", edit_script_path); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; } if (worktree != NULL && !list_backups && !delete_backups) { error = worktree_has_logmsg_ref("histedit", worktree, repo); if (error) goto done; } error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (error) goto done; if (rebase_in_progress) { error = got_error(GOT_ERR_REBASING); goto done; } error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } error = got_worktree_histedit_in_progress(&edit_in_progress, worktree); if (error) goto done; if (edit_in_progress && edit_logmsg_only) { error = got_error_msg(GOT_ERR_HISTEDIT_BUSY, "histedit operation is in progress in this " "work tree and must be continued or aborted " "before the -m option can be used"); goto done; } if (edit_in_progress && drop_only) { error = got_error_msg(GOT_ERR_HISTEDIT_BUSY, "histedit operation is in progress in this " "work tree and must be continued or aborted " "before the -d option can be used"); goto done; } if (edit_in_progress && fold_only) { error = got_error_msg(GOT_ERR_HISTEDIT_BUSY, "histedit operation is in progress in this " "work tree and must be continued or aborted " "before the -f option can be used"); goto done; } if (edit_in_progress && edit_only) { error = got_error_msg(GOT_ERR_HISTEDIT_BUSY, "histedit operation is in progress in this " "work tree and must be continued or aborted " "before the -e option can be used"); goto done; } if (edit_in_progress && abort_edit) { error = got_worktree_histedit_continue(&resume_commit_id, &tmp_branch, &branch, &base_commit_id, &fileindex, worktree, repo); if (error) goto done; printf("Switching work tree to %s\n", got_ref_get_symref_target(branch)); error = got_worktree_histedit_abort(worktree, fileindex, repo, branch, base_commit_id, abort_progress, &upa, 1); if (error) goto done; printf("Histedit of %s aborted\n", got_ref_get_symref_target(branch)); print_merge_progress_stats(&upa); goto done; /* nothing else to do */ } else if (abort_edit) { error = got_error(GOT_ERR_NOT_HISTEDIT); goto done; } error = get_author(&committer, repo, worktree); if (error) goto done; if (continue_edit) { char *path; if (!edit_in_progress) { error = got_error(GOT_ERR_NOT_HISTEDIT); goto done; } error = got_worktree_get_histedit_script_path(&path, worktree); if (error) goto done; error = histedit_load_list(&histedit_cmds, path, repo); free(path); if (error) goto done; error = got_worktree_histedit_continue(&resume_commit_id, &tmp_branch, &branch, &base_commit_id, &fileindex, worktree, repo); if (error) goto done; error = got_ref_resolve(&head_commit_id, repo, branch); if (error) goto done; error = got_object_open_as_commit(&commit, repo, head_commit_id); if (error) goto done; parent_ids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(parent_ids); if (pid == NULL) { error = got_error(GOT_ERR_EMPTY_HISTEDIT); goto done; } error = collect_commits(&commits, head_commit_id, &pid->id, base_commit_id, got_worktree_get_path_prefix(worktree), GOT_ERR_HISTEDIT_PATH, repo); got_object_commit_close(commit); commit = NULL; if (error) goto done; } else { if (edit_in_progress) { error = got_error(GOT_ERR_HISTEDIT_BUSY); goto done; } error = got_ref_open(&branch, repo, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) { error = got_error_msg(GOT_ERR_COMMIT_BRANCH, "will not edit commit history of a branch outside " "the \"refs/heads/\" reference namespace"); goto done; } error = got_ref_resolve(&head_commit_id, repo, branch); got_ref_close(branch); branch = NULL; if (error) goto done; error = got_object_open_as_commit(&commit, repo, head_commit_id); if (error) goto done; parent_ids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(parent_ids); if (pid == NULL) { error = got_error(GOT_ERR_EMPTY_HISTEDIT); goto done; } error = collect_commits(&commits, head_commit_id, &pid->id, got_worktree_get_base_commit_id(worktree), got_worktree_get_path_prefix(worktree), GOT_ERR_HISTEDIT_PATH, repo); got_object_commit_close(commit); commit = NULL; if (error) goto done; if (STAILQ_EMPTY(&commits)) { error = got_error(GOT_ERR_EMPTY_HISTEDIT); goto done; } error = got_worktree_histedit_prepare(&tmp_branch, &branch, &base_commit_id, &fileindex, worktree, repo); if (error) goto done; if (edit_script_path) { error = histedit_load_list(&histedit_cmds, edit_script_path, repo); if (error) { got_worktree_histedit_abort(worktree, fileindex, repo, branch, base_commit_id, abort_progress, &upa, 0); print_merge_progress_stats(&upa); goto done; } } else { const char *branch_name; branch_name = got_ref_get_symref_target(branch); if (strncmp(branch_name, "refs/heads/", 11) == 0) branch_name += 11; error = histedit_edit_script(&histedit_cmds, &commits, branch_name, edit_logmsg_only, fold_only, drop_only, edit_only, editor, repo); if (error) { got_worktree_histedit_abort(worktree, fileindex, repo, branch, base_commit_id, abort_progress, &upa, 0); print_merge_progress_stats(&upa); goto done; } } error = histedit_save_list(&histedit_cmds, worktree, repo); if (error) { got_worktree_histedit_abort(worktree, fileindex, repo, branch, base_commit_id, abort_progress, &upa, 0); print_merge_progress_stats(&upa); goto done; } } error = histedit_check_script(&histedit_cmds, &commits, repo); if (error) goto done; TAILQ_FOREACH(hle, &histedit_cmds, entry) { if (resume_commit_id) { if (got_object_id_cmp(hle->commit_id, resume_commit_id) != 0) continue; resume_commit_id = NULL; if (hle->cmd->code == GOT_HISTEDIT_DROP || hle->cmd->code == GOT_HISTEDIT_FOLD) { error = histedit_skip_commit(hle, worktree, repo); if (error) goto done; } else { struct got_pathlist_head paths; int have_changes = 0; RB_INIT(&paths); error = got_pathlist_insert(NULL, &paths, "", NULL); if (error) goto done; error = got_worktree_status(worktree, &paths, repo, 0, check_local_changes, &have_changes, check_cancelled, NULL); got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); if (error) { if (error->code != GOT_ERR_CANCELLED) goto done; if (sigint_received || sigpipe_received) goto done; } if (have_changes) { error = histedit_commit(NULL, worktree, fileindex, tmp_branch, hle, committer, allow_conflict, editor, repo); if (error) goto done; } else { error = histedit_skip_commit(hle, worktree, repo); if (error) goto done; } } continue; } if (hle->cmd->code == GOT_HISTEDIT_DROP) { error = histedit_skip_commit(hle, worktree, repo); if (error) goto done; continue; } error = got_object_open_as_commit(&commit, repo, hle->commit_id); if (error) goto done; parent_ids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(parent_ids); error = got_worktree_histedit_merge_files(&merged_paths, worktree, fileindex, &pid->id, hle->commit_id, repo, update_progress, &upa, check_cancelled, NULL); if (error) goto done; got_object_commit_close(commit); commit = NULL; print_merge_progress_stats(&upa); if (upa.conflicts > 0 || upa.missing > 0 || upa.not_deleted > 0 || upa.unversioned > 0) { if (upa.conflicts > 0) { error = show_rebase_merge_conflict( hle->commit_id, repo); if (error) goto done; } got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH); break; } if (hle->cmd->code == GOT_HISTEDIT_EDIT) { char *id_str; error = got_object_id_str(&id_str, hle->commit_id); if (error) goto done; printf("Stopping histedit for amending commit %s\n", id_str); free(id_str); got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH); error = got_worktree_histedit_postpone(worktree, fileindex); goto done; } else if (hle->cmd->code == GOT_HISTEDIT_FOLD) { error = histedit_skip_commit(hle, worktree, repo); if (error) goto done; continue; } else if (hle->cmd->code == GOT_HISTEDIT_MESG) { error = histedit_edit_logmsg(hle, editor, repo); if (error) goto done; } error = histedit_commit(&merged_paths, worktree, fileindex, tmp_branch, hle, committer, allow_conflict, editor, repo); got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH); if (error) goto done; } if (upa.conflicts > 0 || upa.missing > 0 || upa.not_deleted > 0 || upa.unversioned > 0) { error = got_worktree_histedit_postpone(worktree, fileindex); if (error) goto done; if (upa.conflicts > 0 && upa.missing == 0 && upa.not_deleted == 0 && upa.unversioned == 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before histedit " "can continue"); } else if (upa.conflicts > 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before histedit " "can continue; changes destined for some " "files were not yet merged and should be " "merged manually if required before the " "histedit operation is continued"); } else { error = got_error_msg(GOT_ERR_CONFLICTS, "changes destined for some files were not " "yet merged and should be merged manually " "if required before the histedit operation " "is continued"); } } else error = histedit_complete(worktree, fileindex, tmp_branch, branch, repo); done: free(cwd); free(editor); free(committer); free(gitconfig_path); got_object_id_queue_free(&commits); histedit_free_list(&histedit_cmds); free(head_commit_id); free(base_commit_id); free(resume_commit_id); if (commit) got_object_commit_close(commit); if (branch) got_ref_close(branch); if (tmp_branch) got_ref_close(tmp_branch); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_integrate(void) { fprintf(stderr, "usage: %s integrate branch\n", getprogname()); exit(1); } static const struct got_error * cmd_integrate(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *refname = NULL, *base_refname = NULL; const char *branch_arg = NULL; struct got_reference *branch_ref = NULL, *base_branch_ref = NULL; struct got_fileindex *fileindex = NULL; struct got_object_id *commit_id = NULL, *base_commit_id = NULL; int ch; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage_integrate(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_integrate(); branch_arg = argv[0]; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "integrate", cwd); goto done; } error = check_rebase_or_histedit_in_progress(worktree); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = check_merge_in_progress(worktree, repo); if (error) goto done; if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_worktree_integrate_prepare(&fileindex, &branch_ref, &base_branch_ref, worktree, refname, repo); if (error) goto done; refname = strdup(got_ref_get_name(branch_ref)); if (refname == NULL) { error = got_error_from_errno("strdup"); got_worktree_integrate_abort(worktree, fileindex, repo, branch_ref, base_branch_ref); goto done; } base_refname = strdup(got_ref_get_name(base_branch_ref)); if (base_refname == NULL) { error = got_error_from_errno("strdup"); got_worktree_integrate_abort(worktree, fileindex, repo, branch_ref, base_branch_ref); goto done; } if (strncmp(base_refname, "refs/heads/", 11) != 0) { error = got_error(GOT_ERR_INTEGRATE_BRANCH); got_worktree_integrate_abort(worktree, fileindex, repo, branch_ref, base_branch_ref); goto done; } error = got_ref_resolve(&commit_id, repo, branch_ref); if (error) goto done; error = got_ref_resolve(&base_commit_id, repo, base_branch_ref); if (error) goto done; if (got_object_id_cmp(commit_id, base_commit_id) == 0) { error = got_error_msg(GOT_ERR_SAME_BRANCH, "specified branch has already been integrated"); got_worktree_integrate_abort(worktree, fileindex, repo, branch_ref, base_branch_ref); goto done; } error = check_linear_ancestry(commit_id, base_commit_id, 1, repo); if (error) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_REBASE_REQUIRED); got_worktree_integrate_abort(worktree, fileindex, repo, branch_ref, base_branch_ref); goto done; } memset(&upa, 0, sizeof(upa)); error = got_worktree_integrate_continue(worktree, fileindex, repo, branch_ref, base_branch_ref, update_progress, &upa, check_cancelled, NULL); if (error) goto done; printf("Integrated %s into %s\n", refname, base_refname); print_update_progress_stats(&upa); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); free(base_commit_id); free(commit_id); free(refname); free(base_refname); return error; } __dead static void usage_merge(void) { fprintf(stderr, "usage: %s merge [-aCcn] [branch]\n", getprogname()); exit(1); } static const struct got_error * cmd_merge(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; struct got_fileindex *fileindex = NULL; char *cwd = NULL, *id_str = NULL, *author = NULL; char *gitconfig_path = NULL; struct got_reference *branch = NULL, *wt_branch = NULL; struct got_object_id *branch_tip = NULL, *yca_id = NULL; struct got_object_id *wt_branch_tip = NULL; int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0; int allow_conflict = 0, prefer_fast_forward = 1, interrupt_merge = 0; struct got_update_progress_arg upa; struct got_object_id *merge_commit_id = NULL; char *branch_name = NULL; int *pack_fds = NULL; memset(&upa, 0, sizeof(upa)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aCcMn")) != -1) { switch (ch) { case 'a': abort_merge = 1; break; case 'C': allow_conflict = 1; break; case 'c': continue_merge = 1; break; case 'M': prefer_fast_forward = 0; break; case 'n': interrupt_merge = 1; break; default: usage_merge(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (abort_merge) { if (continue_merge) option_conflict('a', 'c'); if (!prefer_fast_forward) option_conflict('a', 'M'); if (interrupt_merge) option_conflict('a', 'n'); } else if (continue_merge) { if (!prefer_fast_forward) option_conflict('c', 'M'); if (interrupt_merge) option_conflict('c', 'n'); } if (allow_conflict) { if (!continue_merge) errx(1, "-C option requires -c"); } if (abort_merge || continue_merge) { if (argc != 0) usage_merge(); } else if (argc != 1) usage_merge(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "merge", cwd); goto done; } error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, gitconfig_path, pack_fds); if (error != NULL) goto done; if (worktree != NULL) { error = worktree_has_logmsg_ref("merge", worktree, repo); if (error) goto done; } error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; error = check_rebase_or_histedit_in_progress(worktree); if (error) goto done; error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress && !(abort_merge || continue_merge)) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } if (!merge_in_progress && (abort_merge || continue_merge)) { error = got_error(GOT_ERR_NOT_MERGING); goto done; } if (abort_merge) { error = got_worktree_merge_continue(&branch_name, &branch_tip, &fileindex, worktree, repo); if (error) goto done; error = got_worktree_merge_abort(worktree, fileindex, repo, abort_progress, &upa); if (error) goto done; printf("Merge of %s aborted\n", branch_name); goto done; /* nothing else to do */ } if (strncmp(got_worktree_get_head_ref_name(worktree), "refs/heads/", 11) != 0) { error = got_error_fmt(GOT_ERR_COMMIT_BRANCH, "work tree's current branch %s is outside the " "\"refs/heads/\" reference namespace; " "update -b required", got_worktree_get_head_ref_name(worktree)); goto done; } error = get_author(&author, repo, worktree); if (error) goto done; error = got_ref_open(&wt_branch, repo, got_worktree_get_head_ref_name(worktree), 0); if (error) goto done; error = got_ref_resolve(&wt_branch_tip, repo, wt_branch); if (error) goto done; if (continue_merge) { struct got_object_id *base_commit_id; base_commit_id = got_worktree_get_base_commit_id(worktree); if (got_object_id_cmp(wt_branch_tip, base_commit_id) != 0) { error = got_error(GOT_ERR_MERGE_COMMIT_OUT_OF_DATE); goto done; } error = got_worktree_merge_continue(&branch_name, &branch_tip, &fileindex, worktree, repo); if (error) goto done; } else { error = got_ref_open(&branch, repo, argv[0], 0); if (error != NULL) goto done; branch_name = strdup(got_ref_get_name(branch)); if (branch_name == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_ref_resolve(&branch_tip, repo, branch); if (error) goto done; } error = got_commit_graph_find_youngest_common_ancestor(&yca_id, wt_branch_tip, branch_tip, 0, 0, repo, check_cancelled, NULL); if (error && error->code != GOT_ERR_ANCESTRY) goto done; if (!continue_merge) { error = check_path_prefix(wt_branch_tip, branch_tip, got_worktree_get_path_prefix(worktree), GOT_ERR_MERGE_PATH, repo); if (error) goto done; error = got_worktree_merge_prepare(&fileindex, worktree, repo); if (error) goto done; if (prefer_fast_forward && yca_id && got_object_id_cmp(wt_branch_tip, yca_id) == 0) { struct got_pathlist_head paths; if (interrupt_merge) { error = got_error_fmt(GOT_ERR_BAD_OPTION, "there are no changes to merge since %s " "is already based on %s; merge cannot be " "interrupted for amending; -n", branch_name, got_ref_get_name(wt_branch)); goto done; } printf("Forwarding %s to %s\n", got_ref_get_name(wt_branch), branch_name); error = got_ref_change_ref(wt_branch, branch_tip); if (error) goto done; error = got_ref_write(wt_branch, repo); if (error) goto done; error = got_worktree_set_base_commit_id(worktree, repo, branch_tip); if (error) goto done; RB_INIT(&paths); error = got_pathlist_insert(NULL, &paths, "", NULL); if (error) goto done; error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); if (error) goto done; if (upa.did_something) { char *id_str; error = got_object_id_str(&id_str, branch_tip); if (error) goto done; printf("Updated to commit %s\n", id_str); free(id_str); } else printf("Already up-to-date\n"); print_update_progress_stats(&upa); goto done; } error = got_worktree_merge_write_refs(worktree, branch, repo); if (error) goto done; error = got_worktree_merge_branch(worktree, fileindex, yca_id, branch_tip, repo, update_progress, &upa, check_cancelled, NULL); if (error) goto done; print_merge_progress_stats(&upa); if (!upa.did_something) { error = got_worktree_merge_abort(worktree, fileindex, repo, abort_progress, &upa); if (error) goto done; printf("Already up-to-date\n"); goto done; } } if (interrupt_merge) { error = got_worktree_merge_postpone(worktree, fileindex); if (error) goto done; printf("Merge of %s interrupted on request\n", branch_name); } else if (upa.conflicts > 0 || upa.missing > 0 || upa.not_deleted > 0 || upa.unversioned > 0) { error = got_worktree_merge_postpone(worktree, fileindex); if (error) goto done; if (upa.conflicts > 0 && upa.missing == 0 && upa.not_deleted == 0 && upa.unversioned == 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before merging " "can continue"); } else if (upa.conflicts > 0) { error = got_error_msg(GOT_ERR_CONFLICTS, "conflicts must be resolved before merging " "can continue; changes destined for some " "files were not yet merged and " "should be merged manually if required before the " "merge operation is continued"); } else { error = got_error_msg(GOT_ERR_CONFLICTS, "changes destined for some " "files were not yet merged and should be " "merged manually if required before the " "merge operation is continued"); } goto done; } else { error = got_worktree_merge_commit(&merge_commit_id, worktree, fileindex, author, 0, NULL, 1, branch_tip, branch_name, allow_conflict, repo, continue_merge ? print_status : NULL, NULL); if (error) goto done; error = got_worktree_merge_complete(worktree, fileindex, repo); if (error) goto done; error = got_object_id_str(&id_str, merge_commit_id); if (error) goto done; printf("Merged %s into %s: %s\n", branch_name, got_worktree_get_head_ref_name(worktree), id_str); } done: free(cwd); free(gitconfig_path); free(id_str); free(merge_commit_id); free(author); free(branch_tip); free(branch_name); free(yca_id); if (branch) got_ref_close(branch); if (wt_branch) got_ref_close(wt_branch); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_stage(void) { fprintf(stderr, "usage: %s stage [-lpS] [-F response-script] " "[path ...]\n", getprogname()); exit(1); } static const struct got_error * print_stage(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { const struct got_error *err = NULL; char *id_str = NULL; if (staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_DELETE) return NULL; if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) err = got_object_id_str(&id_str, staged_blob_id); else err = got_object_id_str(&id_str, blob_id); if (err) return err; printf("%s %c %s\n", id_str, staged_status, path); free(id_str); return NULL; } static const struct got_error * cmd_stage(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL; struct got_pathlist_head paths; int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "F:lpS")) != -1) { switch (ch) { case 'F': patch_script_path = optarg; break; case 'l': list_stage = 1; break; case 'p': pflag = 1; break; case 'S': allow_bad_symlinks = 1; break; default: usage_stage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_stage && (pflag || patch_script_path)) errx(1, "-l option cannot be used with other options"); if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "stage", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; if (patch_script_path) { patch_script_file = fopen(patch_script_path, "re"); if (patch_script_file == NULL) { error = got_error_from_errno2("fopen", patch_script_path); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = check_merge_in_progress(worktree, repo); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (list_stage) error = got_worktree_status(worktree, &paths, repo, 0, print_stage, NULL, check_cancelled, NULL); else { cpa.patch_script_file = patch_script_file; cpa.action = "stage"; error = got_worktree_stage(worktree, &paths, pflag ? NULL : print_status, NULL, pflag ? choose_patch : NULL, &cpa, allow_bad_symlinks, repo); } done: if (patch_script_file && fclose(patch_script_file) == EOF && error == NULL) error = got_error_from_errno2("fclose", patch_script_path); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_unstage(void) { fprintf(stderr, "usage: %s unstage [-p] [-F response-script] " "[path ...]\n", getprogname()); exit(1); } static const struct got_error * cmd_unstage(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL; struct got_pathlist_head paths; int ch, pflag = 0; struct got_update_progress_arg upa; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "F:p")) != -1) { switch (ch) { case 'F': patch_script_path = optarg; break; case 'p': pflag = 1; break; default: usage_unstage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "unstage", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; if (patch_script_path) { patch_script_file = fopen(patch_script_path, "re"); if (patch_script_file == NULL) { error = got_error_from_errno2("fopen", patch_script_path); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; cpa.patch_script_file = patch_script_file; cpa.action = "unstage"; memset(&upa, 0, sizeof(upa)); error = got_worktree_unstage(worktree, &paths, update_progress, &upa, pflag ? choose_patch : NULL, &cpa, repo); if (!error) print_merge_progress_stats(&upa); done: if (patch_script_file && fclose(patch_script_file) == EOF && error == NULL) error = got_error_from_errno2("fclose", patch_script_path); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_cat(void) { fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] " "arg ...\n", getprogname()); exit(1); } static const struct got_error * cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_blob_object *blob; int fd = -1; fd = got_opentempfd(); if (fd == -1) return got_error_from_errno("got_opentempfd"); err = got_object_open_as_blob(&blob, repo, id, 8192, fd); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); return err; } static const struct got_error * cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tree_object *tree; int nentries, i; err = got_object_open_as_tree(&tree, repo, id); if (err) return err; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id_str; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) break; fprintf(outfile, "%s %.7o %s\n", id_str, got_tree_entry_get_mode(te), got_tree_entry_get_name(te)); free(id_str); } got_object_tree_close(tree); return err; } static const struct got_error * cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_commit_object *commit; const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; char *id_str = NULL; const char *logmsg = NULL; char gmtoff[6]; err = got_object_open_as_commit(&commit, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str); parent_ids = got_object_commit_get_parent_ids(commit); fprintf(outfile, "numparents %d\n", got_object_commit_get_nparents(commit)); STAILQ_FOREACH(pid, parent_ids, entry) { char *pid_str; err = got_object_id_str(&pid_str, &pid->id); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str); free(pid_str); } got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_author_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR, got_object_commit_get_author(commit), (long long)got_object_commit_get_author_time(commit), gmtoff); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_committer_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER, got_object_commit_get_committer(commit), (long long)got_object_commit_get_committer_time(commit), gmtoff); logmsg = got_object_commit_get_logmsg_raw(commit); fprintf(outfile, "messagelen %zd\n", strlen(logmsg)); fprintf(outfile, "%s", logmsg); done: free(id_str); got_object_commit_close(commit); return err; } static const struct got_error * cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tag_object *tag; char *id_str = NULL; const char *tagmsg = NULL; char gmtoff[6]; err = got_object_open_as_tag(&tag, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str); switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_BLOB); break; case GOT_OBJ_TYPE_TREE: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TREE); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_COMMIT); break; case GOT_OBJ_TYPE_TAG: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TAG); break; default: break; } fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG, got_object_tag_get_name(tag)); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_tag_get_tagger_gmtoff(tag)); fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER, got_object_tag_get_tagger(tag), (long long)got_object_tag_get_tagger_time(tag), gmtoff); tagmsg = got_object_tag_get_message(tag); fprintf(outfile, "messagelen %zd\n", strlen(tagmsg)); fprintf(outfile, "%s", tagmsg); done: free(id_str); got_object_tag_close(tag); return err; } static const struct got_error * cmd_cat(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *label = NULL; char *keyword_idstr = NULL; const char *commit_id_str = NULL; struct got_object_id *id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; int ch, obj_type, i, force_path = 0; struct got_reflist_head refs; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:Pr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_cat(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { repo_path = strdup( got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } if (commit_id_str == NULL) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } } } if (repo_path == NULL) { repo_path = strdup(cwd); if (repo_path == NULL) return got_error_from_errno("strdup"); } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str != NULL) { error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_str = keyword_idstr; if (worktree != NULL) { got_worktree_close(worktree); worktree = NULL; } } else commit_id_str = GOT_REF_HEAD; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; for (i = 0; i < argc; i++) { if (force_path) { error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } else { error = got_repo_match_object_id(&id, &label, argv[i], GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */, repo); if (error) { if (error->code != GOT_ERR_BAD_OBJ_ID_STR && error->code != GOT_ERR_NOT_REF) break; error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } } error = got_object_get_type(&obj_type, repo, id); if (error) break; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: error = cat_blob(id, repo, stdout); break; case GOT_OBJ_TYPE_TREE: error = cat_tree(id, repo, stdout); break; case GOT_OBJ_TYPE_COMMIT: error = cat_commit(id, repo, stdout); break; case GOT_OBJ_TYPE_TAG: error = cat_tag(id, repo, stdout); break; default: error = got_error(GOT_ERR_OBJ_TYPE); break; } if (error) break; free(label); label = NULL; free(id); id = NULL; } done: free(cwd); free(label); free(id); free(commit_id); free(keyword_idstr); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); return error; } __dead static void usage_info(void) { fprintf(stderr, "usage: %s info [path ...]\n", getprogname()); exit(1); } static const struct got_error * print_path_info(void *arg, const char *path, mode_t mode, time_t mtime, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id) { const struct got_error *err = NULL; char *id_str = NULL; char datebuf[128]; struct tm mytm, *tm; struct got_pathlist_head *paths = arg; struct got_pathlist_entry *pe; /* * Clear error indication from any of the path arguments which * would cause this file index entry to be displayed. */ RB_FOREACH(pe, got_pathlist_head, paths) { if (got_path_cmp(path, pe->path, strlen(path), pe->path_len) == 0 || got_path_is_child(path, pe->path, pe->path_len)) pe->data = NULL; /* no error */ } printf(GOT_COMMIT_SEP_STR); if (S_ISLNK(mode)) printf("symlink: %s\n", path); else if (S_ISREG(mode)) { printf("file: %s\n", path); printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } else if (S_ISDIR(mode)) printf("directory: %s\n", path); else printf("something: %s\n", path); tm = localtime_r(&mtime, &mytm); if (tm == NULL) return NULL; if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0) return got_error(GOT_ERR_NO_SPACE); printf("timestamp: %s\n", datebuf); if (blob_id) { err = got_object_id_str(&id_str, blob_id); if (err) return err; printf("based on blob: %s\n", id_str); free(id_str); } if (staged_blob_id) { err = got_object_id_str(&id_str, staged_blob_id); if (err) return err; printf("based on staged blob: %s\n", id_str); free(id_str); } if (commit_id) { err = got_object_id_str(&id_str, commit_id); if (err) return err; printf("based on commit: %s\n", id_str); free(id_str); } return NULL; } static const struct got_error * cmd_info(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_fileindex *fileindex = NULL; char *cwd = NULL, *id_str = NULL; struct got_pathlist_head paths; char *uuidstr = NULL; int ch, show_files = 0; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage_info(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_GOT_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "info", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, NULL); if (error) goto done; #ifndef PROFILE /* Remove "wpath cpath proc exec sendfd" promises. */ if (pledge("stdio rpath flock unveil", NULL) == -1) err(1, "pledge"); #endif error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree)); if (error) goto done; if (argc >= 1) { error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; show_files = 1; } error = got_worktree_path_info_prepare(&fileindex, worktree, repo); if (error) goto done; error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; error = got_worktree_get_uuid(&uuidstr, worktree); if (error) goto done; printf("work tree: %s\n", got_worktree_get_root_path(worktree)); printf("work tree base commit: %s\n", id_str); printf("work tree path prefix: %s\n", got_worktree_get_path_prefix(worktree)); printf("work tree branch reference: %s\n", got_worktree_get_head_ref_name(worktree)); printf("work tree UUID: %s\n", uuidstr); printf("work tree format version: %d\n", got_worktree_get_format_version(worktree)); printf("file index version: %u\n", got_worktree_get_fileindex_version(fileindex)); printf("repository: %s\n", got_worktree_get_repo_path(worktree)); if (show_files) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, &paths) { if (pe->path_len == 0) continue; /* * Assume this path will fail. This will be corrected * in print_path_info() in case the path does suceeed. */ pe->data = (void *)got_error(GOT_ERR_BAD_PATH); } error = got_worktree_path_info(worktree, fileindex, &paths, print_path_info, &paths, check_cancelled, NULL); if (error) goto done; RB_FOREACH(pe, got_pathlist_head, &paths) { if (pe->data != NULL) { const struct got_error *perr; perr = pe->data; error = got_error_path(pe->path, perr->code); break; } } } done: if (worktree) { const struct got_error *cerr; cerr = got_worktree_path_info_complete(fileindex, worktree); if (error == NULL) error = cerr; got_worktree_close(worktree); } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(uuidstr); return error; } got-portable-0.119/got/got-worktree.50000664000175000017500000001457415066535721013143 .\" .\" Copyright (c) 2018 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOT-WORKTREE 5 .Os .Sh NAME .Nm got-worktree .Nd Game of Trees work tree format .Sh DESCRIPTION A Got .Em work tree stores a file hierarchy which corresponds to a versioned snapshot stored in a Git repository. The work tree's meta data is stored in the .Pa .got directory. A work tree is created with .Cm got checkout and is required to make changes to a Git repository with .Xr got 1 . .Pp A work tree stores the path to its Git repository, the name of a reference to the branch which files were checked out from, and the ID of a commit on this branch known as the .Em base commit . .Pp File meta-data is stored in a structured file called the .Em file index which tracks the status of file modifications, additions, and deletions, relative to the base commit in the repository. The file index contains a series of records, and each such record contains the following status information for a particular file: .Bl -tag -width Ds .It Copy of filesystem meta-data Timestamp, file size, and file ownership information from .Xr stat 2 . This is only used to detect file modifications and is never applied back to the filesystem. File permissions are not tracked, except for the executable bit. When versioned files are checked out into the work tree, the current .Xr umask 2 is heeded. .It Blob object ID The hash of the blob object which corresponds to the contents of this file in the repository. The hash is stored as binary data. The size of the hash depends on the hashing algorithm used in the repository. .It Commit object ID The hash of the commit object the file was checked out from. The hash is stored as binary data. This data is used to detect past incomplete update operations. Entries which do not match the work tree's base commit may still need to be updated to match file content stored in the base commit. .It Flags This field contains the length, according to .Xr strlen 3 , of path data which follows, and the following flags: .Bl -tag -width Ds .It STAGE Reflects the added, modified, or deleted staged state of a path staged with .Cm got stage . .It NOT_FLUSHED The entry was added to the file index in memory and does not exist in file index data read from disk. This happens to files which are added to the work tree while operations such as .Cm got checkout , .Cm got update , .Cm got cherrypick , .Cm got backout , .Cm got rebase , and .Cm got histedit are in progress. This flag is always cleared before the entry is written to disk. .It NO_BLOB The entry's on-disk file content in the work tree is not based on a blob in the repository. The blob object ID of this entry must be considered invalid. This happens when unversioned files are added with .Cm got add and when files are added to the work tree by operations such as .Cm got cherrypick , .Cm got backout , .Cm got rebase , and .Cm got histedit . .It NO_COMMIT The entry is not based on a commit in the repository. The commit object ID of this entry must be considered invalid. This happens when unversioned files are added with .Cm got add and when files are added to the work tree by operations such as .Cm got cherrypick , .Cm got backout , .Cm got rebase , and .Cm got histedit . .It NO_FILE_ON_DISK The entry has no corresponding on-disk file in the work tree. This happens when files are removed with .Cm got remove . .El .It Path data The path of the entry, relative to the work tree root. Path data is of variable length and NUL-padded to a multiple of 8 bytes. .It Staged blob object ID The hash of a blob object containing file content which has been staged for commit. The hash is stored as binary data. Only present if a file addition or modification has been staged with .Cm got stage . .El .Pp A corrupt or missing file index can be recreated on demand as follows: .Pp .Dl $ mv .got/file-index .got/file-index.bad .Dl $ got update # re-create .got/file-index .Dl $ find\ . -type f -exec touch {}\ + # update timestamp of all files .Dl $ got update # sync timestamps .Pp When the file index is modified, it is read into memory in its entirety, modified in place, and written to a temporary file. This temporary file is then moved on top of the old file index with .Xr rename 2 . This ensures that no other processes see an inconsistent file index which is in the process of being written. .Pp Work tree meta data must only be modified while the work tree's .Pa lock file has been exclusively locked with .Xr lockf 3 . .Pp Each work tree has a universal unique identifier. When a work tree is checked out or updated, this identifier is used to create a reference to the current base commit in the Git repository. The presence of this reference prevents the Git garbage collector and .Cm gotadmin cleanup from discarding the base commit and any objects it refers to. When a work tree is no longer needed, its reference can be deleted from the Git repository with .Cm got ref -d . .Sh FILES .Bl -tag -width path-prefix -compact .It Pa .got Meta-data directory where all files listed below reside. .It Pa base-commit hash digest hex-string representation of the current base commit. .It Pa file-index File status information. .It Pa format Work tree format number. .It Pa got.conf Configuration file for .Xr got 1 . See .Xr got.conf 5 . .It Pa head-ref Name of the reference to the current branch. .It Pa lock Lock file to obtain exclusive write access to meta data. .It Pa path-prefix Path inside repository the work tree was checked out from. .It Pa repository Path to the repository the work tree was checked out from. .It Pa uuid A universal unique identifier for the work tree. .El .Sh SEE ALSO .Xr got 1 , .Xr rename 2 , .Xr stat 2 , .Xr umask 2 , .Xr flock 3 , .Xr git-repository 5 , .Xr got.conf 5 got-portable-0.119/got/git-repository.50000664000175000017500000001752015066535721013504 .\" .\" Copyright (c) 2018 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GIT-REPOSITORY 5 .Os .Sh NAME .Nm git-repository .Nd Git repository format .Sh DESCRIPTION A Git repository stores a series of versioned snapshots of a file hierarchy. Conceptually, the repository's data model is a directed acyclic graph which contains four types of objects as nodes: .Bl -tag -width commits .It Blobs The content of tracked files is stored in objects of type .Em blob . .It Trees A .Em tree object points to any number of such blobs, and also to other trees in order to represent a hierarchy of files and directories. .It Commits A .Em commit object points to the root element of one tree, and thus records the state of this entire tree as a snapshot. Commit objects are chained together to form lines of version control history. Most commits have just one successor commit, but commits may be succeeded by an arbitrary number of subsequent commits so that diverging lines of version control history, known as .Em branches , can be represented. A commit which precedes another commit is referred to as that other commit's .Em parent commit . A commit with multiple parents unites disparate lines of history and is known as a .Em merge commit . .It Tags A .Em tag object associates a user-defined label with another object, which is typically a commit object. Tag objects also contain a tag message, as well as author and timestamp information. .El .Pp Each object is identified by an hash calculated over both the object's header and the data stored in the object. The hashing algorithm used is specified in the repository .Pa config file for newer repositories while older ones use SHA1 implicitly. .Sh OBJECT STORAGE Loose objects are stored as individual files beneath the directory .Pa objects , spread across 256 sub-directories named after the 256 possible hexadecimal values of the first byte of an object identifier. The name of the loose object file corresponds to the remaining hexadecimal byte values of the object's identifier. .Pp A loose object file begins with a header which specifies the type of object as an ASCII string, followed by an ASCII space character, followed by the object data's size encoded as an ASCII number string. The header is terminated by a .Sy NUL character, and the remainder of the file contains object data. Loose objects files are compressed with .Xr deflate 3 . .Pp Multiple objects can be bundled in a .Em pack file for better disk space efficiency and increased run-time performance. The pack file format introduces two additional types of objects: .Bl -tag -width Ds .It Offset Delta Objects This object is represented as a delta against another object in the same pack file. This other object is referred to by its offset in the pack file. .It Reference Delta Objects This object is represented as a delta against another object in the same pack file. The other object is referred to by its object identifier. .El .Pp Pack files are self-contained and may not refer to loose objects or objects stored in other pack files. Deltified objects may refer to other deltified objects as their delta base, forming chains of deltas. The ultimate base of a delta chain must be an object of the same type as the original object which is stored in deltified form. .Pp Each pack file is accompanied by a corresponding .Em pack index file, which lists the IDs and offsets of all objects contained in the pack file. .Sh REFERENCES A reference associates a name with an object ID. A prominent use of references is providing names to branches in the repository by pointing at commit objects which represent the current tip commit of a branch. Because references may point to arbitrary object IDs, their use is not limited to branches. .Pp The name is a non-empty UTF-8 string with the following disallowed characters: .Sq \ \& (space), \(a~ (tilde), \(a^ (caret), : (colon), ? (question mark), * (asterisk), [ (opening square bracket), \\ (backslash). The name may not be the string .Dq @ , may not begin with a / (slash), and may not begin or end with a \. (period). Additionally, the name may not contain the two-character sequences //, .. , and @{. .Pp Reference names may optionally have multiple components separated by the / (slash) character, forming a hierarchy of reference namespaces. Got reserves the .Pa refs/got/ reference namespace for internal use. .Pp A symbolic reference associates a name with the name of another reference. The most prominent example is the .Pa HEAD reference which points at the name of the repository's default branch reference. .Pp References are stored either as a plain file within the repository, typically under the .Pa refs/ directory, or in the .Pa packed-refs file which contains one reference definition per line. .Pp Any object which is not directly or indirectly reachable via a reference is subject to deletion by Git's garbage collector or .Cm gotadmin cleanup . .Sh FILES .Bl -tag -width packed-refs -compact .It Pa HEAD A reference to the current head commit of the Git work tree. In bare repositories, this file serves as a default reference. .It Pa ORIG_HEAD Reference to original head commit. Set by some Git operations. .It Pa FETCH_HEAD Reference to a branch tip commit most recently fetched from another repository. .It Pa branches/ Legacy directory used by the deprecated Gogito Git interface. .It Pa config Git configuration file. See .Xr git-config 1 . .It Pa description A human-readable description of the repository. .It Pa got.conf Configuration file for .Xr got 1 . See .Xr got.conf 5 . .It Pa hooks/ This directory contains hook scripts to run when certain events occur. .It Pa index The file index used by .Xr git 1 . This file is not used by .Xr got 1 , which uses the .Xr got-worktree 5 file index instead. .It Pa info Various configuration items. .It Pa logs/ Directory where reflogs are stored. .It Pa objects/ Loose and packed objects are stored in this directory. .It Pa packed-refs A file which stores references. Corresponding on-disk references take precedence over those stored here. .It Pa refs/ The default directory to store references in. .El .Pp A typical Git repository exposes a work tree which allows the user to make changes to versioned files and create new commits. When a Git work tree is present, the actual repository data is stored in a .Pa .git subfolder of the repository's root directory. A Git repository without a work tree is known as a .Dq bare repository. .Xr got 1 does not make use of Git's work tree and treats every repository as if it was bare. .Sh SEE ALSO .Xr got 1 , .Xr gotadmin 1 , .Xr deflate 3 , .Xr SHA1 3 , .Xr got-worktree 5 , .Xr got.conf 5 .Sh HISTORY The Git repository format was initially designed by Linus Torvalds in 2005 and has since been extended by various people involved in the development of the Git version control system. .Sh CAVEATS The particular set of disallowed characters in reference names is a consequence of design choices made for the command-line interface of .Xr git 1 . The same characters are disallowed by Got for compatibility purposes. Got additionally prevents users from creating reference names with a leading - (dash) character, because this is rarely intended and not considered useful. got-portable-0.119/got/got.10000664000175000017500000036654315066535721011305 .\" .\" Copyright (c) 2017 Martin Pieuchot .\" Copyright (c) 2018, 2019, 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOT 1 .Os .Sh NAME .Nm got .Nd Game of Trees .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Sh DESCRIPTION .Nm is a version control system which stores the history of tracked files in a Git repository, as used by the Git version control system. This repository format is described in .Xr git-repository 5 . .Pp .Nm is a .Dq distributed version control system because every copy of a repository is writeable. Modifications made to files can be synchronized between repositories at any time. .Pp Files managed by .Nm must be checked out from the repository for modification. Checked out files are stored in a .Em work tree which can be placed at an arbitrary directory in the filesystem hierarchy. The on-disk format of this work tree is described in .Xr got-worktree 5 . .Pp The .Nm utility provides global and command-specific options. Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information and exit immediately. .It Fl V , -version Display program version and exit immediately. .El .Pp The .Nm utility only provides commands needed to perform version control tasks. Commands needed for repository maintenance tasks are provided by .Xr gotadmin 1 . Git repository server functionality is provided by .Xr gotd 8 . A repository interface for web browsers is provided by .Xr gotwebd 8 . An interactive repository interface for the terminal is provided by .Xr tog 1 . .Pp The commands for .Nm are as follows: .Bl -tag -width checkout .It Cm init Oo Fl A Ar hashing-algorithm Oc Oo Fl b Ar branch Oc Ar repository-path Create a new empty repository at the specified .Ar repository-path . .Pp After .Cm got init , the new repository must be populated before .Cm got checkout can be used. The .Cm got import command can be used to populate the new repository with data from a local directory. Alternatively, on a server running .Xr gotd 8 , the new repository can be made available to .Xr got 1 or .Xr git 1 clients by adding the repository to .Xr gotd.conf 5 and restarting .Xr gotd 8 . Clients may then clone the new repository from the server, populate the cloned repository, and then populate the new repository on the server via .Cm got send or .Cm git push . .Pp The options for .Cm got init are as follows: .Bl -tag -width Ds .It Fl A Ar hashing-algorithm Configure the repository's .Ar hashing-algorithm used for the computation of Git object IDs. Possible values are .Cm sha1 .Pq the default or .Cm sha256 . .It Fl b Ar branch Make the repository's HEAD reference point to the specified .Ar branch instead of the default branch .Dq main . .El .Pp The .Cm got init command is equivalent to .Cm gotadmin init . .Tg im .It Xo .Cm import .Op Fl b Ar branch .Op Fl I Ar pattern .Op Fl m Ar message .Op Fl r Ar repository-path .Ar directory .Xc .Dl Pq alias: Cm im Create an initial commit in a repository from the file hierarchy within the specified .Ar directory . The created commit will not have any parent commits, i.e. it will be a root commit. Also create a new reference which provides a branch name for the newly created commit. Show the path of each imported file to indicate progress. .Pp The .Cm got import command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got import are as follows: .Bl -tag -width Ds .It Fl b Ar branch Create the specified .Ar branch . If this option is not specified, a branch corresponding to the repository's HEAD reference will be used. Use of this option is required if the branch resolved via the repository's HEAD reference already exists. .It Fl I Ar pattern Ignore files or directories with a name which matches the specified .Ar pattern . This option may be specified multiple times to build a list of ignore patterns. The .Ar pattern follows the globbing rules documented in .Xr glob 7 . Ignore patterns which end with a slash, .Dq / , will only match directories. .It Fl m Ar message Use the specified log message when creating the new commit. Without the .Fl m option, .Cm got import opens a temporary file in an editor where a log message can be written. Quitting the editor without saving the file will abort the import operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. .El .Tg cl .It Xo .Cm clone .Op Fl almqv .Op Fl b Ar branch .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Fl R Ar reference .Ar repository-URL .Op Ar directory .Xc .Dl Pq alias: Cm cl Clone a Git repository at the specified .Ar repository-URL into the specified .Ar directory . If no .Ar directory is specified, the directory name will be derived from the name of the cloned repository. .Cm got clone will refuse to run if the .Ar directory already exists. .Pp The .Ar repository-URL specifies a protocol scheme, a server hostname, an optional port number separated from the hostname by a colon, and a path to the repository on the server: .Lk scheme://hostname:port/path/to/repository .Pp The following protocol schemes are supported: .Bl -tag -width https .It git The Git protocol as implemented by the .Xr git-daemon 1 server. Use of this protocol is discouraged since it supports neither authentication nor encryption. .It ssh The Git protocol wrapped in an authenticated and encrypted .Xr ssh 1 tunnel. With this protocol the hostname may contain an embedded username for .Xr ssh 1 to use: .Mt user@hostname .It http The .Dq smart Git HTTP protocol. Not compatible with servers using the .Dq dumb Git HTTP protocol. .Pp The .Dq smart Git HTTP protocol is supported by .Cm got clone and .Cm got fetch , but not by .Cm got send . Sending from a repository cloned over HTTP will require use of a .Ic send block in .Xr got.conf 5 to ensure that the .Dq ssh:// protocol will be used by .Cm got send . .Pp Use of this protocol is discouraged since it supports neither authentication nor encryption. .It https The .Dq smart Git HTTP protocol wrapped in SSL/TLS. .El .Pp Objects in the cloned repository are stored in a pack file which is downloaded from the server. This pack file will then be indexed to facilitate access to the objects stored within. If any objects in the pack file are stored in deltified form, all deltas will be fully resolved in order to compute the ID of such objects. This can take some time. More details about the pack file format are documented in .Xr git-repository 5 . .Pp .Cm got clone creates a remote repository entry in the .Xr got.conf 5 and .Pa config files of the cloned repository to store the .Ar repository-url and any .Ar branch or .Ar reference arguments for future use by .Cm got fetch or .Xr git-fetch 1 . .Pp The options for .Cm got clone are as follows: .Bl -tag -width Ds .It Fl a Fetch all branches from the remote repository's .Dq refs/heads/ reference namespace and set .Cm fetch_all_branches in the cloned repository's .Xr got.conf 5 file for future use by .Cm got fetch . If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl b option. .It Fl b Ar branch Fetch the specified .Ar branch from the remote repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to fetch. If the branch corresponding to the remote repository's HEAD reference is not in this list, the cloned repository's HEAD reference will be set to the first branch which was fetched. If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl a option. .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl l List branches and tags available for fetching from the remote repository and exit immediately. Cannot be used together with any of the other options except .Fl q and .Fl v . .It Fl m Create the cloned repository as a mirror of the original repository. This is useful if the cloned repository will not be used to store locally created commits. .Pp The repository's .Xr got.conf 5 and .Pa config files will be set up with the .Dq mirror option enabled, such that .Cm got fetch or .Xr git-fetch 1 will write incoming changes directly to branches in the .Dq refs/heads/ reference namespace, rather than to branches in the .Dq refs/remotes/ namespace. This avoids the usual requirement of having to run .Cm got rebase or .Cm got merge after .Cm got fetch in order to make incoming changes appear on branches in the .Dq refs/heads/ namespace. But maintaining custom changes in the cloned repository becomes difficult since such changes will be at risk of being discarded whenever incoming changes are fetched. .It Fl q Suppress progress reporting output. The same option will be passed to .Xr ssh 1 if applicable. .It Fl R Ar reference In addition to the branches and tags that will be fetched, fetch an arbitrary .Ar reference from the remote repository's .Dq refs/ namespace. This option may be specified multiple times to build a list of additional references to fetch. The specified .Ar reference may either be a path to a specific reference, or a reference namespace which will cause all references in this namespace to be fetched. .Pp Each reference will be mapped into the cloned repository's .Dq refs/remotes/ namespace, unless the .Fl m option is used to mirror references directly into the cloned repository's .Dq refs/ namespace. .Pp .Cm got clone will refuse to fetch references from the remote repository's .Dq refs/remotes/ or .Dq refs/got/ namespace. .It Fl v Verbose mode. Causes .Cm got clone to print debugging messages to standard error output. This option will be passed to .Xr ssh 1 if applicable. Multiple -v options increase the verbosity. The maximum is 3. .El .Tg fe .It Xo .Cm fetch .Op Fl adlqtvX .Op Fl b Ar branch .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Fl R Ar reference .Op Fl r Ar repository-path .Op Ar remote-repository .Xc .Dl Pq alias: Cm fe Fetch new changes from a remote repository. If no .Ar remote-repository is specified, .Dq origin will be used. The remote repository's URL is obtained from the corresponding entry in .Xr got.conf 5 or Git's .Pa config file of the local repository, as created by .Cm got clone . .Pp By default, any branches configured in .Xr got.conf 5 for the .Ar remote-repository will be fetched. If .Cm got fetch is invoked in a work tree then this work tree's current branch will be fetched, too, provided it is present on the server. If no branches to fetch can be found in .Xr got.conf 5 or via a work tree, or said branches are not found on the server, a branch resolved via the remote repository's HEAD reference will be fetched. Likewise, if a HEAD reference for the .Ar remote-repository exists but its target no longer matches the remote HEAD, then the new target branch will be fetched. This default behaviour can be overridden with the .Fl a and .Fl b options. .Pp New changes will be stored in a separate pack file downloaded from the server. Over time, small pack files will accumulate as a result of repeatedly running .Ic got fetch . For best performance, multiple small pack files can be combined into a single larger pack file with .Ic gotadmin cleanup . The number of pack files in the repository is displayed by .Ic gotadmin info . .Pp By default, branch references in the .Dq refs/remotes/ reference namespace will be updated to point at the newly fetched commits. The .Cm got rebase or .Cm got merge command can then be used to make new changes visible on branches in the .Dq refs/heads/ namespace, merging incoming changes with the changes on those branches as necessary. .Pp If the repository was created as a mirror with .Cm got clone -m , then all branches in the .Dq refs/heads/ namespace will be updated directly to match the corresponding branches in the remote repository. If those branches contained local commits, these commits will no longer be reachable via a reference and will therefore be at risk of being discarded by Git's garbage collector or .Cm gotadmin cleanup . Maintaining custom changes in a mirror repository is therefore discouraged. .Pp In any case, references in the .Dq refs/tags/ namespace will always be fetched and mapped directly to local references in the same namespace. .Pp The options for .Cm got fetch are as follows: .Bl -tag -width Ds .It Fl a Fetch all branches from the remote repository's .Dq refs/heads/ reference namespace. This option can be enabled by default for specific repositories in .Xr got.conf 5 . Cannot be used together with the .Fl b option. .It Fl b Ar branch Fetch the specified .Ar branch from the remote repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to fetch. Cannot be used together with the .Fl a option. .It Fl d Delete branches and tags from the local repository which are no longer present in the remote repository. Only references are deleted. Any commit, tree, tag, and blob objects belonging to deleted branches or tags remain in the repository and may be removed separately with Git's garbage collector or .Cm gotadmin cleanup . .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl l List branches and tags available for fetching from the remote repository and exit immediately. Cannot be used together with any of the other options except .Fl v , .Fl q , and .Fl r . .It Fl q Suppress progress reporting output. The same option will be passed to .Xr ssh 1 if applicable. .It Fl R Ar reference In addition to the branches and tags that will be fetched, fetch an arbitrary .Ar reference from the remote repository's .Dq refs/ namespace. This option may be specified multiple times to build a list of additional references to fetch. The specified .Ar reference may either be a path to a specific reference, or a reference namespace which will cause all references in this namespace to be fetched. .Pp Each reference will be mapped into the local repository's .Dq refs/remotes/ namespace, unless the local repository was created as a mirror with .Cm got clone -m in which case references will be mapped directly into the local repository's .Dq refs/ namespace. .Pp Once a reference has been fetched, a branch based on it can be created with .Cm got branch if needed. .Pp .Cm got fetch will refuse to fetch references from the remote repository's .Dq refs/remotes/ or .Dq refs/got/ namespace. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl t Allow existing references in the .Dq refs/tags namespace to be updated if they have changed on the server. If not specified, only new tag references will be created. .It Fl v Verbose mode. Causes .Cm got fetch to print debugging messages to standard error output. The same option will be passed to .Xr ssh 1 if applicable. Multiple -v options increase the verbosity. The maximum is 3. .It Fl X Delete all references which correspond to a particular .Ar remote-repository instead of fetching new changes. This can be useful when a remote repository is being removed from .Xr got.conf 5 . .Pp With .Fl X , the .Ar remote-repository argument is mandatory and no other options except .Fl r , .Fl v , and .Fl q are allowed. .Pp Only references are deleted. Any commit, tree, tag, and blob objects fetched from a remote repository will generally be stored in pack files and may be removed separately with .Ic gotadmin cleanup and Git's garbage collector. .El .Tg co .It Xo .Cm checkout .Op Fl \&Eq .Op Fl b Ar branch .Op Fl c Ar commit .Op Fl p Ar path-prefix .Ar repository-path .Op Ar work-tree-path .Xc .Dl Pq alias: Cm co Copy files from a repository into a new work tree. Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It A Ta new file was added .It E Ta file already exists in work tree's meta-data .El .Pp If the .Ar work tree path is not specified, either use the last component of .Ar repository path , or if a .Ar path prefix was specified use the last component of .Ar path prefix . .Pp The options for .Cm got checkout are as follows: .Bl -tag -width Ds .It Fl b Ar branch Check out files from a commit on the specified .Ar branch . If this option is not specified, a branch resolved via the repository's HEAD reference will be used. .It Fl c Ar commit Check out files from the specified .Ar commit on the selected branch. If this option is not specified, the most recent commit on the selected branch will be used. .Pp The expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the repository's HEAD reference, or, if the .Fl b option is used, the head of the checked-out .Ar branch . Keywords and reference names may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy foo:-3 will denote the 3rd generation ancestor of the commit resolved by the .Qq foo reference. If an integer does not follow the .Qq :+ or .Qq :- modifier, a .Qq 1 is implicitly appended .Po e.g., .Sy :head:- is equivalent to .Sy :head:-1 .Pc . .Pp If the specified .Ar commit is not contained in the selected branch, a different branch which contains this commit must be specified with the .Fl b option. If no such branch is known, a new branch must be created for this commit with .Cm got branch before .Cm got checkout can be used. Checking out work trees with an unknown branch is intentionally not supported. .It Fl E Proceed with the checkout operation even if the directory at .Ar work-tree-path is not empty. Existing files will be left intact. .It Fl p Ar path-prefix Restrict the work tree to a subset of the repository's tree hierarchy. Only files beneath the specified .Ar path-prefix will be checked out. .It Fl q Silence progress output. .El .Tg up .It Xo .Cm update .Op Fl q .Op Fl b Ar branch .Op Fl c Ar commit .Op Ar path ... .Xc .Dl Pq alias: Cm up Update an existing work tree to a different .Ar commit . Change existing files in the work tree as necessary to match file contents of this commit. Preserve any local changes in the work tree and merge them with the incoming changes. .Pp Files which already contain merge conflicts will not be updated to avoid further complications. Such files will be updated when .Cm got update is run again after merge conflicts have been resolved. If the conflicting changes are no longer needed, affected files can be reverted with .Cm got revert before running .Cm got update again. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated and contained no local changes .It G Ta file was updated and local changes were merged cleanly .It C Ta file was updated and conflicts occurred during merge .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta versioned file is obstructed by a non-regular file .It ! Ta a missing versioned file was restored .It # Ta file was not updated because it contains merge conflicts .It ? Ta changes destined for an unversioned file were not merged .El .Pp If no .Ar path is specified, update the entire work tree. Otherwise, restrict the update operation to files at or within the specified paths. Each path is required to exist in the update operation's target commit. Files in the work tree outside specified paths will remain unchanged and will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. Specifying a .Ar path is incompatible with the .Fl b option. .Pp .Cm got update cannot update paths with staged changes. If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . .Pp The options for .Cm got update are as follows: .Bl -tag -width Ds .It Fl b Ar branch Switch the work tree's branch reference to the specified .Ar branch before updating the work tree. This option requires that all paths in the work tree are updated. .Pp As usual, any local changes in the work tree will be preserved. This can be useful when switching to a newly created branch in order to commit existing local changes to this branch. .Pp Any local changes must be dealt with separately in order to obtain a work tree with pristine file contents corresponding exactly to the specified .Ar branch . Such changes could first be committed to a different branch with .Cm got commit , or could be discarded with .Cm got revert . .It Fl c Ar commit Update the work tree to the specified .Ar commit . If this option is not specified, the most recent commit on the work tree's branch will be used. .Pp The expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. Keywords and reference names may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent, respectively, by first parent traversal; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foo:-3 will denote the 3rd generation ancestor of the commit resolved by the .Qq foo reference. If an integer does not follow the .Qq :+ or .Qq :- modifier, a .Qq 1 is implicitly appended .Po e.g., .Sy :head:- is equivalent to .Sy :head:-1 .Pc . .It Fl q Silence progress output. .El .Tg st .It Xo .Cm status .Op Fl I .Op Fl S Ar status-codes .Op Fl s Ar status-codes .Op Ar path ... .Xc .Dl Pq alias: Cm st Show the current modification status of files in a work tree, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It D Ta file scheduled for deletion in next commit .It C Ta modified or added file which contains merge conflicts .It ! Ta versioned file was expected on disk but is missing .It \(a~ Ta versioned file is obstructed by a non-regular file .It ? Ta unversioned item not tracked by .Nm .It m Ta modified file modes (executable bit only) .It N Ta non-existent .Ar path specified on the command line .El .Pp If no .Ar path is specified, show modifications in the entire work tree. Otherwise, show modifications at or within the specified paths. .Pp If changes have been staged with .Cm got stage , staged changes are shown in the second output column, using the following status codes: .Bl -column YXZ description .It M Ta file modification is staged .It A Ta file addition is staged .It D Ta file deletion is staged .El .Pp Changes created on top of staged changes are indicated in the first column: .Bl -column YXZ description .It MM Ta file was modified after earlier changes have been staged .It MA Ta file was modified after having been staged for addition .El .Pp If the work tree contains the results of an interrupted .Cm got rebase , .Cm got histedit , or .Cm got merge operation then display a message which shows the branches involved. .Pp The options for .Cm got status are as follows: .Bl -tag -width Ds .It Fl I Show unversioned files even if they match an ignore pattern. See .Sx Ignore Patterns . .It Fl S Ar status-codes Suppress the output of files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl s option. .It Fl s Ar status-codes Only show files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl S option. .El .It Xo .Cm log .Op Fl bdPpRst .Op Fl C Ar number .Op Fl c Ar commit .Op Fl l Ar N .Op Fl r Ar repository-path .Op Fl S Ar search-pattern .Op Fl x Ar commit .Op Ar path .Xc Display history of a repository. If a .Ar path is specified, show only commits which modified this path. If invoked in a work tree, the .Ar path is interpreted relative to the current working directory, and the work tree's path prefix is implicitly prepended. Otherwise, the path is interpreted relative to the repository root. .Pp The options for .Cm got log are as follows: .Bl -tag -width Ds .It Fl b Display individual commits which were merged into the current branch from other branches. By default, .Cm got log shows the linear history of the current branch only. .It Fl C Ar number Set the number of context lines shown in diffs with .Fl p . By default, 3 lines of context are shown. .It Fl c Ar commit Start traversing history at the specified .Ar commit . If this option is not specified, default to the work tree's current branch if invoked in a work tree, or to the repository's HEAD reference. .Pp The expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent, respectively, by first parent traversal; for example, .Sy :head:-2 denotes the HEAD reference's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy bar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq bar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl d Display diffstat of changes introduced in each commit. Cannot be used with the .Fl s option. Implies the .Fl P option (diffstat displays a list of changed paths). .It Fl l Ar N Limit history traversal to a given number of commits. If this option is not specified, a default limit value of zero is used, which is treated as an unbounded limit. The .Ev GOT_LOG_DEFAULT_LIMIT environment variable may be set to change this default value. .It Fl P Display the list of file paths changed in each commit, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Cannot be used with the .Fl s option. .It Fl p Display the patch of modifications made in each commit. If a .Ar path is specified, only show the patch of modifications at or within this path. Cannot be used with the .Fl s option. .It Fl R Determine a set of commits to display as usual, but display these commits in reverse order. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl S Ar search-pattern If specified, show only commits with a log message, author name, committer name, or commit ID matched by the extended regular expression .Ar search-pattern . Lines in committed patches will be matched if .Fl p is specified. File paths changed by a commit will be matched if .Fl P is specified. Regular expression syntax is documented in .Xr re_format 7 . .It Fl s Display a short one-line summary of each commit, instead of the default history format. Cannot be used together with the .Fl p or .Fl P option. .It Fl t Display commits in topological order. This option has no effect without the .Fl b option because a linear history is sorted in topological order by definition. Topological sorting is disabled by default because the present implementation requires that commit history is fully traversed before any output can be shown. .It Fl x Ar commit Stop traversing commit history immediately after the specified .Ar commit has been traversed. Like .Fl c , the expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. This option has no effect if the specified .Ar commit is never traversed. .El .Tg di .It Xo .Cm diff .Op Fl adPsw .Op Fl C Ar number .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar object1 Ar object2 | Ar path ... .Xc .Dl Pq alias: Cm di When invoked within a work tree without any arguments, display all local changes in the work tree. If one or more .Ar path arguments are specified, only show changes within the specified paths. .Pp If two arguments are provided, treat each argument as a reference, a tag name, or an object ID, and display differences between the corresponding objects. Both objects must be of the same type (blobs, trees, or commits). An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. If none of these interpretations produce a valid result or if the .Fl P option is used, and if .Cm got diff is running in a work tree, attempt to interpret the two arguments as paths. .Pp The options for .Cm got diff are as follows: .Bl -tag -width Ds .It Fl a Treat file contents as ASCII text even if binary data is detected. .It Fl C Ar number Set the number of context lines shown in the diff. By default, 3 lines of context are shown. .It Fl c Ar commit Show differences between commits in the repository. This option may be used up to two times. When used only once, show differences between the specified .Ar commit and its first parent commit. When used twice, show differences between the two specified commits. .Pp If the .Fl c option is used, all non-option arguments will be interpreted as paths. If one or more such .Ar path arguments are provided, only show differences for the specified paths. .Pp The expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent, respectively, by first parent traversal; for example, .Sy :head:-2 denotes the HEAD reference's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy baz:+8 will denote the 8th generation descendant of the commit resolved by the .Qq baz reference. If an integer does not follow the .Qq :+ or .Qq :- modifier, a .Qq 1 is implicitly appended .Po e.g., .Sy :head:- is equivalent to .Sy :head:-1 .Pc . .Pp Cannot be used together with the .Fl P option. .It Fl d Display diffstat of changes before the actual diff by annotating each file path or blob hash being diffed with the total number of lines added and removed. A summary line will display the total number of changes across all files. .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Show changes staged with .Cm got stage instead of showing local changes in the work tree. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl w Ignore whitespace-only changes. .El .Tg bl .It Xo .Cm blame .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar path .Xc .Dl Pq alias: Cm bl Display line-by-line history of a file at the specified path. .Pp The options for .Cm got blame are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy xyz:-5 will denote the 5th generation ancestor of the commit resolved by the .Qq xyz reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .Tg tr .It Xo .Cm tree .Op Fl iR .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc .Dl Pq alias: Cm tr Display a listing of files and directories at the specified directory path in the repository. Entries shown in this listing may carry one of the following trailing annotations: .Bl -column YXZ description .It @ Ta entry is a symbolic link .It / Ta entry is a directory .It * Ta entry is an executable file .It $ Ta entry is a Git submodule .El .Pp Symbolic link entries are also annotated with the target path of the link. .Pp If no .Ar path is specified, list the repository path corresponding to the current directory of the work tree, or the root directory of the repository if there is no work tree. .Pp The options for .Cm got tree are as follows: .Bl -tag -width Ds .It Fl c Ar commit List files and directories as they appear in the specified .Ar commit . .Pp The expected argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy spam:-3 will denote the 3rd generation ancestor of the commit resolved by the .Qq spam reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl i Show object IDs of files (blob objects) and directories (tree objects). .It Fl R Recurse into sub-directories in the repository. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Xo .Cm ref .Op Fl dlt .Op Fl c Ar object .Op Fl r Ar repository-path .Op Fl s Ar reference .Op Ar name .Xc Manage references in a repository. .Pp References may be listed, created, deleted, and changed. When creating, deleting, or changing a reference the specified .Ar name must be an absolute reference name, i.e. it must begin with .Dq refs/ . .Pp The options for .Cm got ref are as follows: .Bl -tag -width Ds .It Fl c Ar object Create a reference or change an existing reference. The reference with the specified .Ar name will point at the specified .Ar object . .Pp The expected .Ar object argument is an object ID or an existing reference or tag name or a keyword which will be resolved to the ID of a corresponding commit, tree, tag, or blob object. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and reference names may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy tagged:-3 will denote the 3rd generation ancestor of the commit resolved by the .Qq tagged reference. If an integer does not follow the .Qq :+ or .Qq :- modifier, a .Qq 1 is implicitly appended .Po e.g., .Sy :head:- is equivalent to .Sy :head:-1 .Pc . .Pp Cannot be used together with any other options except .Fl r . .It Fl d Delete the reference with the specified .Ar name from the repository. Any commit, tree, tag, and blob objects belonging to deleted references remain in the repository and may be removed separately with Git's garbage collector or .Cm gotadmin cleanup . Cannot be used together with any other options except .Fl r . .It Fl l List references in the repository. If no .Ar name is specified, list all existing references in the repository. If .Ar name is a reference namespace, list all references in this namespace. Otherwise, show only the reference with the given .Ar name . Cannot be used together with any other options except .Fl r and .Fl t . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Ar reference Create a symbolic reference, or change an existing symbolic reference. The symbolic reference with the specified .Ar name will point at the specified .Ar reference which must already exist in the repository. Care should be taken not to create loops between references when this option is used. Cannot be used together with any other options except .Fl r . .It Fl t Sort listed references by modification time (most recently modified first) instead of sorting by lexicographical order. Use of this option requires the .Fl l option to be used as well. .El .Tg br .It Xo .Cm branch .Op Fl lnt .Op Fl c Ar commit .Op Fl d Ar name .Op Fl r Ar repository-path .Op Ar name .Xc .Dl Pq alias: Cm br Create, list, or delete branches. .Pp Local branches are managed via references which live in the .Dq refs/heads/ reference namespace. The .Cm got branch command creates references in this namespace only. .Pp When deleting branches, the specified .Ar name is searched in the .Dq refs/heads reference namespace first. If no corresponding branch is found, the .Dq refs/remotes namespace will be searched next. .Pp If invoked in a work tree without any arguments, print the name of the work tree's current branch. .Pp If a .Ar name argument is passed, attempt to create a branch reference with the given name. By default the new branch reference will point at the latest commit on the work tree's current branch if invoked in a work tree, and otherwise to a commit resolved via the repository's HEAD reference. .Pp If invoked in a work tree, once the branch was created successfully switch the work tree's head reference to the newly created branch and update files across the entire work tree, just like .Cm got update -b Ar name would do. Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated and contained no local changes .It G Ta file was updated and local changes were merged cleanly .It C Ta file was updated and conflicts occurred during merge .It D Ta file was deleted .It A Ta new file was added .It \(a~ Ta versioned file is obstructed by a non-regular file .It ! Ta a missing versioned file was restored .El .Pp The options for .Cm got branch are as follows: .Bl -tag -width Ds .It Fl c Ar commit Make a newly created branch reference point at the specified .Ar commit . The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl d Ar name Delete the branch with the specified .Ar name from the .Dq refs/heads or .Dq refs/remotes reference namespace. .Pp Only the branch reference is deleted. Any commit, tree, and blob objects belonging to the branch remain in the repository and may be removed separately with Git's garbage collector or .Cm gotadmin cleanup . .It Fl l List all existing branches in the repository, including copies of remote repositories' branches in the .Dq refs/remotes/ reference namespace. .Pp If invoked in a work tree, the work tree's current branch is shown with one of the following annotations: .Bl -column YXZ description .It * Ta work tree's base commit and the base commit of all tracked files matches the branch tip .It \(a~ Ta work tree comprises mixed commits or its base commit is out-of-date .El .It Fl n Do not switch and update the work tree after creating a new branch. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl t Sort listed branches by modification time (most recently modified first) instead of sorting by lexicographical order. Branches in the .Dq refs/heads/ reference namespace are listed before branches in .Dq refs/remotes/ regardless. Use of this option requires the .Fl l option to be used as well. .El .It Xo .Cm tag .Op Fl lsVv .Op Fl c Ar commit .Op Fl m Ar message .Op Fl r Ar repository-path .Op Fl S Ar signer-id .Ar name .Xc Manage tags in a repository. .Pp Tags are managed via references which live in the .Dq refs/tags/ reference namespace. The .Cm got tag command operates on references in this namespace only. References in this namespace point at tag objects which contain a pointer to another object, a tag message, as well as author and timestamp information. .Pp Attempt to create a tag with the given .Ar name , and make this tag point at the given .Ar commit . If no commit is specified, default to the latest commit on the work tree's current branch if invoked in a work tree, and to a commit resolved via the repository's HEAD reference otherwise. .Pp The options for .Cm got tag are as follows: .Bl -tag -width Ds .It Fl c Ar commit Make the newly created tag reference point at the specified .Ar commit . The expected .Ar commit argument is a commit ID, or a reference or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy eggs:-3 will denote the 3rd generation ancestor of the commit resolved by the .Qq eggs reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl l List all existing tags in the repository instead of creating a new tag. If a .Ar name argument is passed, show only the tag with the given .Ar name . .It Fl m Ar message Use the specified tag message when creating the new tag. Without the .Fl m option, .Cm got tag opens a temporary file in an editor where a tag message can be written. Quitting the editor without saving the file will abort the tag operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl S Ar signer-id While creating a new tag, sign this tag with the identity given in .Ar signer-id . .Pp For SSH-based signatures, .Ar signer-id is the path to a file which may refer to either a private SSH key, or a public SSH key with the private half available via .Xr ssh-agent 1 . .Cm got tag will sign the tag object by invoking .Xr ssh-keygen 1 with the .Fl Y Cm sign command, using the signature namespace .Dq git for compatibility with .Xr git 1 . .It Fl s Display a short one-line summary of each tag, instead of the default history format. Can only be used with the .Fl l option. .It Fl V Verify tag object signatures. If a .Ar name is specified, show and verify the tag object with the provided name. Otherwise, list all tag objects and verify signatures where present. .Pp .Cm got tag verifies SSH-based signatures by invoking .Xr ssh-keygen 1 with the options .Fl Y Cm verify Fl f Ar allowed_signers . A path to the .Ar allowed_signers file must be set in .Xr got.conf 5 , otherwise verification is impossible. .It Fl v Verbose mode. During SSH signature creation and verification this option will be passed to .Xr ssh-keygen 1 . Multiple -v options increase the verbosity. The maximum is 3. .El .Pp By design, the .Cm got tag command will not delete tags or change existing tags. If a tag must be deleted, the .Cm got ref command may be used to delete a tag's reference. This should only be done if the tag has not already been copied to another repository. .It Xo .Cm add .Op Fl IR .Ar path ... .Xc Schedule unversioned files in a work tree for addition to the repository in the next commit. By default, files which match an ignore pattern will not be added. See .Sx Ignore Patterns . .Pp If a .Ar path mentioned in the command line is not an unversioned file then .Cm got add may raise an error. To avoid unnecessary errors from paths picked up by file globbing patterns in the shell, paths in the argument list will be silently ignored if they are not reported by .Cm got status at all, or if they are reported with one of the following status codes and do not have changes staged via .Cm got stage : .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It C Ta modified or added file which contains merge conflicts .It m Ta modified file modes (executable bit only) .El .Pp The options for .Cm got add are as follows: .Bl -tag -width Ds .It Fl I Add files even if they match an ignore pattern. See .Xs Ignore Patterns . .It Fl R Permit recursion into directories. If this option is not specified, .Cm got add will refuse to run if a specified .Ar path is a directory. .El .Tg rm .It Xo .Cm remove .Op Fl fkR .Op Fl s Ar status-codes .Ar path ... .Xc .Dl Pq alias: Cm rm Remove versioned files from a work tree and schedule them for deletion from the repository in the next commit. .Pp The options for .Cm got remove are as follows: .Bl -tag -width Ds .It Fl f Perform the operation even if a file contains local modifications, and do not raise an error if a specified .Ar path does not exist on disk. .It Fl k Keep affected files on disk. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got remove will refuse to run if a specified .Ar path is a directory. .It Fl s Ar status-codes Only delete files with a modification status matching one of the single-character status codes contained in the .Ar status-codes argument. The following status codes may be specified: .Bl -column YXZ description .It M Ta modified file (this implies the .Fl f option) .It ! Ta versioned file expected on disk but missing .El .El .Tg pa .It Xo .Cm patch .Op Fl nR .Op Fl c Ar commit .Op Fl p Ar strip-count .Op Ar patchfile .Xc .Dl Pq alias: Cm pa Apply changes from .Ar patchfile to files in a work tree. Files added or removed by a patch will be scheduled for addition or removal in the work tree. .Pp The patch must be in the unified diff format as produced by .Cm got diff , .Xr git-diff 1 , or by .Xr diff 1 and .Xr cvs 1 diff when invoked with their .Fl u options. If no .Ar patchfile argument is provided, read unified diff data from standard input instead. .Pp If the .Ar patchfile contains multiple patches, then attempt to apply each of them in sequence. .Pp Show the status of each affected file, using the following status codes: .Bl -column XYZ description .It M Ta file was modified .It G Ta file was merged using a merge-base found in the repository .It C Ta file was merged and conflicts occurred during merge .It D Ta file was deleted .It A Ta file was added .It # Ta failed to patch the file .El .Pp If a change does not match at its exact line number, attempt to apply it somewhere else in the file if a good spot can be found. Otherwise, the patch will fail to apply. .Pp .Nm .Cm patch will refuse to apply a patch if certain preconditions are not met. Files to be deleted must already be under version control, and must not have been scheduled for deletion already. Files to be added must not yet be under version control and must not already be present on disk. Files to be modified must already be under version control and may not contain conflict markers. .Pp If an error occurs, the .Cm patch operation will be aborted. Any changes made to the work tree up to this point will be left behind. Such changes can be viewed with .Cm got diff and can be reverted with .Cm got revert if needed. .Pp The options for .Cm got patch are as follows: .Bl -tag -width Ds .It Fl c Ar commit Attempt to locate files within the specified .Ar commit for use as a merge-base for 3-way merges. .Pp If the .Fl c option is not used then .Cm got patch will attempt to locate merge-bases via object IDs found in .Ar patchfile meta-data, such as produced by .Cm got diff or .Xr git-diff 1 . Use of the .Fl c option is only recommended in the absence of such meta-data. .Pp Ideally, the specified .Ar commit should contain versions of files which the changes contained in the .Ar patchfile were based on. Files will be located by path, relative to the repository root. If the .Fl p option is used then leading path components will be stripped before paths are looked up in the repository. .Pp In case no merge-base is available for a file, changes will be applied without doing a 3-way merge. Changes which do not apply cleanly may then be rejected entirely, rather than producing merge conflicts in the patched target file. .Pp The expected .Ar commit argument is a commit ID, or a reference name or a keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy flan:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq flan reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl n Do not make any modifications to the work tree. This can be used to check whether a patch would apply without issues. If the .Ar patchfile contains diffs that affect the same file multiple times, the results displayed may be incorrect. .It Fl p Ar strip-count Specify the number of leading path components to strip from paths parsed from .Ar patchfile . If the .Fl p option is not used, .Sq a/ and .Sq b/ path prefixes generated by .Xr git-diff 1 will be recognized and stripped automatically. .It Fl R Reverse the patch before applying it. .El .Tg rv .It Xo .Cm revert .Op Fl pR .Op Fl F Ar response-script .Ar path ... .Xc .Dl Pq alias: Cm rv Revert any local changes in files at the specified paths in a work tree. File contents will be overwritten with those contained in the work tree's base commit. There is no way to bring discarded changes back after .Cm got revert ! .Pp If a file was added with .Cm got add , it will become an unversioned file again. If a file was deleted with .Cm got remove , it will be restored. .Pp The options for .Cm got revert are as follows: .Bl -tag -width Ds .It Fl F Ar response-script With the .Fl p option, read .Dq y , .Dq n , and .Dq q responses line-by-line from the specified .Ar response-script file instead of prompting interactively. .It Fl p Instead of reverting all changes in files, interactively select or reject changes to revert based on .Dq y (revert change), .Dq n (keep change), and .Dq q (quit reverting this file) responses. If a file is in modified status, individual patches derived from the modified file content can be reverted. Files in added or deleted status may only be reverted in their entirety. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got revert will refuse to run if a specified .Ar path is a directory. .El .Tg ci .It Xo .Cm commit .Op Fl CNnS .Op Fl A Ar author .Op Fl F Ar path .Op Fl m Ar message .Op Ar path ... .Xc .Dl Pq alias: Cm ci Create a new commit in the repository from changes in a work tree and use this commit as the new base commit for the work tree. If no .Ar path is specified, commit all changes in the work tree. Otherwise, commit changes at or within the specified paths. .Pp If changes have been explicitly staged for commit with .Cm got stage , only commit staged changes and reject any specified paths which have not been staged. .Pp .Cm got commit opens a temporary file in an editor where a log message can be written unless the .Fl m option is used or the .Fl F and .Fl N options are used together. Quitting the editor without saving the file will abort the commit operation. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Files which are not part of the new commit will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. .Pp The .Cm got commit command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got commit are as follows: .Bl -tag -width Ds .It Fl A Ar author Set author information in the newly created commit to .Ar author . This is useful when committing changes on behalf of someone else. The .Ar author argument must use the same format as the .Ev GOT_AUTHOR environment variable. .Pp In addition to storing author information, the newly created commit object will retain .Dq committer information which is obtained, as usual, from the .Ev GOT_AUTHOR environment variable, or .Xr got.conf 5 , or Git configuration settings. .It Fl C Allow committing files in conflicted status. .Pp Committing files with conflict markers should generally be avoided. Cases where conflict markers must be stored in the repository for some legitimate reason should be very rare. There are usually ways to avoid storing conflict markers verbatim by applying appropriate programming tricks. .It Fl F Ar path Use the prepared log message stored in the file found at .Ar path when creating the new commit. .Cm got commit opens a temporary file in an editor where the prepared log message can be reviewed and edited further if needed. Cannot be used together with the .Fl m option. .It Fl m Ar message Use the specified log message when creating the new commit. Cannot be used together with the .Fl F option. .It Fl N This option prevents .Cm got commit from opening the commit message in an editor. It has no effect unless it is used together with the .Fl F option and is intended for non-interactive use such as scripting. .It Fl n This option prevents .Cm got commit from generating a diff of the to-be-committed changes in a temporary file which can be viewed while editing a commit message. .It Fl S Allow the addition of symbolic links which point outside of the path space that is under version control. By default, .Cm got commit will reject such symbolic links due to safety concerns. As a precaution, .Nm may decide to represent such a symbolic link as a regular file which contains the link's target path, rather than creating an actual symbolic link which points outside of the work tree. Use of this option is discouraged because external mechanisms such as .Dq make obj are better suited for managing symbolic links to paths not under version control. .El .Pp .Cm got commit will refuse to run if certain preconditions are not met. If the work tree's current branch is not in the .Dq refs/heads/ reference namespace, new commits may not be created on this branch. Local changes may only be committed if they are based on file content found in the most recent commit on the work tree's branch. If a path is found to be out of date, .Cm got update must be used first in order to merge local changes with changes made in the repository. .Tg se .It Xo .Cm send .Op Fl afqTv .Op Fl b Ar branch .Op Fl d Ar branch .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Fl r Ar repository-path .Op Fl t Ar tag .Op Ar remote-repository .Xc .Dl Pq alias: Cm se Send new changes to a remote repository. If no .Ar remote-repository is specified, .Dq origin will be used. The remote repository's URL is obtained from the corresponding entry in .Xr got.conf 5 or Git's .Pa config file of the local repository, as created by .Cm got clone . .Pp All objects corresponding to new changes will be written to a temporary pack file which is then uploaded to the server. Upon success, references in the .Dq refs/remotes/ reference namespace of the local repository will be updated to point at the commits which have been sent. .Pp By default, changes will only be sent if they are based on up-to-date copies of relevant branches in the remote repository. If any changes to be sent are based on out-of-date copies or would otherwise break linear history of existing branches, new changes must be fetched from the server with .Cm got fetch and local branches must be rebased with .Cm got rebase before .Cm got send can succeed. The .Fl f option can be used to make exceptions to these requirements. .Pp The options for .Cm got send are as follows: .Bl -tag -width Ds .It Fl a Send all branches from the local repository's .Dq refs/heads/ reference namespace. The .Fl a option is equivalent to listing all branches with multiple .Fl b options. Cannot be used together with the .Fl b option. .It Fl b Ar branch Send the specified .Ar branch from the local repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to send. If this option is not specified, default to the work tree's current branch if invoked in a work tree, or to the repository's HEAD reference. Cannot be used together with the .Fl a option. .It Fl d Ar branch Delete the specified .Ar branch from the remote repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to delete. .Pp Only references are deleted. Any commit, tree, tag, and blob objects belonging to deleted branches may become subject to deletion by Git's garbage collector running on the server. .Pp Requesting deletion of branches results in an error if the server does not support this feature or disallows the deletion of branches based on its configuration. .It Fl f Attempt to force the server to overwrite existing branches or tags in the remote repository, even when .Cm got fetch followed by .Cm got rebase or .Cm got merge would usually be required before changes can be sent. The server may reject forced requests regardless, depending on its configuration. .Pp Any commit, tree, tag, and blob objects belonging to overwritten branches or tags may become subject to deletion by Git's garbage collector running on the server. .Pp The .Dq refs/tags reference namespace is globally shared between all repositories. Use of the .Fl f option to overwrite tags is discouraged because it can lead to inconsistencies between the tags present in different repositories. In general, creating a new tag with a different name is recommended instead of overwriting an existing tag. .Pp Use of the .Fl f option is particularly discouraged if changes being sent are based on an out-of-date copy of a branch in the remote repository. Instead of using the .Fl f option, new changes should be fetched with .Cm got fetch and local branches should be rebased with .Cm got rebase or merged with .Cm got merge , followed by another attempt to send the changes. .Pp The .Fl f option should only be needed in situations where the remote repository's copy of a branch or tag is known to be out-of-date and is considered disposable. The risks of creating inconsistencies between different repositories should also be taken into account. .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl q Suppress progress reporting output. The same option will be passed to .Xr ssh 1 if applicable. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl T Attempt to send all tags from the local repository's .Dq refs/tags/ reference namespace. The .Fl T option is equivalent to listing all tags with multiple .Fl t options. Cannot be used together with the .Fl t option. .It Fl t Ar tag Send the specified .Ar tag from the local repository's .Dq refs/tags/ reference namespace, in addition to any branches that are being sent. The .Fl t option may be specified multiple times to build a list of tags to send. No tags will be sent if the .Fl t option is not used. .Pp Raise an error if the specified .Ar tag already exists in the remote repository, unless the .Fl f option is used to overwrite the server's copy of the tag. In general, creating a new tag with a different name is recommended instead of overwriting an existing tag. .Pp Cannot be used together with the .Fl T option. .It Fl v Verbose mode. Causes .Cm got send to print debugging messages to standard error output. The same option will be passed to .Xr ssh 1 if applicable. Multiple -v options increase the verbosity. The maximum is 3. .El .Tg cy .It Xo .Cm cherrypick .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm cy Merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on a different branch than the work tree's base commit. .Pp The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy barbaz:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq barbaz reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got cherrypick commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got cherrypick creates a record of commits which have been merged into the work tree. When a file changed by .Cm got cherrypick is committed with .Cm got commit , the log messages of relevant merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for cherrypicking the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got cherrypick will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm cherrypick are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .Pp .Tg bo .It Xo .Cm backout .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm bo Reverse-merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on the same branch as the work tree's base commit. .Pp The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy wip:+5 will denote the 5th generation descendant of the commit resolved by the .Qq wip reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The reverse-merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got backout commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got backout creates a record of commits which have been reverse-merged into the work tree. When a file changed by .Cm got backout is committed with .Cm got commit , the log messages of relevant reverse-merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for backing out the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got backout will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm backout are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .Pp .Tg rb .It Xo .Cm rebase .Op Fl aCclX .Op Ar branch .Xc .Dl Pq alias: Cm rb Rebase commits on the specified .Ar branch onto the tip of the current branch of the work tree. The .Ar branch must share common ancestry with the work tree's current branch. Rebasing begins with the first descendant commit of the youngest common ancestor commit shared by the specified .Ar branch and the work tree's current branch, and stops once the tip commit of the specified .Ar branch has been rebased. .Pp When .Cm got rebase is used as intended, the specified .Ar branch represents a local commit history and may already contain changes that are not yet visible in any other repositories. The work tree's current branch, which must be set with .Cm got update -b before starting the .Cm rebase operation, represents a branch from a remote repository which shares a common history with the specified .Ar branch but has progressed, and perhaps diverged, due to commits added to the remote repository. .Pp Rebased commits are accumulated on a temporary branch which the work tree will remain switched to throughout the entire rebase operation. Commits on this branch represent the same changes with the same log messages as their counterparts on the original .Ar branch , but with different commit IDs. Once rebasing has completed successfully, the temporary branch becomes the new version of the specified .Ar branch and the work tree is automatically switched to it. If author information is available via the .Ev GOT_AUTHOR environment variable, .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings, this author information will be used to identify the .Dq committer of rebased commits. .Pp Old commits in their pre-rebase state are automatically backed up in the .Dq refs/got/backup/rebase reference namespace. As long as these references are not removed older versions of rebased commits will remain in the repository and can be viewed with the .Cm got rebase -l command. Removal of these references makes objects which become unreachable via any reference subject to removal by Git's garbage collector or .Cm gotadmin cleanup . .Pp While rebasing commits, show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp If merge conflicts occur, the rebase operation is interrupted and may be continued once conflicts have been resolved. If any files with destined changes are found to be missing or unversioned, or if files could not be deleted due to differences in deleted content, the rebase operation will be interrupted to prevent potentially incomplete changes from being committed to the repository without user intervention. The work tree may be modified as desired and the rebase operation can be continued once the changes present in the work tree are considered complete. Alternatively, the rebase operation may be aborted which will leave .Ar branch unmodified and the work tree switched back to its original branch. .Pp If a merge conflict is resolved in a way which renders the merged change into a no-op change, the corresponding commit will be elided when the rebase operation continues. .Pp .Cm got rebase will refuse to run if certain preconditions are not met. If the .Ar branch is not in the .Dq refs/heads/ reference namespace, the branch may not be rebased. If the work tree is not yet fully updated to the tip commit of its branch, then the work tree must first be updated with .Cm got update . If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . If the work tree contains local changes, these changes must first be committed with .Cm got commit or reverted with .Cm got revert . If the .Ar branch contains changes to files outside of the work tree's path prefix, the work tree cannot be used to rebase this branch. .Pp The .Cm got update , .Cm got integrate , .Cm got merge , .Cm got commit , and .Cm got histedit commands will refuse to run while a rebase operation is in progress. Other commands which manipulate the work tree may be used for conflict resolution purposes. .Pp If the specified .Ar branch is already based on the work tree's current branch, then no commits need to be rebased and .Cm got rebase will simply switch the work tree to the specified .Ar branch and update files in the work tree accordingly. .Pp The options for .Cm got rebase are as follows: .Bl -tag -width Ds .It Fl a Abort an interrupted rebase operation. If this option is used, no other command-line arguments are allowed. .It Fl C Allow a rebase operation to continue with files in conflicted status. This option should generally be avoided, and can only be used with the .Fl c option. .It Fl c Continue an interrupted rebase operation. If this option is used, no other command-line arguments are allowed except .Fl C . .It Fl l Show a list of past rebase operations, represented by references in the .Dq refs/got/backup/rebase reference namespace. .Pp Display the author, date, and log message of each backed up commit, the object ID of the corresponding post-rebase commit, and the object ID of their common ancestor commit. Given these object IDs, the .Cm got log command with the .Fl c and .Fl x options can be used to examine the history of either version of the branch, and the .Cm got branch command with the .Fl c option can be used to create a new branch from a pre-rebase state if desired. .Pp If a .Ar branch is specified, only show commits which at some point in time represented this branch. Otherwise, list all backed up commits for any branches. .Pp If this option is used, .Cm got rebase does not require a work tree. None of the other options can be used together with .Fl l . .It Fl X Delete backups created by past rebase operations, represented by references in the .Dq refs/got/backup/rebase reference namespace. .Pp If a .Ar branch is specified, only delete backups which at some point in time represented this branch. Otherwise, delete all references found within .Dq refs/got/backup/rebase . .Pp Any commit, tree, tag, and blob objects belonging to deleted backups remain in the repository and may be removed separately with Git's garbage collector or .Cm gotadmin cleanup . .Pp If this option is used, .Cm got rebase does not require a work tree. None of the other options can be used together with .Fl X . .El .Tg he .It Xo .Cm histedit .Op Fl aCcdeflmX .Op Fl F Ar histedit-script .Op Ar branch .Xc .Dl Pq alias: Cm he Edit commit history between the work tree's current base commit and the tip commit of the work tree's current branch. .Pp The .Cm got histedit command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp Before starting a .Cm histedit operation, the work tree's current branch must be set with .Cm got update -b to the branch which should be edited, unless this branch is already the current branch of the work tree. The tip of this branch represents the upper bound (inclusive) of commits touched by the .Cm histedit operation. .Pp Furthermore, the work tree's base commit must be set with .Cm got update -c to a point in this branch's commit history where editing should begin. This commit represents the lower bound (non-inclusive) of commits touched by the .Cm histedit operation. .Pp Editing of commit history is controlled via a .Ar histedit script which can be written in an editor based on a template, passed on the command line, or generated with the .Fl d , .Fl e , .Fl f , or .Fl m options. Quitting the editor without saving the file will abort the histedit operation. .Pp The format of the histedit script is line-based. Each line in the script begins with a command name, followed by whitespace and an argument. For most commands, the expected argument is a commit ID. Any remaining text on the line is ignored. Lines which begin with the .Sq # character are ignored entirely. .Pp The available histedit script commands are as follows: .Bl -column YXZ pick-commit .It Cm pick Ar commit Ta Use the specified commit as it is. .It Cm edit Ar commit Ta Apply the changes from the specified commit, but then interrupt the histedit operation for amending, without creating a commit. While the histedit operation is interrupted arbitrary files may be edited, and commands which manipulate the work tree can be used freely. The .Cm got add and .Cm got remove commands can be used to add new files or remove existing ones. The .Cm got revert -p command can be used to eliminate arbitrary changes from files in the work tree. The .Cm got stage -p command may be used to prepare a subset of changes for inclusion in the next commit. Finally, the .Cm got commit command can be used to insert arbitrary commits into the edited history. Regular editing of history must eventually be resumed by running .Cm got histedit -c . .It Cm fold Ar commit Ta Combine the specified commit with the next commit listed further below that will be used. .It Cm drop Ar commit Ta Remove this commit from the edited history. .It Cm mesg Ar commit Ta Open an editor to create a new log message for this commit. .El .Pp Every commit in the history being edited must be mentioned in the script. Lines may be re-ordered to change the order of commits in the edited history. No commit may be listed more than once. .Pp Edited commits are accumulated on a temporary branch which the work tree will remain switched to throughout the entire histedit operation. Once history editing has completed successfully, the temporary branch becomes the new version of the work tree's branch and the work tree is automatically switched to it. .Pp Old commits in their pre-histedit state are automatically backed up in the .Dq refs/got/backup/histedit reference namespace. As long as these references are not removed older versions of edited commits will remain in the repository and can be viewed with the .Cm got histedit -l command. Removal of these references makes objects which become unreachable via any reference subject to removal by Git's garbage collector or .Cm gotadmin cleanup . .Pp While merging commits, show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp If merge conflicts occur, the histedit operation is interrupted and may be continued once conflicts have been resolved. If any files with destined changes are found to be missing or unversioned, or if files could not be deleted due to differences in deleted content, the histedit operation will be interrupted to prevent potentially incomplete changes from being committed to the repository without user intervention. The work tree may be modified as desired and the histedit operation can be continued once the changes present in the work tree are considered complete. Alternatively, the histedit operation may be aborted which will leave the work tree switched back to its original branch. .Pp If a merge conflict is resolved in a way which renders the merged change into a no-op change, the corresponding commit will be elided when the histedit operation continues. .Pp .Cm got histedit will refuse to run if certain preconditions are not met. If the work tree's current branch is not in the .Dq refs/heads/ reference namespace, the history of the branch may not be edited. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . If the work tree contains local changes, these changes must first be committed with .Cm got commit or reverted with .Cm got revert . If the edited history contains changes to files outside of the work tree's path prefix, the work tree cannot be used to edit the history of this branch. .Pp The .Cm got update , .Cm got rebase , .Cm got merge , and .Cm got integrate commands will refuse to run while a histedit operation is in progress. Other commands which manipulate the work tree may be used, and the .Cm got commit command may be used to commit arbitrary changes to the temporary branch while the histedit operation is interrupted. .Pp The options for .Cm got histedit are as follows: .Bl -tag -width Ds .It Fl a Abort an interrupted histedit operation. If this option is used, no other command-line arguments are allowed. .It Fl C Allow a histedit operation to continue with files in conflicted status. This option should generally be avoided, and can only be used with the .Fl c option. .It Fl c Continue an interrupted histedit operation. If this option is used, no other command-line arguments are allowed except .Fl C . .It Fl d Drop all commits. This option is a quick equivalent to a histedit script which drops all commits. The .Fl d option can only be used when starting a new histedit operation. If this option is used, no other command-line arguments are allowed. .It Fl e Interrupt the histedit operation for editing after merging each commit. This option is a quick equivalent to a histedit script which uses the .Cm edit command for all commits. The .Fl e option can only be used when starting a new histedit operation. If this option is used, no other command-line arguments are allowed. .It Fl F Ar histedit-script Use the specified .Ar histedit-script instead of opening a temporary file in an editor where a histedit script can be written. .It Fl f Fold all commits into a single commit. This option is a quick equivalent to a histedit script which folds all commits, combining them all into one commit. The .Fl f option can only be used when starting a new histedit operation. If this option is used, no other command-line arguments are allowed. .It Fl l Show a list of past histedit operations, represented by references in the .Dq refs/got/backup/histedit reference namespace. .Pp Display the author, date, and log message of each backed up commit, the object ID of the corresponding post-histedit commit, and the object ID of their common ancestor commit. Given these object IDs, the .Cm got log command with the .Fl c and .Fl x options can be used to examine the history of either version of the branch, and the .Cm got branch command with the .Fl c option can be used to create a new branch from a pre-histedit state if desired. .Pp If a .Ar branch is specified, only show commits which at some point in time represented this branch. Otherwise, list all backed up commits for any branches. .Pp If this option is used, .Cm got histedit does not require a work tree. None of the other options can be used together with .Fl l . .It Fl m Edit log messages only. This option is a quick equivalent to a histedit script which edits only log messages but otherwise leaves every picked commit as-is. The .Fl m option can only be used when starting a new histedit operation. If this option is used, no other command-line arguments are allowed. .It Fl X Delete backups created by past histedit operations, represented by references in the .Dq refs/got/backup/histedit reference namespace. .Pp If a .Ar branch is specified, only delete backups which at some point in time represented this branch. Otherwise, delete all references found within .Dq refs/got/backup/histedit . .Pp Any commit, tree, tag, and blob objects belonging to deleted backups remain in the repository and may be removed separately with Git's garbage collector or .Cm gotadmin cleanup . .Pp If this option is used, .Cm got histedit does not require a work tree. None of the other options can be used together with .Fl X . .El .Tg ig .It Cm integrate Ar branch .Dl Pq alias: Cm ig Integrate the specified .Ar branch into the work tree's current branch. Files in the work tree are updated to match the contents on the integrated .Ar branch , and the reference of the work tree's branch is changed to point at the head commit of the integrated .Ar branch . .Pp Both branches can be considered equivalent after integration since they will be pointing at the same commit. Both branches remain available for future work, if desired. In case the integrated .Ar branch is no longer needed it may be deleted with .Cm got branch -d . .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated .It D Ta file was deleted .It A Ta new file was added .It \(a~ Ta versioned file is obstructed by a non-regular file .It ! Ta a missing versioned file was restored .El .Pp .Cm got integrate will refuse to run if certain preconditions are not met. Most importantly, the .Ar branch must have been rebased onto the work tree's current branch with .Cm got rebase before it can be integrated, in order to linearize commit history and resolve merge conflicts. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . If the work tree contains local changes, these changes must first be committed with .Cm got commit or reverted with .Cm got revert . .Tg mg .It Xo .Cm merge .Op Fl aCcMn .Op Ar branch .Xc .Dl Pq alias: Cm mg Merge the specified .Ar branch into the current branch of the work tree. If the branches have diverged, merge changes into the work tree and create a merge commit. Otherwise, if the specified .Ar branch is already based on the work tree's current branch, make the work tree's current branch equivalent to the specified .Ar branch and update files in the work tree accordingly. .Pp Merge commits are commits based on multiple parent commits. The tip commit of the work tree's current branch will be used as the first parent. The tip commit of the specified .Ar branch will be used as the second parent. The work tree's current branch must be in the .Dq refs/heads/ reference namespace and can be set with .Cm got update -b before starting the .Cm merge operation. .Pp No ancestral relationship between the two branches is required. If the two branches have already been merged previously, only new changes will be merged. .Pp It is not possible to create merge commits with more than two parents. If more than one branch needs to be merged, then multiple merge commits with two parents each can be created in sequence. .Pp If a linear project history is desired, then use of .Cm got rebase should generally be preferred over .Cm got merge . However, even strictly linear projects may require occasional merge commits, for example in order to merge in new versions of third-party code stored on .Dq vendor branches created with .Cm got import . .Pp While merging changes found on the .Ar branch into the work tree, show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp If merge conflicts occur, the merge operation is interrupted and conflicts must be resolved before the merge operation can continue. If any files with destined changes are found to be missing or unversioned, or if files could not be deleted due to differences in deleted content, the merge operation will be interrupted to prevent potentially incomplete changes from being committed to the repository without user intervention. The work tree may be modified as desired and the merge can be continued once the changes present in the work tree are considered complete. Alternatively, the merge operation may be aborted which will leave the work tree's current branch unmodified. .Pp .Cm got merge will refuse to run if certain preconditions are not met. If the work tree's current branch is not in the .Dq refs/heads/ reference namespace then the work tree must first be switched to a branch in the .Dq refs/heads/ namespace with .Cm got update -b . If the work tree is not yet fully updated to the tip commit of its branch, then the work tree must first be updated with .Cm got update . If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . If the work tree contains local changes, these changes must first be committed with .Cm got commit or reverted with .Cm got revert . If the .Ar branch contains changes to files outside of the work tree's path prefix, the work tree cannot be used to merge this branch. .Pp The .Cm got update , .Cm got commit , .Cm got rebase , .Cm got histedit , .Cm got integrate , and .Cm got stage commands will refuse to run while a merge operation is in progress. Other commands which manipulate the work tree may be used for conflict resolution purposes. .Pp The options for .Cm got merge are as follows: .Bl -tag -width Ds .It Fl a Abort an interrupted merge operation. If this option is used, no other command-line arguments are allowed. .It Fl C Allow a merge operation to continue with files in conflicted status. This option should generally be avoided, and can only be used with the .Fl c option. .It Fl c Continue an interrupted merge operation. If this option is used, no other command-line arguments are allowed except .Fl C . .It Fl M Create a merge commit even if the branches have not diverged. .It Fl n Merge changes into the work tree as usual but do not create a merge commit immediately. The merge result can be adjusted as desired before a merge commit is created with .Cm got merge -c . Alternatively, the merge may be aborted with .Cm got merge -a . .El .Tg sg .It Xo .Cm stage .Op Fl lpS .Op Fl F Ar response-script .Op Ar path ... .Xc .Dl Pq alias: Cm sg Stage local changes for inclusion in the next commit. If no .Ar path is specified, stage all changes in the work tree. Otherwise, stage changes at or within the specified paths. Paths may be staged if they are added, modified, or deleted according to .Cm got status . .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It A Ta file addition has been staged .It M Ta file modification has been staged .It D Ta file deletion has been staged .El .Pp Staged file contents are saved in newly created blob objects in the repository. These blobs will be referred to by tree objects once staged changes have been committed. .Pp Staged changes affect the behaviour of .Cm got commit , .Cm got status , and .Cm got diff . While paths with staged changes exist, the .Cm got commit command will refuse to commit any paths which do not have staged changes. Local changes created on top of staged changes can only be committed if the path is staged again, or if the staged changes are committed first. The .Cm got status command will show both local changes and staged changes. The .Cm got diff command is able to display local changes relative to staged changes, and to display staged changes relative to the repository. The .Cm got revert command cannot revert staged changes but may be used to revert local changes created on top of staged changes. .Pp The options for .Cm got stage are as follows: .Bl -tag -width Ds .It Fl F Ar response-script With the .Fl p option, read .Dq y , .Dq n , and .Dq q responses line-by-line from the specified .Ar response-script file instead of prompting interactively. .It Fl l Instead of staging new changes, list paths which are already staged, along with the IDs of staged blob objects and stage status codes. If paths were provided on the command line, show the staged paths among the specified paths. Otherwise, show all staged paths. .It Fl p Instead of staging the entire content of a changed file, interactively select or reject changes for staging based on .Dq y (stage change), .Dq n (reject change), and .Dq q (quit staging this file) responses. If a file is in modified status, individual patches derived from the modified file content can be staged. Files in added or deleted status may only be staged or rejected in their entirety. .It Fl S Allow staging of symbolic links which point outside of the path space that is under version control. By default, .Cm got stage will reject such symbolic links due to safety concerns. As a precaution, .Nm may decide to represent such a symbolic link as a regular file which contains the link's target path, rather than creating an actual symbolic link which points outside of the work tree. Use of this option is discouraged because external mechanisms such as .Dq make obj are better suited for managing symbolic links to paths not under version control. .El .Pp .Cm got stage will refuse to run if certain preconditions are not met. If a file contains merge conflicts, these conflicts must be resolved first. If a file is found to be out of date relative to the head commit on the work tree's current branch, the file must be updated with .Cm got update before it can be staged (however, this does not prevent the file from becoming out-of-date at some point after having been staged). .Pp The .Cm got update , .Cm got rebase , .Cm got merge , and .Cm got histedit commands will refuse to run while staged changes exist. If staged changes cannot be committed because a staged path is out of date, the path must be unstaged with .Cm got unstage before it can be updated with .Cm got update , and may then be staged again if necessary. .Tg ug .It Xo .Cm unstage .Op Fl p .Op Fl F Ar response-script .Op Ar path ... .Xc .Dl Pq alias: Cm ug Merge staged changes back into the work tree and put affected paths back into non-staged status. If no .Ar path is specified, unstage all staged changes across the entire work tree. Otherwise, unstage changes at or within the specified paths. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was unstaged .It C Ta file was unstaged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was staged as deleted and still is deleted .It d Ta file's deletion was prevented by local modifications .It \(a~ Ta changes destined for a non-regular file were not merged .El .Pp The options for .Cm got unstage are as follows: .Bl -tag -width Ds .It Fl F Ar response-script With the .Fl p option, read .Dq y , .Dq n , and .Dq q responses line-by-line from the specified .Ar response-script file instead of prompting interactively. .It Fl p Instead of unstaging the entire content of a changed file, interactively select or reject changes for unstaging based on .Dq y (unstage change), .Dq n (keep change staged), and .Dq q (quit unstaging this file) responses. If a file is staged in modified status, individual patches derived from the staged file content can be unstaged. Files staged in added or deleted status may only be unstaged in their entirety. .El .It Xo .Cm cat .Op Fl P .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar arg ... .Xc Parse and print contents of objects to standard output in a line-based text format. Content of commit, tree, and tag objects is printed in a way similar to the actual content stored in such objects. Blob object contents are printed as they would appear in files on disk. .Pp Attempt to interpret each argument as a reference, a tag name, or an object ID. References will be resolved to an object ID. Tag names will resolved to a tag object. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. .Pp If none of the above interpretations produce a valid result, or if the .Fl P option is used, attempt to interpret the argument as a path which will be resolved to the ID of an object found at this path in the repository. .Pp The options for .Cm got cat are as follows: .Bl -tag -width Ds .It Fl c Ar commit Look up paths in the specified .Ar commit . If this option is not used, paths are looked up in the commit resolved via the repository's HEAD reference. .Pp The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy quux:-8 will denote the 8th generation ancestor of the commit resolved by the .Qq quux reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Cm info Op Ar path ... Display meta-data stored in a work tree. See .Xr got-worktree 5 for details. .Pp The work tree to use is resolved implicitly by walking upwards from the current working directory. .Pp If one or more .Ar path arguments are specified, show additional per-file information for tracked files located at or within these paths. If a .Ar path argument corresponds to the work tree's root directory, display information for all tracked files. .El .Tg ignore .Ss Ignore Patterns .Cm got status and .Cm got add read patterns from .Pa .cvsignore and .Pa .gitignore files in each traversed directory and will not display or add unversioned files which match these patterns. The patterns are matched according to .Xr glob 7 rules, with extensions to improve compatibility with .Xr cvs 1 and .Xr git 1 . Patterns from each .Pa .cvsignore or .Pa .gitignore file are matched relative to the directory containing that file. If a pattern begins with two asterisks followed by a slash, .Dq **/ , the remainder of the pattern will match at any directory at or below the directory containing .Pa .cvsignore or .Pa gitignore file. Two asterisks surrounded by slashes, .Dq /**/ , in the middle of a pattern will match one directory or more. Patterns which end with a slash, .Dq / , will only match directories, and any paths below matching directories will be ignored. .Pp Unlike .Xr cvs 1 , .Nm only supports a single ignore pattern per line. Unlike .Xr git 1 , .Nm does not support negated ignore patterns prefixed with .Dq \&! , and does not match patterns at arbitrary depth relative to the .Pa .gitignore file unless they begin with .Dq **/ . For better .Xr git 1 compatibility, patterns beginning with a slash are matched as if the slash were not present. .Sh ENVIRONMENT .Bl -tag -width GOT_IGNORE_GITCONFIG .It Ev GOT_AUTHOR The author's name and email address, such as .Qq An Flan Hacker Aq Mt flan_hacker@openbsd.org . Used by the .Cm got commit , .Cm got import , .Cm got rebase , .Cm got merge , and .Cm got histedit commands. Because .Xr git 1 may fail to parse commits without an email address in author data, .Nm attempts to reject .Ev GOT_AUTHOR environment variables with a missing email address. .Pp .Ev GOT_AUTHOR will be overridden by configuration settings in .Xr got.conf 5 or by Git's .Dv user.name and .Dv user.email configuration settings in the repository's .Pa .git/config file. The .Dv user.name and .Dv user.email configuration settings contained in Git's global .Pa ~/.gitconfig configuration file will only be used if neither .Xr got.conf 5 nor the .Ev GOT_AUTHOR environment variable provide author information. .It Ev GOT_IGNORE_GITCONFIG If this variable is set then any remote repository definitions or author information found in Git configuration files will be ignored. .It Ev GOT_LOG_DEFAULT_LIMIT The default limit on the number of commits traversed by .Cm got log . If set to zero, the limit is unbounded. This variable will be silently ignored if it is set to a non-numeric value. .It Ev VISUAL , EDITOR The editor spawned by .Cm got commit , .Cm got histedit , .Cm got import , or .Cm got tag . If not set, the .Xr vi 1 text editor will be spawned. .El .Sh FILES .Bl -tag -width packed-refs -compact .It Pa got.conf Repository-wide configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file located in the root directory of a Git repository supersedes any relevant settings in Git's .Pa config file. .Pp .It Pa .got/got.conf Worktree-specific configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file in the .Pa .got meta-data directory of a work tree supersedes any relevant settings in the repository's .Xr got.conf 5 configuration file and Git's .Pa config file. .El .Sh EXIT STATUS .Ex -std got .Sh EXAMPLES Enable tab-completion of .Nm command names in .Xr ksh 1 : .Pp .Dl $ set -A complete_got_1 -- $(got -h 2>&1 | sed -n s/commands://p) .Pp Clone an existing Git repository for use with .Nm : .Pp .Dl $ cd /var/git/ .Dl $ got clone ssh://git@github.com/openbsd/src.git .Pp Unfortunately, many of the popular Git hosting sites do not offer anonymous access via SSH. Such sites will require an account to be created, and a public SSH key to be uploaded to this account, before repository access via ssh:// URLs will work. .Pp Most sites offer anonymous repository access via HTTPS: .Pp .Dl $ cd /var/git/ .Dl $ got clone https://github.com/openbsd/src.git .Pp Alternatively, for quick and dirty local testing of .Nm a new Git repository could be created and populated with files, e.g. from a temporary CVS checkout located at .Pa /tmp/src : .Pp .Dl $ got init /var/git/src.git .Dl $ got import -r /var/git/src.git -I CVS -I obj /tmp/src .Pp Check out a work tree from the Git repository to /usr/src: .Pp .Dl $ got checkout /var/git/src.git /usr/src .Pp View local changes in a work tree directory: .Pp .Dl $ got diff | less .Pp In a work tree, display files in a potentially problematic state: .Pp .Dl $ got status -s 'C!~?' .Pp Interactively revert selected local changes in a work tree directory: .Pp .Dl $ got revert -p -R\ . .Pp In a work tree or a git repository directory, list all branch references: .Pp .Dl $ got branch -l .Pp As above, but list the most recently modified branches only: .Pp .Dl $ got branch -lt | head .Pp In a work tree or a git repository directory, create a new branch called .Dq unified-buffer-cache which is forked off the .Dq master branch: .Pp .Dl $ got branch -c master unified-buffer-cache .Pp Switch an existing work tree to the branch .Dq unified-buffer-cache . Local changes in the work tree will be preserved and merged if necessary: .Pp .Dl $ got update -b unified-buffer-cache .Pp Create a new commit from local changes in a work tree directory. This new commit will become the head commit of the work tree's current branch: .Pp .Dl $ got commit .Pp In a work tree or a git repository directory, view changes committed in the 3 most recent commits to the work tree's branch, or the branch resolved via the repository's HEAD reference, respectively: .Pp .Dl $ got log -p -l 3 .Pp As above, but display changes in the order in which .Xr patch 1 could apply them in sequence: .Pp .Dl $ got log -p -l 3 -R .Pp In a work tree or a git repository directory, log the history of a subdirectory: .Pp .Dl $ got log sys/uvm .Pp While operating inside a work tree, paths are specified relative to the current working directory, so this command will log the subdirectory .Pa sys/uvm : .Pp .Dl $ cd sys/uvm && got log\ . .Pp And this command has the same effect: .Pp .Dl $ cd sys/dev/usb && got log ../../uvm .Pp And this command displays work tree meta-data about all tracked files: .Pp .Dl $ cd /usr/src .Dl $ got info\ . | less .Pp Add new files and remove obsolete files in a work tree directory: .Pp .Dl $ got add sys/uvm/uvm_ubc.c .Dl $ got remove sys/uvm/uvm_vnode.c .Pp A file can be renamed or moved by removing it from its old location and adding it at the new location: .Pp .Dl $ cp oldfile.c newfile.c .Dl $ got remove oldfile.c .Dl $ got add newfile.c .Pp .Nm does not yet follow file history across renames, but .Xr git 1 will be able to do so regardless. .Pp Create a new commit from local changes in a work tree directory with a pre-defined log message. .Pp .Dl $ got commit -m 'unify the buffer cache' .Pp Alternatively, create a new commit from local changes in a work tree directory with a log message that has been prepared in the file .Pa /tmp/msg : .Pp .Dl $ got commit -F /tmp/msg .Pp Update any work tree checked out from the .Dq unified-buffer-cache branch to the latest commit on this branch: .Pp .Dl $ got update .Pp Roll file content on the unified-buffer-cache branch back by one commit, and then fetch the rolled-back change into the work tree as a local change to be amended and perhaps committed again: .Pp .Dl $ got backout unified-buffer-cache .Dl $ got commit -m 'roll back previous' .Dl $ # now back out the previous backout :-) .Dl $ got backout unified-buffer-cache .Pp Fetch new changes on the remote repository's .Dq master branch, making them visible on the local repository's .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got fetch .Pp Rebase the local .Dq master branch to merge the new changes that are now visible on the .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got update -b origin/master .Dl $ got rebase master .Pp Rebase the .Dq unified-buffer-cache branch on top of the new head commit of the .Dq master branch. .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Create a patch from all changes on the unified-buffer-cache branch. The patch can be mailed out for review and applied to .Ox Ns 's CVS tree: .Pp .Dl $ got diff master unified-buffer-cache > /tmp/ubc.diff .Pp Edit the entire commit history of the .Dq unified-buffer-cache branch: .Pp .Dl $ got update -b unified-buffer-cache .Dl $ got update -c master .Dl $ got histedit .Pp Before working against existing branches in a repository cloned with .Cm git clone --bare instead of .Cm got clone , a Git .Dq refspec must be configured to map all references in the remote repository into the .Dq refs/remotes namespace of the local repository. This can be achieved by setting Git's .Pa remote.origin.fetch configuration variable to the value .Dq +refs/heads/*:refs/remotes/origin/* with the .Cm git config command: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' .Pp Additionally, the .Dq mirror option must be disabled: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.mirror false .Pp Alternatively, the following .Xr git-fetch 1 configuration item can be added manually to the Git repository's .Pa config file: .Pp .Dl [remote \&"origin\&"] .Dl url = ... .Dl fetch = +refs/heads/*:refs/remotes/origin/* .Dl mirror = false .Pp This configuration leaves the local repository's .Dq refs/heads namespace free for use by local branches checked out with .Cm got checkout and, if needed, created with .Cm got branch . Branches in the .Dq refs/remotes/origin namespace can now be updated with incoming changes from the remote repository with .Cm got fetch or .Xr git-fetch 1 without extra command line arguments. Newly fetched changes can be examined with .Cm got log . .Pp Display changes on the remote repository's version of the .Dq master branch, as of the last time .Cm got fetch was run: .Pp .Dl $ got log -c origin/master | less .Pp As shown here, most commands accept abbreviated reference names such as .Dq origin/master instead of .Dq refs/remotes/origin/master . The latter is only needed in case of ambiguity. .Pp .Cm got rebase can be used to merge changes which are visible on the .Dq origin/master branch into the .Dq master branch. This will also merge local changes, if any, with the incoming changes: .Pp .Dl $ got update -b origin/master .Dl $ got rebase master .Pp In order to make changes committed to the .Dq unified-buffer-cache visible on the .Dq master branch, the .Dq unified-buffer-cache branch can be rebased onto the .Dq master branch: .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Changes on the .Dq unified-buffer-cache branch can now be made visible on the .Dq master branch with .Cm got integrate . Because the rebase operation switched the work tree to the .Dq unified-buffer-cache branch, the work tree must be switched back to the .Dq master branch first: .Pp .Dl $ got update -b master .Dl $ got integrate unified-buffer-cache .Pp On the .Dq master branch, log messages for local changes can now be amended with .Dq OK by other developers and any other important new information: .Pp .Dl $ got update -c origin/master .Dl $ got histedit -m .Pp If the remote repository offers write access, local changes on the .Dq master branch can be sent to the remote repository with .Cm got send . Usually, .Cm got send can be run without further arguments. The arguments shown here match defaults, provided the work tree's current branch is the .Dq master branch: .Pp .Dl $ got send -b master origin .Pp If the remote repository requires the HTTPS protocol, the .Xr git-push 1 command must be used instead: .Pp .Dl $ cd /var/git/src.git .Dl $ git push origin master .Pp When making contributions to projects which use the .Dq pull request workflow, SSH protocol repository access needs to be set up first. Once an account has been created on a Git hosting site it should be possible to upload a public SSH key for repository access authentication. .Pp The .Dq pull request workflow will usually involve two remote repositories. In the real-life example below, the .Dq origin repository was forked from the .Dq upstream repository by using the Git hosting site's web interface. The .Xr got.conf 5 file in the local repository describes both remote repositories: .Bd -literal -offset indent # Jelmers's repository, which accepts pull requests remote "upstream" { server git@github.com protocol ssh repository "/jelmer/dulwich" branch { "master" } } # Stefan's fork, used as the default remote repository remote "origin" { server git@github.com protocol ssh repository "/stspdotname/dulwich" branch { "master" } } .Ed .Pp With this configuration, Stefan can create commits on .Dq refs/heads/master and send them to the .Dq origin repository by running: .Pp .Dl $ got send -b master origin .Pp The changes can now be proposed to Jelmer by opening a pull request via the Git hosting site's web interface. If Jelmer requests further changes to be made, additional commits can be created on the .Dq master branch and be added to the pull request by running .Cd got send again. .Pp If Jelmer prefers additional commits to be .Dq squashed then the following commands can be used to achieve this: .Pp .Dl $ got update -b master .Dl $ got update -c origin/master .Dl $ got histedit -f .Dl $ got send -f -b master origin .Pp In addition to reviewing the pull request in the web user interface, Jelmer can fetch the pull request's branch into his local repository and create a local branch which contains the proposed changes: .Pp .Dl $ got fetch -R refs/pull/1046/head origin .Dl $ got branch -c refs/remotes/origin/pull/1046/head pr1046 .Pp Once Jelmer has accepted the pull request, Stefan can fetch the merged changes, and possibly several other new changes, by running: .Pp .Dl $ got fetch upstream .Pp The merged changes will now be visible under the reference .Dq refs/remotes/upstream/master . The local .Dq master branch can now be rebased on top of the latest changes from upstream: .Pp .Dl $ got update -b upstream/master .Dl $ got rebase master .Pp As an alternative to .Cm got rebase , branches can be merged with .Cm got merge : .Pp .Dl $ got update -b master .Dl $ got merge upstream/master .Pp The question of whether to rebase or merge branches is philosophical. When in doubt, refer to the software project's policies set by project maintainers. .Pp As a final step, the forked repository's copy of the master branch needs to be kept in sync by sending the new changes there: .Pp .Dl $ got send -f -b master origin .Pp If multiple pull requests need to be managed in parallel, a separate branch must be created for each pull request with .Cm got branch . Each such branch can then be used as above, in place of .Dq refs/heads/master . Changes for any accepted pull requests will still appear under .Dq refs/remotes/upstream/master, regardless of which branch was used in the forked repository to create a pull request. .Sh SEE ALSO .Xr gotadmin 1 , .Xr tog 1 , .Xr git-repository 5 , .Xr got-worktree 5 , .Xr got.conf 5 , .Xr gotwebd 8 .Sh AUTHORS .An Anthony J. Bentley Aq Mt bentley@openbsd.org .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Florian Obser Aq Mt florian@narrans.de .An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org .An James Cook Aq Mt falsifian@falsifian.org .An Jasper Lievisse Adriaanse Aq Mt j@jasper.la .An Josh Rickmar Aq Mt jrick@zettaport.com .An Joshua Stein Aq Mt jcs@openbsd.org .An Josiah Frentsos Aq Mt jfrent@tilde.team .An Klemens Nanni Aq Mt kn@openbsd.org .An Kyle Ackerman Aq Mt kackerman0102@gmail.com .An Lorenz (xha) Aq Mt me@xha.li .An Lucas Gabriel Vuotto Aq Mt lucas@sexy.is .An Mark Jamsek Aq Mt mark@jamsek.dev .An Martin Pieuchot Aq Mt mpi@openbsd.org .An Mikhail Pchelin Aq Mt misha@freebsd.org .An Neels Hofmeyr Aq Mt neels@hofmeyr.de .An Omar Polo Aq Mt op@openbsd.org .An Ori Bernstein Aq Mt ori@openbsd.org .An Sebastien Marie Aq Mt semarie@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Steven McDonald Aq Mt steven@steven-mcdonald.id.au .An Ted Unangst Aq Mt tedu@tedunangst.com .An Theo Buehler Aq Mt tb@openbsd.org .An Thomas Adam Aq Mt thomas@xteddy.org .An Tobias Heider Aq Mt me@tobhe.de .An Todd C. Miller Aq Todd.Miller@sudo.ws .An Tom Jones Aq Mt thj@freebsd.org .An Tracey Emery Aq Mt tracey@traceyemery.net .An Yang Zhong Aq Mt yzhong@freebsdfoundation.org .Pp Parts of .Nm , .Xr tog 1 , .Xr gotd 8 , and .Xr gotwebd 8 were derived from code under copyright by: .Pp .An Bjoern Hoehrmann .An Caldera International .An Daniel Hartmeier .An David Gwynne .An Esben Norby .An Henning Brauer .An Håkan Olsson .An Ingo Schwarze .An Jean-Francois Brousseau .An Jerome Kasper .An Joris Vink .An Jyri J. Virkki .An Larry Wall .An Markus Friedl .An Mike Larkin .An Niall O'Higgins .An Niklas Hallqvist .An Ray Lai .An Reyk Floeter .An Ryan McBride .An Theo de Raadt .An Xavier Santolaria .Pp .Nm contains code contributed to the public domain by .An Austin Appleby . .Sh CAVEATS .Nm is a work-in-progress and some features remain to be implemented. .Pp At present, the user has to fall back on .Xr git 1 to perform some tasks. In particular: .Bl -bullet .It With repositories that use the sha256 object ID hashing algorithm, .Xr git 1 is currently required for all network operations (clone, fetch, and push) because .Nm does not yet support version 2 of the Git network protocol. .It Writing to remote repositories over HTTP or HTTPS protocols requires .Xr git-push 1 . .It The creation of merge commits with more than two parent commits requires .Xr git-merge 1 . .It In situations where files or directories were moved around .Cm got will not automatically merge changes to new locations and .Xr git 1 will usually produce better results. .El got-portable-0.119/got/Makefile.am0000664000175000017500000000505315066536113012444 bin_PROGRAMS = got include $(top_builddir)/Makefile.common got_SOURCES = got.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c EXTRA_DIST = $(top_srcdir)/compat/*.[ch] \ $(top_srcdir)/lib/*.[ch] \ $(top_srcdir)/include/*.[ch] \ got.1 got.conf.5 git-repository.5 got-worktree.5 got_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = got.1 man5_MANS = got.conf.5 git-repository.5 got-worktree.5 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm LDADD += $(libuuid_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libuuid_CFLAGS) \ $(zlib_CFLAGS) \ $(libbsd_CFLAGS) \ $(libmd_CLFAGS) got-portable-0.119/got/got.conf.50000664000175000017500000002271615066535721012224 .\" .\" Copyright (c) 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOT.CONF 5 .Os .Sh NAME .Nm got.conf .Nd Game of Trees configuration file .Sh DESCRIPTION .Nm is the run-time configuration file for .Xr got 1 . .Pp .Nm may be present in the root directory of a Git repository for repository-wide settings, or in the .Pa .got meta-data directory of a work tree to override repository-wide settings for .Xr got 1 commands executed within this work tree. .Pp The file format is line-based, with one configuration directive per line. Comments can be put anywhere in the file using a hash mark .Pq Sq # , and extend to the end of the current line. Arguments names not beginning with a letter, digit or underscore, as well as reserved words .Pq such as Ic author , Ic remote No or Ic port , must be quoted. Arguments containing whitespace should be surrounded by double quotes .Pq \&" . .Pp The available configuration directives are as follows: .Bl -tag -width Ds .It Ic author Dq Real Name Configure the author's name and email address for .Cm got commit and .Cm got import when operating on this repository. Author information specified here overrides the .Ev GOT_AUTHOR environment variable. .Pp Because .Xr git 1 may fail to parse commits without an email address in author data, .Xr got 1 attempts to reject author information with a missing email address. .It Ic signer_id Pa signer-id Configure a .Ar signer-id to sign tag objects. This key will be used to sign all tag objects unless overridden by .Cm got tag Fl s Ar signer-id . .Pp For SSH-based signatures, .Ar signer-id is the path to a file which may refer to either a private SSH key, or a public SSH key with the private half available via .Xr ssh-agent 1 . .It Ic allowed_signers Pa path Configure a .Ar path to the "allowed signers" file which contains a list of trusted SSH signer identities. The file will be passed to .Xr ssh-keygen 1 during verification of SSH-based signatures with .Cm got tag Fl V . The format of the "allowed signers" file is documented in the ALLOWED SIGNERS section of .Xr ssh-keygen 1 . .Pp Verification of SSH-based signatures is impossible unless the .Ic allowed_signers option is set in .Nm . .It Ic revoked_signers Pa path Configure a .Ar path to the optional "revoked signers" file, which contains a list of revoked SSH signer identities. This file is passed to .Xr ssh-keygen 1 during signature verification with .Cm got tag Fl V . Revoked identities are no longer considered trustworthy and verification of relevant signatures will fail. .It Ic remote Ar name Brq ... Define a remote repository. The specified .Ar name can be used to refer to the remote repository on the command line of .Cm got fetch and .Cm got send . .Pp When repositories are shared between multiple users on the system, it is recommended that users configure their trusted remote repositories in each of their work-trees' .Nm files, overriding corresponding repository-wide settings. This can avoid potentially undesirable connections to remote repositories placed into the shared repository's .Nm file by other users. .Pp Information about a repository is declared in a block of options enclosed in curly brackets: .Bl -tag -width Ds .It Ic server Ar hostname Defines the hostname to use for contacting the remote repository's server. .It Ic repository Ar path Defines the path to the repository on the remote repository's server. .It Ic protocol Ar scheme Defines the protocol to use for communicating with the remote repository's server. .Pp The following protocol schemes are supported: .Bl -tag -width https .It git The Git protocol as implemented by the .Xr git-daemon 1 server. Use of this protocol is discouraged since it supports neither authentication nor encryption. .It ssh The Git protocol wrapped in an authenticated and encrypted .Xr ssh 1 tunnel. With this protocol the hostname may contain an embedded username for .Xr ssh 1 to use: .Mt user@hostname .It http The .Dq smart Git HTTP protocol. Not compatible with servers using the .Dq dumb Git HTTP protocol. .Pp The .Dq smart Git HTTP protocol is supported by .Cm got clone and .Cm got fetch , but not by .Cm got send . To send from a repository cloned over HTTP, add a .Ic send block (see below) to ensure that the .Dq ssh:// protocol will be used by .Cm got send . .Pp Use of this protocol is discouraged since it supports neither authentication nor encryption. .It https The .Dq smart Git HTTP protocol wrapped in SSL/TLS. .El .It Ic port Ar port Defines the port to use for connecting to the remote repository's server. The .Ar port can be specified by number or name. The port name to number mappings are found in the file .Pa /etc/services ; see .Xr services 5 for details. If not specified, the default port of the specified .Cm protocol will be used. .It Ic branch Brq Ar branch ... Specify one or more branches which .Cm got fetch and .Cm got send should fetch from and send to the remote repository by default. The list of branches specified here can be overridden at the .Cm got fetch and .Cm got send command lines with the .Fl b option. .It Ic fetch_all_branches Ar yes | no This option controls whether .Cm got fetch will fetch all branches from the remote repository by default. If enabled, this behaviour can be overridden at the .Cm got fetch command line with the .Fl b option, and any .Cm branch configuration settings for this remote repository will be ignored. .It Ic reference Brq Ar reference ... Specify one or more arbitrary references which .Cm got fetch should fetch by default, in addition to the branches and tags that will be fetched. The list of references specified here can be overridden at the .Cm got fetch command line with the .Fl R option. .Cm got fetch will refuse to fetch references from the remote repository's .Dq refs/remotes/ or .Dq refs/got/ namespace. In any case, references in the .Dq refs/tags/ namespace will always be fetched and mapped directly to local references in the same namespace. .It Ic mirror_references Ar yes | no This option controls the behaviour of .Cm got fetch when updating references. .Sy Enabling this option can lead to the loss of local commits. Maintaining custom changes in a mirror repository is therefore discouraged. .Pp If this option is not specified or set to .Ar no , .Cm got fetch will map references of the remote repository into the local repository's .Dq refs/remotes/ namespace. .Pp If this option is set to .Ar yes , all branches in the .Dq refs/heads/ namespace will be updated directly to match the corresponding branches in the remote repository. .It Ic fetch Brq ... An optional .Ic fetch block may contain any of the following configuration settings for use by .Cm got fetch , overriding corresponding settings in the containing .Ic remote Ar name Brq ... block. .Bl -bullet .It .Ic server Ar hostname .It .Ic repository Ar path .It .Ic protocol Ar scheme .It .Ic port Ar port .It .Ic branch Brq Ar branch ... .El .It Ic send Brq ... An optional .Ic send block may contain any of the following configuration settings for use by .Cm got send , overriding corresponding settings in the containing .Ic remote Ar name Brq ... block. .Bl -bullet .It .Ic server Ar hostname .It .Ic repository Ar path .It .Ic protocol Ar scheme .It .Ic port Ar port .It .Ic branch Brq Ar branch ... .El .El .El .Sh FILES .Bl -tag -width Ds -compact .It Pa got.conf If present, .Nm located in the root directory of a Git repository supersedes any relevant settings in Git's .Pa config file. .Pp .It Pa .got/got.conf If present, .Nm located in the .Pa .got meta-data directory of a .Xr got 1 work tree supersedes any relevant settings in the repository's .Nm configuration file and Git's .Pa config file. .El .Sh EXAMPLES Configure author information: .Bd -literal -offset indent author "Flan Hacker " .Ed .Pp Remote repository specification for the Game of Trees repository: .Bd -literal -offset indent remote "origin" { server anonymous@got.gameoftrees.org protocol ssh repository got branch { "main" } } .Ed .Pp Mirror the .Ox src repository from Github: .Bd -literal -offset indent remote "origin" { repository "openbsd/src" server git@github.com protocol git+ssh mirror_references yes } .Ed .Pp Fetch changes via the Git protocol and send changes via the SSH protocol: .Bd -literal -offset indent remote "origin" { repository my_repo server git.example.com protocol git send { server git@git.example.com protocol ssh } } .Ed .Sh SEE ALSO .Xr got 1 , .Xr git-repository 5 , .Xr got-worktree 5 .Sh CAVEATS .Nm offers no way to configure the editor spawned by .Cm got commit , .Cm got histedit , .Cm got import , or .Cm got tag . This is deliberate and prevents potential arbitrary command execution as another user when repositories or work trees are shared between users. Users should set their .Ev VISUAL or .Ev EDITOR environment variables instead. got-portable-0.119/got/Makefile.in0000664000175000017500000014545315066537207012473 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = got$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = got ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(man5dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_OBJECTS = got.$(OBJEXT) $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fetch.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/keyword.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_privsep.$(OBJEXT) \ $(top_builddir)/lib/patch.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/repository_init.$(OBJEXT) \ $(top_builddir)/lib/send.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) got_OBJECTS = $(am_got_OBJECTS) got_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fetch.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/keyword.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/patch.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/repository_init.Po \ $(top_builddir)/lib/$(DEPDIR)/send.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/got.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_SOURCES) DIST_SOURCES = $(got_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 man5dir = $(mandir)/man5 NROFF = nroff MANS = $(man1_MANS) $(man5_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libuuid_CFLAGS) $(zlib_CFLAGS) \ $(libbsd_CFLAGS) $(libmd_CLFAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_SOURCES = got.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c EXTRA_DIST = $(top_srcdir)/compat/*.[ch] \ $(top_srcdir)/lib/*.[ch] \ $(top_srcdir)/include/*.[ch] \ got.1 got.conf.5 git-repository.5 got-worktree.5 got_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = got.1 man5_MANS = got.conf.5 git-repository.5 got-worktree.5 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libuuid_LIBS) \ $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign got/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign got/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: -$(am__rm_f) $(bin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fetch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/keyword.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/patch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository_init.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/send.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got$(EXEEXT): $(got_OBJECTS) $(got_DEPENDENCIES) $(EXTRA_got_DEPENDENCIES) @rm -f got$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_OBJECTS) $(got_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fetch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/keyword.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/patch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository_init.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/send.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man5: $(man5_MANS) @$(NORMAL_INSTALL) @list1='$(man5_MANS)'; \ list2=''; \ test -n "$(man5dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.5[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ done; } uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/got.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man5 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/got.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 uninstall-man5 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-man5 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-man \ uninstall-man1 uninstall-man5 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/0000775000175000017500000000000015066537276011322 5got-portable-0.119/libexec/got-send-pack/0000775000175000017500000000000015066537276013756 5got-portable-0.119/libexec/got-send-pack/got-send-pack.c0000664000175000017500000004643415066536114016477 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_version.h" #include "got_fetch.h" #include "got_reference.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" #include "got_lib_gitproto.h" #include "got_lib_ratelimit.h" #include "got_lib_poll.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_object *indexed; static int chattygot; static const struct got_capability got_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, #if 0 { GOT_CAPA_SIDE_BAND_64K, NULL }, #endif { GOT_CAPA_REPORT_STATUS, NULL }, { GOT_CAPA_DELETE_REFS, NULL }, }; static const struct got_error * send_upload_progress(struct imsgbuf *ibuf, off_t bytes, struct got_ratelimit *rl) { const struct got_error *err = NULL; int elapsed = 0; if (rl) { err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; } if (imsg_compose(ibuf, GOT_IMSG_SEND_UPLOAD_PROGRESS, 0, 0, -1, &bytes, sizeof(bytes)) == -1) return got_error_from_errno( "imsg_compose SEND_UPLOAD_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_pack_request(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_SEND_PACK_REQUEST, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose SEND_PACK_REQUEST"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_SEND_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose SEND_DONE"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * recv_packfd(int *packfd, struct imsgbuf *ibuf) { const struct got_error *err; struct imsg imsg; *packfd = -1; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; if (imsg.hdr.type == GOT_IMSG_STOP) { err = got_error(GOT_ERR_CANCELLED); goto done; } if (imsg.hdr.type != GOT_IMSG_SEND_PACKFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } *packfd = imsg_get_fd(&imsg); done: imsg_free(&imsg); return err; } static const struct got_error * send_pack_file(int sendfd, int packfd, struct imsgbuf *ibuf) { const struct got_error *err; unsigned char buf[8192]; ssize_t r; off_t wtotal = 0; struct got_ratelimit rl; if (lseek(packfd, 0L, SEEK_SET) == -1) return got_error_from_errno("lseek"); got_ratelimit_init(&rl, 0, 500); for (;;) { r = read(packfd, buf, sizeof(buf)); if (r == -1) return got_error_from_errno("read"); if (r == 0) break; err = got_poll_write_full(sendfd, buf, r); if (err) return NULL; wtotal += r; err = send_upload_progress(ibuf, wtotal, &rl); if (err) return err; } return send_upload_progress(ibuf, wtotal, NULL); } static const struct got_error * send_error(const char *buf, size_t len) { static char msg[1024]; size_t i; for (i = 0; i < len && i < sizeof(msg) - 1; i++) { if (!isprint((unsigned char)buf[i])) return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received from server"); msg[i] = buf[i]; } msg[i] = '\0'; return got_error_msg(GOT_ERR_SEND_FAILED, msg); } static const struct got_error * send_their_ref(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { struct ibuf *wbuf; size_t len, reflen = strlen(refname); len = sizeof(struct got_imsg_send_remote_ref) + reflen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REMOTE_REF, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create SEND_REMOTE_REF"); /* Keep in sync with struct got_imsg_send_remote_ref definition! */ if (imsg_add(wbuf, refid, sizeof(*refid)) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add SEND_REMOTE_REF"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_ref_status(struct imsgbuf *ibuf, const char *refname, int success, struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs) { struct ibuf *wbuf; size_t i, len, reflen, errmsglen = 0; struct got_pathlist_entry *pe; int ref_valid = 0; char *eol, *sp; const char *errmsg = ""; eol = strchr(refname, '\n'); if (eol == NULL) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } *eol = '\0'; sp = strchr(refname, ' '); if (sp != NULL) { *sp++ = '\0'; errmsg = sp; errmsglen = strlen(errmsg); for (i = 0; i < errmsglen; ++i) { if (!isprint((unsigned char)errmsg[i])) { return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received " "from the server"); } } } reflen = strlen(refname); if (!got_ref_name_is_valid(refname)) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } RB_FOREACH(pe, got_pathlist_head, refs) { if (strcmp(refname, pe->path) == 0) { ref_valid = 1; break; } } if (!ref_valid) { RB_FOREACH(pe, got_pathlist_head, delete_refs) { if (strcmp(refname, pe->path) == 0) { ref_valid = 1; break; } } } if (!ref_valid) { return got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); } len = sizeof(struct got_imsg_send_ref_status) + reflen + errmsglen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF_STATUS, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create SEND_REF_STATUS"); /* Keep in sync with struct got_imsg_send_ref_status definition! */ if (imsg_add(wbuf, &success, sizeof(success)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, &errmsglen, sizeof(errmsglen)) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); if (imsg_add(wbuf, errmsg, errmsglen) == -1) return got_error_from_errno("imsg_add SEND_REF_STATUS"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * describe_refchange(int *n, int *sent_my_capabilites, const char *my_capabilities, char *buf, size_t bufsize, const char *refname, const char *old_hashstr, const char *new_hashstr) { *n = snprintf(buf, bufsize, "%s %s %s", old_hashstr, new_hashstr, refname); if (*n < 0 || (size_t)*n >= bufsize) return got_error(GOT_ERR_NO_SPACE); /* * We must announce our capabilities along with the first * reference. Unfortunately, the protocol requires an embedded * NUL as a separator between reference name and capabilities, * which we have to deal with here. * It also requires a linefeed for terminating packet data. */ if (!*sent_my_capabilites && my_capabilities != NULL) { int m; if (*n >= bufsize - 1) return got_error(GOT_ERR_NO_SPACE); m = snprintf(buf + *n + 1, /* offset after '\0' */ bufsize - (*n + 1), "%s\n", my_capabilities); if (m < 0 || *n + m >= bufsize) return got_error(GOT_ERR_NO_SPACE); *n += m; *sent_my_capabilites = 1; } else { *n = strlcat(buf, "\n", bufsize); if (*n >= bufsize) return got_error(GOT_ERR_NO_SPACE); } return NULL; } static const struct got_error * send_pack(int fd, struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs, struct imsgbuf *ibuf) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; const unsigned char zero_id[SHA1_DIGEST_LENGTH] = { 0 }; char old_hashstr[SHA1_DIGEST_STRING_LENGTH]; char new_hashstr[SHA1_DIGEST_STRING_LENGTH]; struct got_pathlist_head their_refs; int is_firstpkt = 1; int n, nsent = 0; int packfd = -1; char *id_str = NULL, *refname = NULL; struct got_object_id *id = NULL; char *server_capabilities = NULL, *my_capabilities = NULL; struct got_pathlist_entry *pe; int sent_my_capabilites = 0; RB_INIT(&their_refs); if (RB_EMPTY(refs) && RB_EMPTY(delete_refs)) return got_error(GOT_ERR_SEND_EMPTY); while (1) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n == 0) break; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } free(id_str); free(refname); err = got_gitproto_parse_refline(&id_str, &refname, &server_capabilities, buf, n); if (err) goto done; if (is_firstpkt) { if (server_capabilities == NULL) { server_capabilities = strdup(""); if (server_capabilities == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); err = got_gitproto_match_capabilities(&my_capabilities, NULL, server_capabilities, got_capabilities, nitems(got_capabilities)); if (err) goto done; if (chattygot) fprintf(stderr, "%s: my capabilities:%s\n", getprogname(), my_capabilities ? my_capabilities : ""); is_firstpkt = 0; } if (strstr(refname, "^{}")) { if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } continue; } id = malloc(sizeof(*id)); if (id == NULL) { err = got_error_from_errno("malloc"); goto done; } if (!got_parse_object_id(id, id_str, GOT_HASH_SHA1)) { err = got_error(GOT_ERR_BAD_OBJ_ID_STR); goto done; } err = send_their_ref(ibuf, id, refname); if (err) goto done; err = got_pathlist_insert(&pe, &their_refs, refname, id); if (err || pe == NULL) { free(refname); free(id); if (err) goto done; } if (chattygot) fprintf(stderr, "%s: remote has %s %s\n", getprogname(), refname, id_str); free(id_str); id_str = NULL; refname = NULL; /* do not free; owned by their_refs */ id = NULL; /* do not free; owned by their_refs */ } if (!RB_EMPTY(delete_refs)) { if (my_capabilities == NULL || strstr(my_capabilities, GOT_CAPA_DELETE_REFS) == NULL) { err = got_error(GOT_ERR_CAPA_DELETE_REFS); goto done; } } RB_FOREACH(pe, got_pathlist_head, delete_refs) { const char *refname = pe->path; struct got_pathlist_entry *their_pe; struct got_object_id *their_id = NULL; RB_FOREACH(their_pe, got_pathlist_head, &their_refs) { const char *their_refname = their_pe->path; if (got_path_cmp(refname, their_refname, strlen(refname), strlen(their_refname)) == 0) { their_id = their_pe->data; break; } } if (their_id == NULL) { err = got_error_fmt(GOT_ERR_NOT_REF, "%s does not exist in remote repository", refname); goto done; } got_object_id_hex(their_id, old_hashstr, sizeof(old_hashstr)); got_sha1_digest_to_str(zero_id, new_hashstr, sizeof(new_hashstr)); err = describe_refchange(&n, &sent_my_capabilites, my_capabilities, buf, sizeof(buf), refname, old_hashstr, new_hashstr); if (err) goto done; err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; if (chattygot) { fprintf(stderr, "%s: deleting %s %s\n", getprogname(), refname, old_hashstr); } nsent++; } RB_FOREACH(pe, got_pathlist_head, refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_object_id *their_id = NULL; struct got_pathlist_entry *their_pe; RB_FOREACH(their_pe, got_pathlist_head, &their_refs) { const char *their_refname = their_pe->path; if (got_path_cmp(refname, their_refname, strlen(refname), strlen(their_refname)) == 0) { their_id = their_pe->data; break; } } if (their_id) { if (got_object_id_cmp(id, their_id) == 0) { if (chattygot) { fprintf(stderr, "%s: no change for %s\n", getprogname(), refname); } continue; } got_object_id_hex(their_id, old_hashstr, sizeof(old_hashstr)); } else { got_sha1_digest_to_str(zero_id, old_hashstr, sizeof(old_hashstr)); } got_object_id_hex(id, new_hashstr, sizeof(new_hashstr)); err = describe_refchange(&n, &sent_my_capabilites, my_capabilities, buf, sizeof(buf), refname, old_hashstr, new_hashstr); if (err) goto done; err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; if (chattygot) { if (their_id) { fprintf(stderr, "%s: updating %s %s -> %s\n", getprogname(), refname, old_hashstr, new_hashstr); } else { fprintf(stderr, "%s: creating %s %s\n", getprogname(), refname, new_hashstr); } } nsent++; } err = got_pkt_flushpkt(fd, chattygot); if (err) goto done; err = send_pack_request(ibuf); if (err) goto done; err = recv_packfd(&packfd, ibuf); if (err) goto done; if (packfd != -1) { err = send_pack_file(fd, packfd, ibuf); if (err) goto done; } err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } else if (n < 10 || strncmp(buf, "unpack ok\n", 10) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } while (nsent > 0) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n < 3) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } else if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = send_error(&buf[4], n - 4); goto done; } else if (strncmp(buf, "ok ", 3) == 0) { err = send_ref_status(ibuf, buf + 3, 1, refs, delete_refs); if (err) goto done; } else if (strncmp(buf, "ng ", 3) == 0) { err = send_ref_status(ibuf, buf + 3, 0, refs, delete_refs); if (err) goto done; } else { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } nsent--; } err = send_done(ibuf); done: got_pathlist_free(&their_refs, GOT_PATHLIST_FREE_ALL); free(id_str); free(id); free(refname); free(server_capabilities); free(my_capabilities); return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; int sendfd = -1; struct imsgbuf ibuf; struct imsg imsg; struct got_pathlist_head refs; struct got_pathlist_head delete_refs; struct got_imsg_send_request send_req; struct got_imsg_send_ref href; size_t datalen, i; #if 0 static int attached; while (!attached) sleep (1); #endif RB_INIT(&refs); RB_INIT(&delete_refs); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_SEND_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(send_req)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&send_req, imsg.data, sizeof(send_req)); sendfd = imsg_get_fd(&imsg); imsg_free(&imsg); if (send_req.verbosity > 0) chattygot += send_req.verbosity; for (i = 0; i < send_req.nrefs; i++) { struct got_object_id *id; char *refname; struct got_pathlist_entry *new; if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_SEND_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(href)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&href, imsg.data, sizeof(href)); if (datalen - sizeof(href) < href.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = malloc(href.name_len + 1); if (refname == NULL) { err = got_error_from_errno("malloc"); goto done; } memcpy(refname, imsg.data + sizeof(href), href.name_len); refname[href.name_len] = '\0'; /* * Prevent sending of references that won't make any * sense outside the local repository's context. */ if (strncmp(refname, "refs/got/", 9) == 0 || strncmp(refname, "refs/remotes/", 13) == 0) { err = got_error_fmt(GOT_ERR_SEND_BAD_REF, "%s", refname); goto done; } id = malloc(sizeof(*id)); if (id == NULL) { free(refname); err = got_error_from_errno("malloc"); goto done; } memcpy(id, &href.id, sizeof(*id)); if (href.delete) err = got_pathlist_insert(&new, &delete_refs, refname, id); else err = got_pathlist_insert(&new, &refs, refname, id); if (err || new == NULL ) { free(refname); free(id); if (err) goto done; } imsg_free(&imsg); } err = send_pack(sendfd, &refs, &delete_refs, &ibuf); done: got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&delete_refs, GOT_PATHLIST_FREE_ALL); if (sendfd != -1 && close(sendfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err != NULL && err->code != GOT_ERR_CANCELLED) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } imsgbuf_clear(&ibuf); exit(0); } got-portable-0.119/libexec/got-send-pack/Makefile.am0000664000175000017500000000142315066536114015720 libexec_PROGRAMS = got-send-pack include $(top_builddir)/Makefile.common got_send_pack_SOURCES = \ got-send-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/reference_parse.c got_send_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-send-pack/Makefile.in0000664000175000017500000006305215066537210015735 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-send-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-send-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_send_pack_OBJECTS = got-send-pack.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitproto.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) got_send_pack_OBJECTS = $(am_got_send_pack_OBJECTS) got_send_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitproto.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ ./$(DEPDIR)/got-send-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_send_pack_SOURCES) DIST_SOURCES = $(got_send_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_send_pack_SOURCES = \ got-send-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/reference_parse.c got_send_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-send-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-send-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitproto.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-send-pack$(EXEEXT): $(got_send_pack_OBJECTS) $(got_send_pack_DEPENDENCIES) $(EXTRA_got_send_pack_DEPENDENCIES) @rm -f got-send-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_send_pack_OBJECTS) $(got_send_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitproto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-send-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/got-send-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f ./$(DEPDIR)/got-send-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-object/0000775000175000017500000000000015066537275014267 5got-portable-0.119/libexec/got-read-object/got-read-object.c0000664000175000017500000001276615066536114017324 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif #define GOT_OBJ_TAG_COMMIT "commit" #define GOT_OBJ_TAG_TREE "tree" #define GOT_OBJ_TAG_BLOB "blob" #define GOT_OBJ_TAG_TAG "tag" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * send_raw_obj(struct imsgbuf *ibuf, struct got_object *obj, struct got_object_id *expected_id, int fd, int outfd) { const struct got_error *err = NULL; uint8_t *data = NULL; off_t size; size_t hdrlen; if (lseek(fd, 0L, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } err = got_object_read_raw(&data, &size, &hdrlen, GOT_PRIVSEP_INLINE_BLOB_DATA_MAX, outfd, expected_id, fd); if (err) goto done; err = got_privsep_send_raw_obj(ibuf, size, hdrlen, data); done: free(data); if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct got_object *obj = NULL; struct imsg imsg; struct imsgbuf ibuf; size_t datalen; struct got_object_id expected_id; signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { int fd = -1, outfd = -1, finished = 0; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { finished = 1; goto done; } if (imsg.hdr.type != GOT_IMSG_OBJECT_REQUEST && imsg.hdr.type != GOT_IMSG_RAW_OBJECT_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_header(&obj, fd); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_RAW_OBJECT_REQUEST) { struct imsg imsg_outfd; err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0); if (err) { if (imsg_outfd.hdr.len == 0) err = NULL; goto done; } if (imsg_outfd.hdr.type == GOT_IMSG_STOP) { imsg_free(&imsg_outfd); goto done; } if (imsg_outfd.hdr.type != GOT_IMSG_RAW_OBJECT_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); imsg_free(&imsg_outfd); goto done; } datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); imsg_free(&imsg_outfd); goto done; } outfd = imsg_get_fd(&imsg_outfd); if (outfd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); imsg_free(&imsg_outfd); goto done; } err = send_raw_obj(&ibuf, obj, &expected_id, fd, outfd); fd = -1; /* fd is owned by send_raw_obj() */ if (close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg_outfd); if (err) goto done; } else err = got_privsep_send_obj(&ibuf, obj); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (obj) { got_object_close(obj); obj = NULL; } if (err || finished) break; } if (err) { if(!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-object/Makefile.am0000664000175000017500000000122515066536114016232 libexec_PROGRAMS = got-read-object include $(top_builddir)/Makefile.common got_read_object_SOURCES = got-read-object.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_object_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-object/Makefile.in0000664000175000017500000005743015066537207016260 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-object$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-object ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_object_OBJECTS = got-read-object.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_object_OBJECTS = $(am_got_read_object_OBJECTS) got_read_object_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-object.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_object_SOURCES) DIST_SOURCES = $(got_read_object_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_object_SOURCES = got-read-object.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_object_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-object/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-object/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-object$(EXEEXT): $(got_read_object_OBJECTS) $(got_read_object_DEPENDENCIES) $(EXTRA_got_read_object_DEPENDENCIES) @rm -f got-read-object$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_object_OBJECTS) $(got_read_object_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-object.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-object.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-object.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-tree/0000775000175000017500000000000015066537276013761 5got-portable-0.119/libexec/got-read-tree/Makefile.am0000664000175000017500000000121515066536114015722 libexec_PROGRAMS = got-read-tree include $(top_builddir)/Makefile.common got_read_tree_SOURCES = got-read-tree.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tree_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-tree/got-read-tree.c0000664000175000017500000000733215066536114016477 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0; signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; uint8_t *buf = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_TREE_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } /* Always assume file offset zero. */ err = got_object_read_tree(&entries, &nentries, &nentries_alloc, &buf, fd, &expected_id); if (err) goto done; err = got_privsep_send_tree(&ibuf, entries, nentries); done: free(buf); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } free(entries); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-tree/Makefile.in0000664000175000017500000005734615066537210015751 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-tree$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-tree ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_tree_OBJECTS = got-read-tree.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_tree_OBJECTS = $(am_got_read_tree_OBJECTS) got_read_tree_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-tree.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_tree_SOURCES) DIST_SOURCES = $(got_read_tree_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_tree_SOURCES = got-read-tree.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tree_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-tree/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-tree/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-tree$(EXEEXT): $(got_read_tree_OBJECTS) $(got_read_tree_DEPENDENCIES) $(EXTRA_got_read_tree_DEPENDENCIES) @rm -f got-read-tree$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_tree_OBJECTS) $(got_read_tree_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-tree.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tree.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tree.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-tag/0000775000175000017500000000000015066537276013575 5got-portable-0.119/libexec/got-read-tag/got-read-tag.c0000664000175000017500000000702615066536114016127 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; struct got_tag_object *tag = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_TAG_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } /* Always assume file offset zero. */ err = got_object_read_tag(&tag, fd, &expected_id, 0); if (err) goto done; err = got_privsep_send_tag(&ibuf, tag); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-tag/Makefile.am0000664000175000017500000000121115066536114015532 libexec_PROGRAMS = got-read-tag include $(top_builddir)/Makefile.common got_read_tag_SOURCES = got-read-tag.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tag_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-tag/Makefile.in0000664000175000017500000005731515066537210015561 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-tag$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-tag ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_tag_OBJECTS = got-read-tag.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_tag_OBJECTS = $(am_got_read_tag_OBJECTS) got_read_tag_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-tag.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_tag_SOURCES) DIST_SOURCES = $(got_read_tag_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_tag_SOURCES = got-read-tag.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_tag_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-tag/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-tag/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-tag$(EXEEXT): $(got_read_tag_OBJECTS) $(got_read_tag_DEPENDENCIES) $(EXTRA_got_read_tag_DEPENDENCIES) @rm -f got-read-tag$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_tag_OBJECTS) $(got_read_tag_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-tag.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tag.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-tag.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-fetch-http/0000775000175000017500000000000015066537275014156 5got-portable-0.119/libexec/got-fetch-http/got-fetch-http.c0000664000175000017500000003057415066536114017077 /* * Copyright (c) 2024 Tobias Heider * Copyright (c) 2022, 2025 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_path.h" #include "got_version.h" #include "got_lib_pkt.h" #include "bufio.h" #define UPLOAD_PACK_ADV "application/x-git-upload-pack-advertisement" #define UPLOAD_PACK_REQ "application/x-git-upload-pack-request" #define UPLOAD_PACK_RES "application/x-git-upload-pack-result" #define GOT_USERAGENT "got/" GOT_VERSION_STR #define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) #define hasprfx(str, p) (strncasecmp(str, p, strlen(p)) == 0) FILE *tmp; static int verbose; static char * bufio_getdelim_sync(struct bufio *bio, const char *nl, size_t *len) { int r; do { r = bufio_read(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_read: %s", bufio_io_err(bio)); } while (r == -1 && errno == EAGAIN); return buf_getdelim(&bio->rbuf, nl, len); } static void bufio_close_sync(struct bufio *bio) { int r; do { r = bufio_close(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_close: %s", bufio_io_err(bio)); } while (r == -1 && errno == EAGAIN); } static long long hexstrtonum(const char *str, long long min, long long max, const char **errstr) { long long lval; char *cp; errno = 0; lval = strtoll(str, &cp, 16); if (*str == '\0' || *cp != '\0') { *errstr = "not a number"; return 0; } if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || lval < min || lval > max) { *errstr = "out of range"; return 0; } *errstr = NULL; return lval; } static int dial(int https, const char *host, const char *port) { struct addrinfo hints, *res, *res0; int error, saved_errno, fd = -1; const char *cause = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) { warnx("%s", gai_strerror(error)); return -1; } for (res = res0; res; res = res->ai_next) { fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd == -1) { cause = "socket"; continue; } if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) break; cause = "connect"; saved_errno = errno; close(fd); fd = -1; errno = saved_errno; } freeaddrinfo(res0); if (fd == -1) { warn("%s", cause); return -1; } return fd; } static int http_open(struct bufio *bio, int https, const char *method, const char *host, const char *port, const char *path, const char *path_sufx, const char *query, const char *ctype) { const char *chdr = NULL, *te = ""; char *p, *req; int r; if (strcmp(method, "POST") == 0) te = "\r\nTransfer-Encoding: chunked\r\n"; if (ctype) chdr = "Content-Type: "; r = asprintf(&p, "%s%s/%s%s%s", got_path_is_absolute(path) ? "" :"/", path, path_sufx, query ? "?" : "", query ? query : ""); if (r == -1) err(1, "asprintf"); r = asprintf(&req, "%s %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "User-agent: %s\r\n" "%s%s%s\r\n", method, p, host, GOT_USERAGENT, chdr ? chdr : "", ctype ? ctype : "", te); if (r == -1) err(1, "asprintf"); free(p); if (verbose > 0) fprintf(stderr, "%s: request: %s\n", getprogname(), req); r = bufio_compose(bio, req, r); if (r == -1) err(1, "bufio_compose_fmt"); free(req); do { r = bufio_write(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_write: %s", bufio_io_err(bio)); } while (bio->wbuf.len != 0); return 0; } static int http_parse_reply(struct bufio *bio, int *chunked, const char *expected_ctype) { char *cp, *line; size_t linelen; *chunked = 0; line = bufio_getdelim_sync(bio, "\r\n", &linelen); if (line == NULL) { warnx("%s: bufio_getdelim_sync()", __func__); return -1; } if (verbose > 0) fprintf(stderr, "%s: response: %s\n", getprogname(), line); if ((cp = strchr(line, ' ')) == NULL) { warnx("malformed HTTP response"); return -1; } cp++; if (strncmp(cp, "200 ", 4) != 0) { warnx("malformed HTTP response"); return -1; } buf_drain(&bio->rbuf, linelen); while(1) { line = bufio_getdelim_sync(bio, "\r\n", &linelen); if (line == NULL) { warnx("%s: bufio_getdelim_sync()", __func__); return -1; } if (*line == '\0') { buf_drain(&bio->rbuf, linelen); break; } if (hasprfx(line, "content-type:")) { cp = strchr(line, ':') + 1; cp += strspn(cp, " \t"); cp[strcspn(cp, " \t")] = '\0'; if (strcmp(cp, expected_ctype) != 0) { warnx("server not using the \"smart\" " "HTTP protocol."); return -1; } } if (hasprfx(line, "transfer-encoding:")) { cp = strchr(line, ':') + 1; cp += strspn(cp, " \t"); cp[strcspn(cp, " \t")] = '\0'; if (strcmp(cp, "chunked") != 0) { warnx("unknown transfer-encoding"); return -1; } *chunked = 1; } buf_drain(&bio->rbuf, linelen); } return 0; } static ssize_t http_read(struct bufio *bio, int chunked, size_t *chunksz, char *buf, size_t bufsz, FILE *out) { struct buf *rbuf = &bio->rbuf; const char *errstr; char *chunk, *endln; size_t avail, w; ssize_t r, ret = 0; while (out != NULL || bufsz > 0) { if (rbuf->cur == rbuf->len) { rbuf->cur = 0; rbuf->len = 0; r = bufio_read(bio); if (r == -1) { warnx("bufio_read: %s", bufio_io_err(bio)); return (-1); } if (r == 0) return ret; } if (chunked && *chunksz == 0) { for (;;) { chunk = rbuf->buf + rbuf->cur; avail = rbuf->len - rbuf->cur; endln = memmem(chunk, avail, "\r\n", 2); if (endln == NULL) { r = bufio_read(bio); if (r == -1) { warnx("bufio_read: %s", bufio_io_err(bio)); return (-1); } if (r == 0) return ret; continue; } rbuf->cur += (endln - chunk) + 2; *endln = '\0'; /* was the CRLF after the chunk? */ if (chunk == endln) continue; break; } *chunksz = hexstrtonum(chunk, 0, INT_MAX, &errstr); if (errstr != NULL) { warnx("invalid HTTP chunk: size is %s (%s)", errstr, chunk); return (-1); } if (*chunksz == 0) break; } avail = rbuf->len - rbuf->cur; if (chunked && avail > *chunksz) avail = *chunksz; if (out != NULL) { w = fwrite(rbuf->buf + rbuf->cur, 1, avail, out); if (w != avail) return (-1); } else { avail = MINIMUM(avail, bufsz); memcpy(buf, rbuf->buf + rbuf->cur, avail); } rbuf->cur += avail; ret += avail; buf += avail; bufsz -= avail; *chunksz -= avail; } return ret; } static int http_chunk(struct bufio *bio, const void *buf, size_t len) { int r; if (bufio_compose_fmt(bio, "%zx\r\n", len) == -1 || bufio_compose(bio, buf, len) == -1 || bufio_compose(bio, "\r\n", 2) == -1) return 1; do { r = bufio_write(bio); if (r == -1 && errno != EAGAIN) errx(1, "bufio_read: %s", bufio_io_err(bio)); } while (bio->wbuf.len != 0); return 0; } static int get_refs(int https, const char *host, const char *port, const char *path) { struct bufio bio; char buf[GOT_PKT_MAX]; const struct got_error *e; size_t chunksz = 0; ssize_t r; int skip; int chunked; int sock; int ret = -1; if ((sock = dial(https, host, port)) == -1) return -1; if (bufio_init(&bio)) { warnx("bufio_init"); goto err; } bufio_set_fd(&bio, sock); if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) { warnx("bufio_starttls"); goto err; } if (http_open(&bio, https, "GET", host, port, path, "info/refs", "service=git-upload-pack", NULL) == -1) goto err; /* Fetch the initial reference announcement from the server. */ if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_ADV) == -1) goto err; /* skip first pack; why git over http is like this? */ r = http_read(&bio, chunked, &chunksz, buf, 4, NULL); if (r <= 0) goto err; e = got_pkt_readlen(&skip, buf, verbose); if (e) { warnx("%s", e->msg); goto err; } /* TODO: validate it's # service=git-upload-pack\n */ while (skip > 0) { r = http_read(&bio, chunked, &chunksz, buf, MINIMUM(skip, sizeof(buf)), NULL); if (r <= 0) goto err; skip -= r; } http_read(&bio, chunked, &chunksz, NULL, 0, stdout); fflush(stdout); ret = 0; err: bufio_close_sync(&bio); bufio_free(&bio); return ret; } static int upload_request(int https, const char *host, const char *port, const char *path, FILE *in) { struct bufio bio; char buf[GOT_PKT_MAX]; const struct got_error *e; ssize_t r; size_t chunksz = 0; int t; int chunked; int sock; int ret = -1; if ((sock = dial(https, host, port)) == -1) return -1; if (bufio_init(&bio)) { warnx("bufio_init"); goto err; } bufio_set_fd(&bio, sock); if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) { warnx("bufio_starttls"); goto err; } #ifndef PROFILE /* TODO: can we push this upwards such that get_refs() is covered? */ if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif if (http_open(&bio, https, "POST", host, port, path, "git-upload-pack", NULL, UPLOAD_PACK_REQ) == -1) goto err; /* * Read have/want lines generated by got-fetch-pack and forward * them to the server in the POST request body. */ for (;;) { r = fread(buf, 1, 4, in); if (r != 4) goto err; e = got_pkt_readlen(&t, buf, verbose); if (e) { warnx("%s", e->msg); goto err; } if (t == 0) { const char *flushpkt = "0000"; if (http_chunk(&bio, flushpkt, strlen(flushpkt))) goto err; continue; /* got-fetch-pack will send "done" */ } if (t < 6) { warnx("pktline len is too small"); goto err; } r = fread(buf + 4, 1, t - 4, in); if (r != t - 4) goto err; if (http_chunk(&bio, buf, t)) goto err; /* * Once got-fetch-pack is done the server will * send pack file data. */ if (t == 9 && strncmp(buf + 4, "done\n", 5) == 0) { if (http_chunk(&bio, NULL, 0)) goto err; break; } } if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_RES) == -1) goto err; /* Fetch pack file data from server. */ http_read(&bio, chunked, &chunksz, NULL, 0, stdout); ret = 0; err: bufio_close_sync(&bio); bufio_free(&bio); return ret; } static __dead void usage(void) { fprintf(stderr, "usage: %s [-qv] proto host port path\n", getprogname()); exit(1); } int main(int argc, char **argv) { struct pollfd pfd; const char *host, *port; char *path; int https = 0; int ch; #ifndef PROFILE if (pledge("stdio rpath inet dns unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "qv")) != -1) { switch (ch) { case 'q': verbose = -1; break; case 'v': verbose++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 4) usage(); https = strcmp(argv[0], "https") == 0; #ifndef PROFILE if (https) { if (unveil("/etc/ssl/cert.pem", "r") == -1) err(1, "unveil /etc/ssl/cert.pem"); } else { /* drop "rpath" */ if (pledge("stdio inet dns unveil", NULL) == -1) err(1, "pledge"); } #else if (unveil("gmon.out", "rwc") != 0) err(1, "unveil gmon.out"); #endif if (unveil(NULL, NULL) == -1) err(1, "unveil NULL"); host = argv[1]; port = argv[2]; path = argv[3]; got_path_strip_trailing_slashes(path); if (get_refs(https, host, port, path) == -1) errx(1, "failed to get refs"); pfd.fd = 0; pfd.events = POLLIN; if (poll(&pfd, 1, INFTIM) == -1) err(1, "poll"); if ((ch = fgetc(stdin)) == EOF) return 0; ungetc(ch, stdin); if (upload_request(https, host, port, path, stdin) == -1) { fflush(tmp); errx(1, "failed to upload request"); } return 0; } got-portable-0.119/libexec/got-fetch-http/Makefile.am0000664000175000017500000000141715066536114016124 libexec_PROGRAMS = got-fetch-http include $(top_builddir)/Makefile.common got_fetch_http_SOURCES = got-fetch-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/object_parse.c got_fetch_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) if HOST_FREEBSD LDADD += -lmd endif if HOST_OPENBSD LDADD += -ltls endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) $(libtls_CFLAGS) got-portable-0.119/libexec/got-fetch-http/Makefile.in0000664000175000017500000006127015066537207016144 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-fetch-http$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd @HOST_OPENBSD_TRUE@am__append_2 = -ltls subdir = libexec/got-fetch-http ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_fetch_http_OBJECTS = got-fetch-http.$(OBJEXT) \ $(top_builddir)/lib/bufio.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) got_fetch_http_OBJECTS = $(am_got_fetch_http_OBJECTS) got_fetch_http_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bufio.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-fetch-http.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_fetch_http_SOURCES) DIST_SOURCES = $(got_fetch_http_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) $(libtls_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_fetch_http_SOURCES = got-fetch-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/object_parse.c got_fetch_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) \ $(am__append_1) $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-fetch-http/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-fetch-http/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bufio.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-fetch-http$(EXEEXT): $(got_fetch_http_OBJECTS) $(got_fetch_http_DEPENDENCIES) $(EXTRA_got_fetch_http_DEPENDENCIES) @rm -f got-fetch-http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_fetch_http_OBJECTS) $(got_fetch_http_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bufio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-fetch-http.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-fetch-http.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-fetch-http.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-commit/0000775000175000017500000000000015066537275014311 5got-portable-0.119/libexec/got-read-commit/Makefile.am0000664000175000017500000000122515066536114016254 libexec_PROGRAMS = got-read-commit include $(top_builddir)/Makefile.common got_read_commit_SOURCES = got-read-commit.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_commit_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-commit/got-read-commit.c0000664000175000017500000000712215066536114017356 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_object_qid.h" #include "got_lib_privsep.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; struct got_commit_object *commit = NULL; struct got_object_id expected_id; int fd = -1; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) break; if (imsg.hdr.type != GOT_IMSG_COMMIT_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_commit(&commit, fd, &expected_id, 0); if (err) goto done; err = got_privsep_send_commit(&ibuf, commit); got_object_commit_close(commit); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (err) break; } if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-commit/Makefile.in0000664000175000017500000005743015066537207016302 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-commit$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-commit ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_commit_OBJECTS = got-read-commit.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_commit_OBJECTS = $(am_got_read_commit_OBJECTS) got_read_commit_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-commit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_commit_SOURCES) DIST_SOURCES = $(got_read_commit_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_commit_SOURCES = got-read-commit.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_commit_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-commit/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-commit/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-commit$(EXEEXT): $(got_read_commit_OBJECTS) $(got_read_commit_DEPENDENCIES) $(EXTRA_got_read_commit_DEPENDENCIES) @rm -f got-read-commit$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_commit_OBJECTS) $(got_read_commit_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-commit.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-commit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-commit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-patch/0000775000175000017500000000000015066537275014120 5got-portable-0.119/libexec/got-read-patch/Makefile.am0000664000175000017500000000122115066536114016057 libexec_PROGRAMS = got-read-patch include $(top_builddir)/Makefile.common got_read_patch_SOURCES = got-read-patch.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_patch_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-patch/got-read-patch.c0000664000175000017500000004001215066536114016767 /* * Copyright 1986, Larry Wall * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following condition is met: * 1. Redistributions of source code must retain the above copyright notice, * this condition and the following disclaimer. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_privsep.h" struct imsgbuf ibuf; static const struct got_error * send_patch(const char *oldname, const char *newname, const char *commitid, const char *blob, const int xbit, int git) { struct got_imsg_patch p; memset(&p, 0, sizeof(p)); if (oldname != NULL) strlcpy(p.old, oldname, sizeof(p.old)); if (newname != NULL) strlcpy(p.new, newname, sizeof(p.new)); if (commitid != NULL) strlcpy(p.cid, commitid, sizeof(p.cid)); if (blob != NULL) strlcpy(p.blob, blob, sizeof(p.blob)); p.xbit = xbit; p.git = git; if (imsg_compose(&ibuf, GOT_IMSG_PATCH, 0, 0, -1, &p, sizeof(p)) == -1) return got_error_from_errno("imsg_compose GOT_IMSG_PATCH"); return NULL; } static const struct got_error * send_patch_done(void) { if (imsg_compose(&ibuf, GOT_IMSG_PATCH_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose GOT_IMSG_PATCH_EOF"); return got_privsep_flush_imsg(&ibuf); } /* based on fetchname from usr.bin/patch/util.c */ static const struct got_error * filename(const char *at, char **name) { char *tmp, *t; *name = NULL; if (*at == '\0') return NULL; while (isspace((unsigned char)*at)) at++; /* files can be created or removed by diffing against /dev/null */ if (!strncmp(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) return NULL; tmp = strdup(at); if (tmp == NULL) return got_error_from_errno("strdup"); if ((t = strchr(tmp, '\t')) != NULL) *t = '\0'; if ((t = strchr(tmp, '\n')) != NULL) *t = '\0'; *name = strdup(tmp); free(tmp); if (*name == NULL) return got_error_from_errno("strdup"); return NULL; } static int binary_deleted(const char *line) { const char *prefix = "Binary files "; const char *suffix = " and /dev/null differ\n"; size_t len, d; if (strncmp(line, prefix, strlen(prefix)) != 0) return 0; line += strlen(prefix); len = strlen(line); if (len <= strlen(suffix)) return 0; d = len - strlen(suffix); return (strcmp(line + d, suffix) == 0); } static const struct got_error * binaryfilename(const char *at, char **name) { const char *suffix = " and /dev/null differ\n"; size_t len, d; *name = NULL; len = strlen(at); if (len <= strlen(suffix)) return NULL; d = len - strlen(suffix); if (strcmp(at + d, suffix) != 0) return NULL; *name = strndup(at, d); if (*name == NULL) return got_error_from_errno("strndup"); return NULL; } static int filexbit(const char *line) { char *m; m = strchr(line, '('); if (m && !strncmp(m + 1, "mode ", 5)) return strncmp(m + 6, "755", 3) == 0; return 0; } static const struct got_error * blobid(const char *line, char **blob, int git) { size_t len; *blob = NULL; len = strspn(line, "0123456789abcdefABCDEF"); if ((*blob = strndup(line, len)) == NULL) return got_error_from_errno("strndup"); if (git) return NULL; if (len != got_hash_digest_string_length(GOT_HASH_SHA1) - 1 && len != got_hash_digest_string_length(GOT_HASH_SHA256) - 1) { /* silently ignore invalid blob ids */ free(*blob); *blob = NULL; } return NULL; } static const struct got_error * patch_start(int *git, char **cid, FILE *fp) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; *git = 0; while ((linelen = getline(&line, &linesize, fp)) != -1) { if (!strncmp(line, "diff --git ", 11)) { *git = 1; free(*cid); *cid = NULL; break; } else if (!strncmp(line, "diff ", 5)) { *git = 0; free(*cid); *cid = NULL; } else if (!strncmp(line, "commit - ", 9)) { free(*cid); err = blobid(line + 9, cid, *git); if (err) break; } else if (!strncmp(line, "--- ", 4) || !strncmp(line, "+++ ", 4) || !strncmp(line, "blob - ", 7) || binary_deleted(line)) { /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); break; } } free(line); if (ferror(fp) && err == NULL) err = got_error_from_errno("getline"); if (feof(fp) && err == NULL) err = got_error(GOT_ERR_NO_PATCH); return err; } static const struct got_error * find_diff(int *done, int *next, FILE *fp, int git, const char *commitid) { const struct got_error *err = NULL; char *old = NULL, *new = NULL; char *blob = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; int create, delete_binary = 0, rename = 0, xbit = 0; *done = 0; *next = 0; while ((linelen = getline(&line, &linesize, fp)) != -1) { /* * Ignore the Index name like GNU and larry' patch, * we don't have to follow POSIX. */ if (!strncmp(line, "--- ", 4)) { free(old); err = filename(line+4, &old); } else if (rename && !strncmp(line, "rename from ", 12)) { free(old); err = filename(line+12, &old); } else if (!strncmp(line, "+++ ", 4)) { free(new); err = filename(line+4, &new); } else if (!strncmp(line, "blob + ", 7) || !strncmp(line, "file + ", 7)) { xbit = filexbit(line); } else if (!git && !strncmp(line, "blob - ", 7)) { free(blob); err = blobid(line + 7, &blob, git); } else if (!strncmp(line, "Binary files ", 13)) { delete_binary = 1; free(old); err = binaryfilename(line + 13, &old); } else if (rename && !strncmp(line, "rename to ", 10)) { free(new); err = filename(line + 10, &new); } else if (git && !strncmp(line, "similarity index 100%", 21)) rename = 1; else if (git && !strncmp(line, "new file mode 100", 17)) xbit = strncmp(line + 17, "755", 3) == 0; else if (git && !strncmp(line, "index ", 6)) { free(blob); err = blobid(line + 6, &blob, git); } else if (!strncmp(line, "diff ", 5)) { /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); *next = 1; break; } if (err) break; /* * Git-style diffs with "similarity index 100%" don't * have any hunks and ends with the "rename to foobar" * line. */ if (rename && old != NULL && new != NULL) { *done = 1; err = send_patch(old, new, commitid, blob, xbit, git); break; } /* * Diffs that remove binary files have no hunks. */ if (delete_binary && old != NULL) { *done = 1; err = send_patch(old, new, commitid, blob, xbit, git); break; } if (!strncmp(line, "@@ -", 4)) { create = !strncmp(line+4, "0,0", 3); if ((old == NULL && new == NULL) || (!create && old == NULL)) err = got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", line); else err = send_patch(old, new, commitid, blob, xbit, git); if (err) break; /* rewind to previous line */ if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); break; } } free(old); free(new); free(blob); free(line); if (ferror(fp) && err == NULL) err = got_error_from_errno("getline"); if (feof(fp) && err == NULL) err = got_error(GOT_ERR_NO_PATCH); return err; } static const struct got_error * strtolnum(char **str, int *n) { char *p, c; const char *errstr; for (p = *str; isdigit((unsigned char)*p); ++p) /* nop */; c = *p; *p = '\0'; *n = strtonum(*str, 0, INT_MAX, &errstr); if (errstr != NULL) return got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s: %s", *str, errstr); *p = c; *str = p; return NULL; } static const struct got_error * parse_hdr(char *s, int *done, struct got_imsg_patch_hunk *hdr) { const struct got_error *err = NULL; char *s0 = s; if (strncmp(s, "@@ -", 4)) { *done = 1; return NULL; } s += 4; if (!*s) return NULL; err = strtolnum(&s, &hdr->oldfrom); if (err) return err; if (*s == ',') { s++; err = strtolnum(&s, &hdr->oldlines); if (err) return err; } else hdr->oldlines = 1; if (*s == ' ') s++; if (*s != '+' || !*++s) return got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", s0); err = strtolnum(&s, &hdr->newfrom); if (err) return err; if (*s == ',') { s++; err = strtolnum(&s, &hdr->newlines); if (err) return err; } else hdr->newlines = 1; if (*s == ' ') s++; if (*s != '@') return got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", s0); if (hdr->oldfrom >= INT_MAX - hdr->oldlines || hdr->newfrom >= INT_MAX - hdr->newlines || /* not so sure about this one */ hdr->oldlines >= INT_MAX - hdr->newlines - 1 || (hdr->oldlines == 0 && hdr->newlines == 0)) return got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", s0); if (hdr->oldlines == 0) { /* larry says to "do append rather than insert"; I don't * quite get it, but i trust him. */ hdr->oldfrom++; } if (imsg_compose(&ibuf, GOT_IMSG_PATCH_HUNK, 0, 0, -1, hdr, sizeof(*hdr)) == -1) return got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_HUNK"); return NULL; } static const struct got_error * send_line(const char *line, size_t len) { const struct got_error *err = NULL; struct iovec iov[2]; int iovcnt = 0; memset(&iov, 0, sizeof(iov)); if (*line != '+' && *line != '-' && *line != ' ' && *line != '\\') { iov[iovcnt].iov_base = (void *)" "; iov[iovcnt].iov_len = 1; iovcnt++; } iov[iovcnt].iov_base = (void *)line; iov[iovcnt].iov_len = len; iovcnt++; if (imsg_composev(&ibuf, GOT_IMSG_PATCH_LINE, 0, 0, -1, iov, iovcnt) == -1) err = got_error_from_errno( "imsg_compose GOT_IMSG_PATCH_LINE"); return err; } static const struct got_error * peek_special_line(FILE *fp) { const struct got_error *err; int ch; ch = fgetc(fp); if (ch != EOF && ch != '\\') { ungetc(ch, fp); return NULL; } if (ch == '\\') { err = send_line("\\", 2); if (err) return err; } while (ch != EOF && ch != '\n') ch = fgetc(fp); if (ch != EOF || feof(fp)) return NULL; return got_error(GOT_ERR_IO); } static const struct got_error * parse_hunk(FILE *fp, int *done) { const struct got_error *err = NULL; struct got_imsg_patch_hunk hdr; char *line = NULL, ch; size_t linesize = 0; ssize_t linelen; int leftold, leftnew; linelen = getline(&line, &linesize, fp); if (linelen == -1) { *done = 1; goto done; } if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; err = parse_hdr(line, done, &hdr); if (err) goto done; if (*done) { if (fseeko(fp, -linelen, SEEK_CUR) == -1) err = got_error_from_errno("fseeko"); goto done; } leftold = hdr.oldlines; leftnew = hdr.newlines; while (leftold > 0 || leftnew > 0) { linelen = getline(&line, &linesize, fp); if (linelen == -1) { if (ferror(fp)) { err = got_error_from_errno("getline"); goto done; } /* trailing newlines may be chopped */ if (leftold < 3 && leftnew < 3) { *done = 1; break; } err = got_error(GOT_ERR_PATCH_TRUNCATED); goto done; } if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; /* usr.bin/patch allows '=' as context char */ if (*line == '=') *line = ' '; ch = *line; if (ch == '\t' || ch == '\0') ch = ' '; /* the space got eaten */ switch (ch) { case '-': leftold--; break; case ' ': leftold--; leftnew--; break; case '+': leftnew--; break; default: err = got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", line); goto done; } if (leftold < 0 || leftnew < 0) { err = got_error_fmt(GOT_ERR_PATCH_MALFORMED, "%s", line); goto done; } err = send_line(line, linelen); if (err) goto done; if ((ch == '-' && leftold == 0) || (ch == '+' && leftnew == 0)) { err = peek_special_line(fp); if (err) goto done; } } done: free(line); return err; } static const struct got_error * read_patch(struct imsgbuf *ibuf, FILE *fp) { const struct got_error *err = NULL; int git, patch_found = 0; char *cid = NULL; while ((err = patch_start(&git, &cid, fp)) == NULL) { int done, next; err = find_diff(&done, &next, fp, git, cid); if (err) goto done; if (next) continue; patch_found = 1; while (!done) { err = parse_hunk(fp, &done); if (err) goto done; } err = send_patch_done(); if (err) goto done; } done: free(cid); /* ignore trailing gibberish */ if (err != NULL && err->code == GOT_ERR_NO_PATCH && patch_found) err = NULL; return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; struct imsg imsg; FILE *fp = NULL; int fd = -1; #if 0 static int attached; while (!attached) sleep(1); #endif if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type != GOT_IMSG_PATCH_FILE) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } fp = fdopen(fd, "r"); if (fp == NULL) { err = got_error_from_errno("fdopen"); goto done; } fd = -1; err = read_patch(&ibuf, fp); if (err) goto done; if (imsg_compose(&ibuf, GOT_IMSG_PATCH_EOF, 0, 0, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg_compose GOT_IMSG_PATCH_EOF"); goto done; } err = got_privsep_flush_imsg(&ibuf); imsg_free(&imsg); done: if (err != NULL) { if (err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); fflush(stderr); } got_privsep_send_error(&ibuf, err); } if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (fp != NULL && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); imsgbuf_clear(&ibuf); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-patch/Makefile.in0000664000175000017500000005737715066537210016115 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-patch$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-patch ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_patch_OBJECTS = got-read-patch.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_patch_OBJECTS = $(am_got_read_patch_OBJECTS) got_read_patch_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-patch.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_patch_SOURCES) DIST_SOURCES = $(got_read_patch_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_patch_SOURCES = got-read-patch.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_patch_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-patch/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-patch/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-patch$(EXEEXT): $(got_read_patch_OBJECTS) $(got_read_patch_DEPENDENCIES) $(EXTRA_got_read_patch_DEPENDENCIES) @rm -f got-read-patch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_patch_OBJECTS) $(got_read_patch_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-patch.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-patch.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-patch.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-index-pack/0000775000175000017500000000000015066537275014133 5got-portable-0.119/libexec/got-index-pack/got-index-pack.c0000664000175000017500000001436015066536114017024 /* * Copyright (c) 2019 Ori Bernstein * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_privsep.h" #include "got_lib_ratelimit.h" #include "got_lib_pack.h" #include "got_lib_pack_index.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static const struct got_error * send_index_pack_progress(void *arg, uint32_t nobj_total, uint32_t nobj_indexed, uint32_t nobj_loose, uint32_t nobj_resolved) { struct imsgbuf *ibuf = arg; struct got_imsg_index_pack_progress iprogress; iprogress.nobj_total = nobj_total; iprogress.nobj_indexed = nobj_indexed; iprogress.nobj_loose = nobj_loose; iprogress.nobj_resolved = nobj_resolved; if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_PROGRESS, 0, 0, -1, &iprogress, sizeof(iprogress)) == -1) return got_error_from_errno("imsg_compose IDXPACK_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_index_pack_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose FETCH"); return got_privsep_flush_imsg(ibuf); } int main(int argc, char **argv) { const struct got_error *err = NULL, *close_err; struct imsgbuf ibuf; struct imsg imsg; struct got_object_id pack_hash; size_t i; int idxfd = -1, tmpfd = -1; FILE *tmpfiles[3]; struct got_pack pack; off_t packfile_size; struct got_ratelimit rl; #if 0 static int attached; while (!attached) sleep(1); #endif got_ratelimit_init(&rl, 0, 500); for (i = 0; i < nitems(tmpfiles); i++) tmpfiles[i] = NULL; if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); memset(&pack, 0, sizeof(pack)); pack.fd = -1; err = got_delta_cache_alloc(&pack.delta_cache); if (err) goto done; #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_IDXPACK_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(pack_hash)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&pack_hash, imsg.data, sizeof(pack_hash)); pack.fd = imsg_get_fd(&imsg); pack.algo = pack_hash.algo; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_IDXPACK_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } idxfd = imsg_get_fd(&imsg); for (i = 0; i < nitems(tmpfiles); i++) { err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) goto done; if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_TMPFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } tmpfd = imsg_get_fd(&imsg); tmpfiles[i] = fdopen(tmpfd, "w+"); if (tmpfiles[i] == NULL) { err = got_error_from_errno("fdopen"); goto done; } tmpfd = -1; } if (lseek(pack.fd, 0, SEEK_END) == -1) { err = got_error_from_errno("lseek"); goto done; } packfile_size = lseek(pack.fd, 0, SEEK_CUR); if (packfile_size == -1) { err = got_error_from_errno("lseek"); goto done; } pack.filesize = packfile_size; if (lseek(pack.fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } #ifndef GOT_PACK_NO_MMAP if (pack.filesize > 0 && pack.filesize <= SIZE_MAX) { pack.map = mmap(NULL, pack.filesize, PROT_READ, MAP_PRIVATE, pack.fd, 0); if (pack.map == MAP_FAILED) pack.map = NULL; /* fall back to read(2) */ } #endif err = got_pack_index(&pack, idxfd, tmpfiles[0], tmpfiles[1], tmpfiles[2], &pack_hash, send_index_pack_progress, &ibuf, &rl); done: close_err = got_pack_close(&pack); if (close_err && err == NULL) err = close_err; if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (tmpfd != -1 && close(tmpfd) == -1 && err == NULL) err = got_error_from_errno("close"); for (i = 0; i < nitems(tmpfiles); i++) { if (tmpfiles[i] != NULL && fclose(tmpfiles[i]) == EOF && err == NULL) err = got_error_from_errno("fclose"); } if (err == NULL) err = send_index_pack_done(&ibuf); if (err) { got_privsep_send_error(&ibuf, err); fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); exit(1); } imsgbuf_clear(&ibuf); exit(0); } got-portable-0.119/libexec/got-index-pack/Makefile.am0000664000175000017500000000152415066536114016100 libexec_PROGRAMS = got-index-pack include $(top_builddir)/Makefile.common got_index_pack_SOURCES = got-index-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/hash.c got_index_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(libbsd_LIBS) $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-index-pack/Makefile.in0000664000175000017500000006472615066537207016132 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-index-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-index-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_index_pack_OBJECTS = got-index-pack.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_index.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) got_index_pack_OBJECTS = $(am_got_index_pack_OBJECTS) got_index_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_index.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ ./$(DEPDIR)/got-index-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_index_pack_SOURCES) DIST_SOURCES = $(got_index_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_index_pack_SOURCES = got-index-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/hash.c got_index_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(libbsd_LIBS) \ $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-index-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-index-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_index.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-index-pack$(EXEEXT): $(got_index_pack_OBJECTS) $(got_index_pack_DEPENDENCIES) $(EXTRA_got_index_pack_DEPENDENCIES) @rm -f got-index-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_index_pack_OBJECTS) $(got_index_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_index.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-index-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-index-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-index-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-gotconfig/0000775000175000017500000000000015066537275015000 5got-portable-0.119/libexec/got-read-gotconfig/parse.c0000664000175000017500000021474515066537261016206 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "gotconfig.h" static struct file { FILE *stream; const char *name; size_t ungetpos; size_t ungetsize; u_char *ungetbuf; int eof_reached; int lineno; } *file; static const struct got_error* newfile(struct file**, const char *, int *); static void closefile(struct file *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); static int parseport(char *, long long *); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); int cmdline_symset(char *); char *symget(const char *); static int atoul(char *, u_long *); static const struct got_error* gerror; static struct gotconfig_remote_repo *remote; static struct gotconfig gotconfig; static const struct got_error* new_remote(struct gotconfig_remote_repo **); static const struct got_error* new_fetch_config(struct fetch_config **); static const struct got_error* new_send_config(struct send_config **); typedef struct { union { long long number; char *string; struct node_branch *branch; struct node_ref *ref; } v; int lineno; } YYSTYPE; #if defined(__APPLE__) && !defined(YYSTYPE) #warning "Setting YYSTYPE - is GNU Bison installed?" #define YYSTYPE YYSTYPE #endif #line 153 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ ERROR = 258, /* ERROR */ REMOTE = 259, /* REMOTE */ REPOSITORY = 260, /* REPOSITORY */ SERVER = 261, /* SERVER */ PORT = 262, /* PORT */ PROTOCOL = 263, /* PROTOCOL */ MIRROR_REFERENCES = 264, /* MIRROR_REFERENCES */ BRANCH = 265, /* BRANCH */ AUTHOR = 266, /* AUTHOR */ ALLOWED_SIGNERS = 267, /* ALLOWED_SIGNERS */ REVOKED_SIGNERS = 268, /* REVOKED_SIGNERS */ SIGNER_ID = 269, /* SIGNER_ID */ FETCH_ALL_BRANCHES = 270, /* FETCH_ALL_BRANCHES */ REFERENCE = 271, /* REFERENCE */ FETCH = 272, /* FETCH */ SEND = 273, /* SEND */ STRING = 274, /* STRING */ NUMBER = 275 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define ERROR 258 #define REMOTE 259 #define REPOSITORY 260 #define SERVER 261 #define PORT 262 #define PROTOCOL 263 #define MIRROR_REFERENCES 264 #define BRANCH 265 #define AUTHOR 266 #define ALLOWED_SIGNERS 267 #define REVOKED_SIGNERS 268 #define SIGNER_ID 269 #define FETCH_ALL_BRANCHES 270 #define REFERENCE 271 #define FETCH 272 #define SEND 273 #define STRING 274 #define NUMBER 275 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_ERROR = 3, /* ERROR */ YYSYMBOL_REMOTE = 4, /* REMOTE */ YYSYMBOL_REPOSITORY = 5, /* REPOSITORY */ YYSYMBOL_SERVER = 6, /* SERVER */ YYSYMBOL_PORT = 7, /* PORT */ YYSYMBOL_PROTOCOL = 8, /* PROTOCOL */ YYSYMBOL_MIRROR_REFERENCES = 9, /* MIRROR_REFERENCES */ YYSYMBOL_BRANCH = 10, /* BRANCH */ YYSYMBOL_AUTHOR = 11, /* AUTHOR */ YYSYMBOL_ALLOWED_SIGNERS = 12, /* ALLOWED_SIGNERS */ YYSYMBOL_REVOKED_SIGNERS = 13, /* REVOKED_SIGNERS */ YYSYMBOL_SIGNER_ID = 14, /* SIGNER_ID */ YYSYMBOL_FETCH_ALL_BRANCHES = 15, /* FETCH_ALL_BRANCHES */ YYSYMBOL_REFERENCE = 16, /* REFERENCE */ YYSYMBOL_FETCH = 17, /* FETCH */ YYSYMBOL_SEND = 18, /* SEND */ YYSYMBOL_STRING = 19, /* STRING */ YYSYMBOL_NUMBER = 20, /* NUMBER */ YYSYMBOL_21_n_ = 21, /* '\n' */ YYSYMBOL_22_ = 22, /* '{' */ YYSYMBOL_23_ = 23, /* '}' */ YYSYMBOL_24_ = 24, /* ',' */ YYSYMBOL_YYACCEPT = 25, /* $accept */ YYSYMBOL_grammar = 26, /* grammar */ YYSYMBOL_boolean = 27, /* boolean */ YYSYMBOL_numberstring = 28, /* numberstring */ YYSYMBOL_portplain = 29, /* portplain */ YYSYMBOL_branch = 30, /* branch */ YYSYMBOL_xbranch = 31, /* xbranch */ YYSYMBOL_branch_list = 32, /* branch_list */ YYSYMBOL_ref = 33, /* ref */ YYSYMBOL_xref = 34, /* xref */ YYSYMBOL_ref_list = 35, /* ref_list */ YYSYMBOL_remoteopts2 = 36, /* remoteopts2 */ YYSYMBOL_remoteopts1 = 37, /* remoteopts1 */ YYSYMBOL_38_1 = 38, /* $@1 */ YYSYMBOL_39_2 = 39, /* $@2 */ YYSYMBOL_fetchempty = 40, /* fetchempty */ YYSYMBOL_fetchopts2 = 41, /* fetchopts2 */ YYSYMBOL_fetchopts1 = 42, /* fetchopts1 */ YYSYMBOL_sendempty = 43, /* sendempty */ YYSYMBOL_sendopts2 = 44, /* sendopts2 */ YYSYMBOL_sendopts1 = 45, /* sendopts1 */ YYSYMBOL_remote = 46, /* remote */ YYSYMBOL_47_3 = 47, /* $@3 */ YYSYMBOL_author = 48, /* author */ YYSYMBOL_allowed_signers = 49, /* allowed_signers */ YYSYMBOL_revoked_signers = 50, /* revoked_signers */ YYSYMBOL_signer_id = 51, /* signer_id */ YYSYMBOL_optnl = 52, /* optnl */ YYSYMBOL_nl = 53, /* nl */ YYSYMBOL_comma = 54 /* comma */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 105 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 25 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 30 /* YYNRULES -- Number of rules. */ #define YYNRULES 67 /* YYNSTATES -- Number of states. */ #define YYNSTATES 122 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 275 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 23, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 119, 119, 120, 121, 122, 123, 124, 125, 127, 142, 150, 152, 160, 161, 162, 164, 174, 175, 181, 182, 183, 185, 195, 196, 202, 203, 205, 208, 211, 214, 217, 220, 223, 226, 229, 229, 242, 242, 256, 257, 259, 260, 262, 265, 268, 271, 274, 278, 279, 281, 282, 284, 287, 290, 293, 296, 300, 300, 315, 319, 323, 327, 331, 332, 334, 336, 337 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "ERROR", "REMOTE", "REPOSITORY", "SERVER", "PORT", "PROTOCOL", "MIRROR_REFERENCES", "BRANCH", "AUTHOR", "ALLOWED_SIGNERS", "REVOKED_SIGNERS", "SIGNER_ID", "FETCH_ALL_BRANCHES", "REFERENCE", "FETCH", "SEND", "STRING", "NUMBER", "'\\n'", "'{'", "'}'", "','", "$accept", "grammar", "boolean", "numberstring", "portplain", "branch", "xbranch", "branch_list", "ref", "xref", "ref_list", "remoteopts2", "remoteopts1", "$@1", "$@2", "fetchempty", "fetchopts2", "fetchopts1", "sendempty", "sendopts2", "sendopts1", "remote", "$@3", "author", "allowed_signers", "revoked_signers", "signer_id", "optnl", "nl", "comma", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-102) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -102, 5, -102, -18, -11, 4, 10, 16, -102, 18, 22, 24, 35, 36, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 25, 41, 41, 62, -102, 44, 45, 8, 57, 66, -9, 66, 2, -102, -102, 43, 41, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 41, -102, -102, -102, -102, 41, -102, -102, 65, 67, -102, 69, -102, 72, 73, 41, 41, 41, -102, 41, 14, 41, 31, 26, 76, -102, -102, -102, -102, 72, -102, -102, 73, 74, 75, 8, 77, -9, 78, 26, 41, 79, 80, 8, 81, -9, 82, 76, 41, 41, 41, -102, -102, -102, -102, -102, -102, 69, -102, -102, -102, -102, -102, -102, -102, 69, -102, -102, -102, -102, -102 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 57, 59, 60, 61, 62, 5, 4, 6, 7, 8, 0, 64, 64, 0, 63, 0, 0, 0, 0, 0, 13, 0, 19, 35, 37, 0, 64, 27, 28, 11, 10, 12, 32, 29, 9, 30, 16, 64, 33, 14, 31, 22, 64, 34, 20, 0, 0, 58, 0, 26, 0, 0, 64, 64, 64, 25, 64, 67, 64, 67, 39, 48, 65, 17, 15, 66, 0, 23, 21, 0, 0, 0, 0, 0, 13, 0, 40, 64, 0, 0, 0, 0, 13, 0, 49, 64, 64, 64, 43, 44, 46, 45, 47, 36, 0, 42, 52, 53, 55, 54, 56, 38, 0, 51, 18, 24, 41, 50 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -102, -102, 53, -102, -83, -84, -58, -102, -102, -63, -102, -102, 56, -102, -102, -102, -102, 7, -102, -102, 6, -102, -102, -102, -102, -102, -102, -26, -101, 29 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 49, 45, 46, 52, 53, 71, 57, 58, 73, 39, 40, 59, 60, 89, 90, 91, 97, 98, 99, 9, 24, 10, 11, 12, 13, 27, 69, 80 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 28, 14, 72, 104, 106, 2, 70, 120, 15, 3, 50, 112, 114, 51, 63, 121, 4, 5, 6, 7, 101, 55, 100, 16, 56, 64, 8, 43, 44, 17, 65, 84, 85, 86, 87, 18, 88, 78, 79, 19, 74, 75, 76, 20, 77, 21, 81, 25, 29, 30, 31, 32, 33, 34, 82, 79, 22, 23, 35, 36, 37, 38, 26, 41, 42, 109, 61, 29, 30, 31, 32, 33, 34, 117, 118, 119, 47, 35, 36, 37, 38, 92, 93, 94, 95, 48, 96, 66, 54, 67, 68, 50, 55, 102, 103, 62, 105, 108, 110, 111, 113, 107, 83, 0, 116, 115 }; static const yytype_int8 yycheck[] = { 26, 19, 65, 86, 88, 0, 64, 108, 19, 4, 19, 94, 96, 22, 40, 116, 11, 12, 13, 14, 83, 19, 80, 19, 22, 51, 21, 19, 20, 19, 56, 5, 6, 7, 8, 19, 10, 23, 24, 21, 66, 67, 68, 21, 70, 21, 72, 22, 5, 6, 7, 8, 9, 10, 23, 24, 21, 21, 15, 16, 17, 18, 21, 19, 19, 91, 23, 5, 6, 7, 8, 9, 10, 99, 100, 101, 19, 15, 16, 17, 18, 5, 6, 7, 8, 19, 10, 22, 35, 22, 21, 19, 19, 19, 19, 39, 19, 90, 19, 19, 19, 23, 73, -1, 98, 23 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 26, 0, 4, 11, 12, 13, 14, 21, 46, 48, 49, 50, 51, 19, 19, 19, 19, 19, 21, 21, 21, 21, 21, 47, 22, 21, 52, 52, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18, 36, 37, 19, 19, 19, 20, 28, 29, 19, 19, 27, 19, 22, 30, 31, 27, 19, 22, 33, 34, 38, 39, 23, 37, 52, 52, 52, 22, 22, 21, 53, 31, 32, 34, 35, 52, 52, 52, 52, 23, 24, 54, 52, 23, 54, 5, 6, 7, 8, 10, 40, 41, 42, 5, 6, 7, 8, 10, 43, 44, 45, 31, 34, 19, 19, 29, 19, 30, 23, 42, 52, 19, 19, 29, 19, 30, 23, 45, 52, 52, 52, 53, 53 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 25, 26, 26, 26, 26, 26, 26, 26, 27, 28, 28, 29, 30, 30, 30, 31, 32, 32, 33, 33, 33, 34, 35, 35, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 37, 39, 37, 40, 40, 41, 41, 42, 42, 42, 42, 42, 43, 43, 44, 44, 45, 45, 45, 45, 45, 47, 46, 48, 49, 50, 51, 52, 52, 53, 54, 54 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 1, 4, 1, 2, 4, 0, 1, 4, 1, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 6, 0, 6, 0, 1, 3, 2, 2, 2, 2, 2, 2, 0, 1, 3, 2, 2, 2, 2, 2, 2, 0, 7, 2, 2, 2, 2, 2, 0, 2, 1, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 9: /* boolean: STRING */ #line 127 "parse.y" { if (strcasecmp((yyvsp[0].v.string), "true") == 0 || strcasecmp((yyvsp[0].v.string), "yes") == 0) (yyval.v.number) = 1; else if (strcasecmp((yyvsp[0].v.string), "false") == 0 || strcasecmp((yyvsp[0].v.string), "no") == 0) (yyval.v.number) = 0; else { yyerror("invalid boolean value '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1353 "parse.c" break; case 10: /* numberstring: NUMBER */ #line 142 "parse.y" { char *s; if (asprintf(&s, "%lld", (yyvsp[0].v.number)) == -1) { yyerror("string: asprintf"); YYERROR; } (yyval.v.string) = s; } #line 1366 "parse.c" break; case 12: /* portplain: numberstring */ #line 152 "parse.y" { if (parseport((yyvsp[0].v.string), &(yyval.v.number)) == -1) { free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1378 "parse.c" break; case 13: /* branch: %empty */ #line 160 "parse.y" { (yyval.v.branch) = NULL; } #line 1384 "parse.c" break; case 14: /* branch: xbranch */ #line 161 "parse.y" { (yyval.v.branch) = (yyvsp[0].v.branch); } #line 1390 "parse.c" break; case 15: /* branch: '{' optnl branch_list '}' */ #line 162 "parse.y" { (yyval.v.branch) = (yyvsp[-1].v.branch); } #line 1396 "parse.c" break; case 16: /* xbranch: STRING */ #line 164 "parse.y" { (yyval.v.branch) = calloc(1, sizeof(struct node_branch)); if ((yyval.v.branch) == NULL) { yyerror("calloc"); YYERROR; } (yyval.v.branch)->branch_name = (yyvsp[0].v.string); (yyval.v.branch)->tail = (yyval.v.branch); } #line 1410 "parse.c" break; case 17: /* branch_list: xbranch optnl */ #line 174 "parse.y" { (yyval.v.branch) = (yyvsp[-1].v.branch); } #line 1416 "parse.c" break; case 18: /* branch_list: branch_list comma xbranch optnl */ #line 175 "parse.y" { (yyvsp[-3].v.branch)->tail->next = (yyvsp[-1].v.branch); (yyvsp[-3].v.branch)->tail = (yyvsp[-1].v.branch); (yyval.v.branch) = (yyvsp[-3].v.branch); } #line 1426 "parse.c" break; case 19: /* ref: %empty */ #line 181 "parse.y" { (yyval.v.ref) = NULL; } #line 1432 "parse.c" break; case 20: /* ref: xref */ #line 182 "parse.y" { (yyval.v.ref) = (yyvsp[0].v.ref); } #line 1438 "parse.c" break; case 21: /* ref: '{' optnl ref_list '}' */ #line 183 "parse.y" { (yyval.v.ref) = (yyvsp[-1].v.ref); } #line 1444 "parse.c" break; case 22: /* xref: STRING */ #line 185 "parse.y" { (yyval.v.ref) = calloc(1, sizeof(struct node_ref)); if ((yyval.v.ref) == NULL) { yyerror("calloc"); YYERROR; } (yyval.v.ref)->ref_name = (yyvsp[0].v.string); (yyval.v.ref)->tail = (yyval.v.ref); } #line 1458 "parse.c" break; case 23: /* ref_list: xref optnl */ #line 195 "parse.y" { (yyval.v.ref) = (yyvsp[-1].v.ref); } #line 1464 "parse.c" break; case 24: /* ref_list: ref_list comma xref optnl */ #line 196 "parse.y" { (yyvsp[-3].v.ref)->tail->next = (yyvsp[-1].v.ref); (yyvsp[-3].v.ref)->tail = (yyvsp[-1].v.ref); (yyval.v.ref) = (yyvsp[-3].v.ref); } #line 1474 "parse.c" break; case 27: /* remoteopts1: REPOSITORY STRING */ #line 205 "parse.y" { remote->repository = (yyvsp[0].v.string); } #line 1482 "parse.c" break; case 28: /* remoteopts1: SERVER STRING */ #line 208 "parse.y" { remote->server = (yyvsp[0].v.string); } #line 1490 "parse.c" break; case 29: /* remoteopts1: PROTOCOL STRING */ #line 211 "parse.y" { remote->protocol = (yyvsp[0].v.string); } #line 1498 "parse.c" break; case 30: /* remoteopts1: MIRROR_REFERENCES boolean */ #line 214 "parse.y" { remote->mirror_references = (yyvsp[0].v.number); } #line 1506 "parse.c" break; case 31: /* remoteopts1: FETCH_ALL_BRANCHES boolean */ #line 217 "parse.y" { remote->fetch_all_branches = (yyvsp[0].v.number); } #line 1514 "parse.c" break; case 32: /* remoteopts1: PORT portplain */ #line 220 "parse.y" { remote->port = (yyvsp[0].v.number); } #line 1522 "parse.c" break; case 33: /* remoteopts1: BRANCH branch */ #line 223 "parse.y" { remote->branch = (yyvsp[0].v.branch); } #line 1530 "parse.c" break; case 34: /* remoteopts1: REFERENCE ref */ #line 226 "parse.y" { remote->fetch_ref = (yyvsp[0].v.ref); } #line 1538 "parse.c" break; case 35: /* $@1: %empty */ #line 229 "parse.y" { static const struct got_error* error; if (remote->fetch_config != NULL) { yyerror("fetch block already exists"); YYERROR; } error = new_fetch_config(&remote->fetch_config); if (error) { yyerror("%s", error->msg); YYERROR; } } #line 1556 "parse.c" break; case 37: /* $@2: %empty */ #line 242 "parse.y" { static const struct got_error* error; if (remote->send_config != NULL) { yyerror("send block already exists"); YYERROR; } error = new_send_config(&remote->send_config); if (error) { yyerror("%s", error->msg); YYERROR; } } #line 1574 "parse.c" break; case 43: /* fetchopts1: REPOSITORY STRING */ #line 262 "parse.y" { remote->fetch_config->repository = (yyvsp[0].v.string); } #line 1582 "parse.c" break; case 44: /* fetchopts1: SERVER STRING */ #line 265 "parse.y" { remote->fetch_config->server = (yyvsp[0].v.string); } #line 1590 "parse.c" break; case 45: /* fetchopts1: PROTOCOL STRING */ #line 268 "parse.y" { remote->fetch_config->protocol = (yyvsp[0].v.string); } #line 1598 "parse.c" break; case 46: /* fetchopts1: PORT portplain */ #line 271 "parse.y" { remote->fetch_config->port = (yyvsp[0].v.number); } #line 1606 "parse.c" break; case 47: /* fetchopts1: BRANCH branch */ #line 274 "parse.y" { remote->fetch_config->branch = (yyvsp[0].v.branch); } #line 1614 "parse.c" break; case 52: /* sendopts1: REPOSITORY STRING */ #line 284 "parse.y" { remote->send_config->repository = (yyvsp[0].v.string); } #line 1622 "parse.c" break; case 53: /* sendopts1: SERVER STRING */ #line 287 "parse.y" { remote->send_config->server = (yyvsp[0].v.string); } #line 1630 "parse.c" break; case 54: /* sendopts1: PROTOCOL STRING */ #line 290 "parse.y" { remote->send_config->protocol = (yyvsp[0].v.string); } #line 1638 "parse.c" break; case 55: /* sendopts1: PORT portplain */ #line 293 "parse.y" { remote->send_config->port = (yyvsp[0].v.number); } #line 1646 "parse.c" break; case 56: /* sendopts1: BRANCH branch */ #line 296 "parse.y" { remote->send_config->branch = (yyvsp[0].v.branch); } #line 1654 "parse.c" break; case 57: /* $@3: %empty */ #line 300 "parse.y" { static const struct got_error* error; error = new_remote(&remote); if (error) { free((yyvsp[0].v.string)); yyerror("%s", error->msg); YYERROR; } remote->name = (yyvsp[0].v.string); } #line 1670 "parse.c" break; case 58: /* remote: REMOTE STRING $@3 '{' optnl remoteopts2 '}' */ #line 310 "parse.y" { TAILQ_INSERT_TAIL(&gotconfig.remotes, remote, entry); gotconfig.nremotes++; } #line 1679 "parse.c" break; case 59: /* author: AUTHOR STRING */ #line 315 "parse.y" { gotconfig.author = (yyvsp[0].v.string); } #line 1687 "parse.c" break; case 60: /* allowed_signers: ALLOWED_SIGNERS STRING */ #line 319 "parse.y" { gotconfig.allowed_signers_file = (yyvsp[0].v.string); } #line 1695 "parse.c" break; case 61: /* revoked_signers: REVOKED_SIGNERS STRING */ #line 323 "parse.y" { gotconfig.revoked_signers_file = (yyvsp[0].v.string); } #line 1703 "parse.c" break; case 62: /* signer_id: SIGNER_ID STRING */ #line 327 "parse.y" { gotconfig.signer_id = (yyvsp[0].v.string); } #line 1711 "parse.c" break; #line 1715 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 339 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; char *err = NULL; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) { gerror = got_error_from_errno("vasprintf"); return 0; } va_end(ap); if (asprintf(&err, "%s: line %d: %s", file->name, yylval.lineno, msg) == -1) { gerror = got_error_from_errno("asprintf"); return(0); } gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err); free(msg); return(0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { {"allowed_signers", ALLOWED_SIGNERS}, {"author", AUTHOR}, {"branch", BRANCH}, {"fetch", FETCH}, {"fetch-all-branches", FETCH_ALL_BRANCHES}, /* deprecated */ {"fetch_all_branches", FETCH_ALL_BRANCHES}, {"mirror-references", MIRROR_REFERENCES}, /* deprecated */ {"mirror_references", MIRROR_REFERENCES}, {"port", PORT}, {"protocol", PROTOCOL}, {"reference", REFERENCE}, {"remote", REMOTE}, {"repository", REPOSITORY}, {"revoked_signers", REVOKED_SIGNERS}, {"send", SEND}, {"server", SERVER}, {"signer_id", SIGNER_ID}, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c, next; if (quotec) { c = igetc(); if (c == EOF) { yyerror("reached end of file while parsing " "quoted string"); } return (c); } c = igetc(); while (c == '\\') { next = igetc(); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "%s", __func__); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* Skip to either EOF or the first real EOL. */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } static long long getservice(char *n) { struct servent *s; u_long ulval; if (atoul(n, &ulval) == 0) { if (ulval == 0 || ulval > 65535) { yyerror("illegal port value %lu", ulval); return (-1); } return ulval; } else { s = getservbyname(n, "tcp"); if (s == NULL) s = getservbyname(n, "udp"); if (s == NULL) { yyerror("unknown port %s", n); return (-1); } return (s->s_port); } } static int parseport(char *port, long long *pn) { if ((*pn = getservice(port)) == -1) { *pn = 0LL; return (-1); } return (0); } int yylex(void) { char buf[8096]; char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && !expanding) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } p = val + strlen(val) - 1; lungetc(DONE_EXPAND); while (p >= val) { lungetc((unsigned char)*p); p--; } lungetc(START_EXPAND); goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc((unsigned char)*--p); c = (unsigned char)*--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } static const struct got_error* newfile(struct file **nfile, const char *filename, int *fd) { const struct got_error* error = NULL; (*nfile) = calloc(1, sizeof(struct file)); if ((*nfile) == NULL) return got_error_from_errno("calloc"); (*nfile)->stream = fdopen(*fd, "r"); if ((*nfile)->stream == NULL) { error = got_error_from_errno("fdopen"); free((*nfile)); return error; } *fd = -1; /* Stream owns the file descriptor now. */ (*nfile)->name = filename; (*nfile)->lineno = 1; (*nfile)->ungetsize = 16; (*nfile)->ungetbuf = malloc((*nfile)->ungetsize); if ((*nfile)->ungetbuf == NULL) { error = got_error_from_errno("malloc"); fclose((*nfile)->stream); free((*nfile)); return error; } return NULL; } static const struct got_error* new_remote(struct gotconfig_remote_repo **remote) { const struct got_error *error = NULL; *remote = calloc(1, sizeof(**remote)); if (*remote == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_fetch_config(struct fetch_config **fetch_config) { const struct got_error *error = NULL; *fetch_config = calloc(1, sizeof(**fetch_config)); if (*fetch_config == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_send_config(struct send_config **send_config) { const struct got_error *error = NULL; *send_config = calloc(1, sizeof(**send_config)); if (*send_config == NULL) error = got_error_from_errno("calloc"); return error; } static void closefile(struct file *file) { fclose(file->stream); free(file->ungetbuf); free(file); } const struct got_error * gotconfig_parse(struct gotconfig **conf, const char *filename, int *fd) { const struct got_error *err = NULL; struct sym *sym, *next; *conf = NULL; err = newfile(&file, filename, fd); if (err) return err; TAILQ_INIT(&gotconfig.remotes); yyparse(); closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (gerror == NULL) *conf = &gotconfig; return gerror; } static void free_fetch_config(struct fetch_config *fetch_config) { free(fetch_config->repository); free(fetch_config->server); free(fetch_config->protocol); free(fetch_config); } static void free_send_config(struct send_config *send_config) { free(send_config->repository); free(send_config->server); free(send_config->protocol); free(send_config); } void gotconfig_free(struct gotconfig *conf) { struct gotconfig_remote_repo *remote; free(conf->author); free(conf->allowed_signers_file); free(conf->revoked_signers_file); free(conf->signer_id); while (!TAILQ_EMPTY(&conf->remotes)) { remote = TAILQ_FIRST(&conf->remotes); TAILQ_REMOVE(&conf->remotes, remote, entry); if (remote->fetch_config != NULL) free_fetch_config(remote->fetch_config); if (remote->send_config != NULL) free_send_config(remote->send_config); free(remote->name); free(remote->repository); free(remote->server); free(remote->protocol); free(remote); } } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; size_t len; val = strrchr(s, '='); if (val == NULL) return (-1); len = strlen(s) - strlen(val) + 1; sym = malloc(len); if (sym == NULL) errx(1, "cmdline_symset: malloc"); strlcpy(sym, s, len); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } static int atoul(char *s, u_long *ulvalp) { u_long ulval; char *ep; errno = 0; ulval = strtoul(s, &ep, 0); if (s[0] == '\0' || *ep != '\0') return (-1); if (errno == ERANGE && ulval == ULONG_MAX) return (-1); *ulvalp = ulval; return (0); } got-portable-0.119/libexec/got-read-gotconfig/got-read-gotconfig.c0000664000175000017500000003622115066536114020536 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "gotconfig.h" /* parse.y */ static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * make_fetch_url(char **url, struct gotconfig_remote_repo *repo) { const struct got_error *err = NULL; char *s = NULL, *p = NULL; const char *protocol, *server, *repo_path; int port; *url = NULL; if (repo->fetch_config && repo->fetch_config->protocol) protocol = repo->fetch_config->protocol; else protocol = repo->protocol; if (protocol == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch protocol required for remote repository \"%s\"", repo->name); if (asprintf(&s, "%s://", protocol) == -1) return got_error_from_errno("asprintf"); if (repo->fetch_config && repo->fetch_config->server) server = repo->fetch_config->server; else server = repo->server; if (server == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch server required for remote repository \"%s\"", repo->name); p = s; s = NULL; if (asprintf(&s, "%s%s", p, server) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; if (repo->fetch_config && repo->fetch_config->server) port = repo->fetch_config->port; else port = repo->port; if (port) { p = s; s = NULL; if (asprintf(&s, "%s:%d", p, repo->port) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; } if (repo->fetch_config && repo->fetch_config->repository) repo_path = repo->fetch_config->repository; else repo_path = repo->repository; if (repo_path == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "fetch repository path required for remote " "repository \"%s\"", repo->name); while (repo_path[0] == '/') repo_path++; p = s; s = NULL; if (asprintf(&s, "%s/%s", p, repo_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; got_path_strip_trailing_slashes(s); done: if (err) { free(s); free(p); } else *url = s; return err; } static const struct got_error * make_send_url(char **url, struct gotconfig_remote_repo *repo) { const struct got_error *err = NULL; char *s = NULL, *p = NULL; const char *protocol, *server, *repo_path; int port; *url = NULL; if (repo->send_config && repo->send_config->protocol) protocol = repo->send_config->protocol; else protocol = repo->protocol; if (protocol == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send protocol required for remote repository \"%s\"", repo->name); if (asprintf(&s, "%s://", protocol) == -1) return got_error_from_errno("asprintf"); if (repo->send_config && repo->send_config->server) server = repo->send_config->server; else server = repo->server; if (server == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send server required for remote repository \"%s\"", repo->name); p = s; s = NULL; if (asprintf(&s, "%s%s", p, server) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; if (repo->send_config && repo->send_config->server) port = repo->send_config->port; else port = repo->port; if (port) { p = s; s = NULL; if (asprintf(&s, "%s:%d", p, repo->port) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; } if (repo->send_config && repo->send_config->repository) repo_path = repo->send_config->repository; else repo_path = repo->repository; if (repo_path == NULL) return got_error_fmt(GOT_ERR_PARSE_CONFIG, "send repository path required for remote " "repository \"%s\"", repo->name); while (repo_path[0] == '/') repo_path++; p = s; s = NULL; if (asprintf(&s, "%s/%s", p, repo_path) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(p); p = NULL; got_path_strip_trailing_slashes(s); done: if (err) { free(s); free(p); } else *url = s; return err; } static const struct got_error * send_gotconfig_str(struct imsgbuf *ibuf, const char *value) { size_t len = value ? strlen(value) : 0; if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_STR_VAL, 0, 0, -1, value, len) == -1) return got_error_from_errno("imsg_compose GOTCONFIG_STR_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_gotconfig_remotes(struct imsgbuf *ibuf, struct gotconfig_remote_repo_list *remotes, int nremotes) { const struct got_error *err = NULL; struct got_imsg_remotes iremotes; struct gotconfig_remote_repo *repo; char *fetch_url = NULL, *send_url = NULL; iremotes.nremotes = nremotes; if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_REMOTES, 0, 0, -1, &iremotes, sizeof(iremotes)) == -1) return got_error_from_errno("imsg_compose GOTCONFIG_REMOTES"); err = got_privsep_flush_imsg(ibuf); if (err) return err; TAILQ_FOREACH(repo, remotes, entry) { struct got_imsg_remote iremote; size_t len = sizeof(iremote); struct ibuf *wbuf; struct node_branch *branch; struct node_ref *ref; int nfetch_branches = 0, nsend_branches = 0, nfetch_refs = 0; if (repo->fetch_config && repo->fetch_config->branch) branch = repo->fetch_config->branch; else branch = repo->branch; while (branch) { branch = branch->next; nfetch_branches++; } if (repo->send_config && repo->send_config->branch) branch = repo->send_config->branch; else branch = repo->branch; while (branch) { branch = branch->next; nsend_branches++; } ref = repo->fetch_ref; while (ref) { ref = ref->next; nfetch_refs++; } iremote.nfetch_branches = nfetch_branches; iremote.nsend_branches = nsend_branches; iremote.nfetch_refs = nfetch_refs; iremote.mirror_references = repo->mirror_references; iremote.fetch_all_branches = repo->fetch_all_branches; iremote.name_len = strlen(repo->name); len += iremote.name_len; err = make_fetch_url(&fetch_url, repo); if (err) break; iremote.fetch_url_len = strlen(fetch_url); len += iremote.fetch_url_len; err = make_send_url(&send_url, repo); if (err) break; iremote.send_url_len = strlen(send_url); len += iremote.send_url_len; wbuf = imsg_create(ibuf, GOT_IMSG_GOTCONFIG_REMOTE, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno( "imsg_create GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, repo->name, iremote.name_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, fetch_url, iremote.fetch_url_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } if (imsg_add(wbuf, send_url, iremote.send_url_len) == -1) { err = got_error_from_errno( "imsg_add GOTCONFIG_REMOTE"); break; } imsg_close(ibuf, wbuf); err = got_privsep_flush_imsg(ibuf); if (err) break; free(fetch_url); fetch_url = NULL; free(send_url); send_url = NULL; if (repo->fetch_config && repo->fetch_config->branch) branch = repo->fetch_config->branch; else branch = repo->branch; while (branch) { err = send_gotconfig_str(ibuf, branch->branch_name); if (err) break; branch = branch->next; } if (repo->send_config && repo->send_config->branch) branch = repo->send_config->branch; else branch = repo->branch; while (branch) { err = send_gotconfig_str(ibuf, branch->branch_name); if (err) break; branch = branch->next; } ref = repo->fetch_ref; while (ref) { err = send_gotconfig_str(ibuf, ref->ref_name); if (err) break; ref = ref->next; } } free(fetch_url); free(send_url); return err; } static const struct got_error * validate_protocol(const char *protocol, const char *repo_name) { static char msg[512]; if (strcmp(protocol, "ssh") != 0 && strcmp(protocol, "git+ssh") != 0 && strcmp(protocol, "git") != 0 && strcmp(protocol, "git+http") != 0 && strcmp(protocol, "http") != 0 && strcmp(protocol, "https") != 0 && strcmp(protocol, "git+https") != 0) { snprintf(msg, sizeof(msg),"unknown protocol \"%s\" " "for remote repository \"%s\"", protocol, repo_name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } return NULL; } static const struct got_error * validate_config(struct gotconfig *gotconfig) { const struct got_error *err; struct gotconfig_remote_repo *repo, *repo2; static char msg[512]; TAILQ_FOREACH(repo, &gotconfig->remotes, entry) { if (repo->name == NULL) { return got_error_msg(GOT_ERR_PARSE_CONFIG, "name required for remote repository"); } TAILQ_FOREACH(repo2, &gotconfig->remotes, entry) { if (repo == repo2 || strcmp(repo->name, repo2->name) != 0) continue; snprintf(msg, sizeof(msg), "duplicate remote repository name '%s'", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->server == NULL && (repo->fetch_config == NULL || repo->fetch_config->server == NULL) && (repo->send_config == NULL || repo->send_config->server == NULL)) { snprintf(msg, sizeof(msg), "server required for remote repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->protocol == NULL && (repo->fetch_config == NULL || repo->fetch_config->protocol == NULL) && (repo->send_config == NULL || repo->send_config->protocol == NULL)) { snprintf(msg, sizeof(msg), "protocol required for remote repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } if (repo->protocol) { err = validate_protocol(repo->protocol, repo->name); if (err) return err; } if (repo->fetch_config && repo->fetch_config->protocol) { err = validate_protocol(repo->fetch_config->protocol, repo->name); if (err) return err; } if (repo->send_config && repo->send_config->protocol) { err = validate_protocol(repo->send_config->protocol, repo->name); if (err) return err; } if (repo->repository == NULL && (repo->fetch_config == NULL || repo->fetch_config->repository == NULL) && (repo->send_config == NULL || repo->send_config->repository == NULL)) { snprintf(msg, sizeof(msg), "repository path required for remote " "repository \"%s\"", repo->name); return got_error_msg(GOT_ERR_PARSE_CONFIG, msg); } } return NULL; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; struct gotconfig *gotconfig = NULL; size_t datalen; const char *filename = "got.conf"; #if 0 static int attached; while (!attached) sleep(1); #endif signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif if (argc > 1) filename = argv[1]; for (;;) { struct imsg imsg; int fd = -1, finished = 0; memset(&imsg, 0, sizeof(imsg)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { finished = 1; goto done; } switch (imsg.hdr.type) { case GOT_IMSG_GOTCONFIG_PARSE_REQUEST: datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); break; } fd = imsg_get_fd(&imsg); if (fd == -1){ err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } if (gotconfig) gotconfig_free(gotconfig); err = gotconfig_parse(&gotconfig, filename, &fd); if (err) break; err = validate_config(gotconfig); break; case GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->author ? gotconfig->author : ""); break; case GOT_IMSG_GOTCONFIG_ALLOWEDSIGNERS_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->allowed_signers_file ? gotconfig->allowed_signers_file : ""); break; case GOT_IMSG_GOTCONFIG_REVOKEDSIGNERS_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->revoked_signers_file ? gotconfig->revoked_signers_file : ""); break; case GOT_IMSG_GOTCONFIG_SIGNERID_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_str(&ibuf, gotconfig->signer_id ? gotconfig->signer_id : ""); break; case GOT_IMSG_GOTCONFIG_REMOTES_REQUEST: if (gotconfig == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_gotconfig_remotes(&ibuf, &gotconfig->remotes, gotconfig->nremotes); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } done: if (fd != -1) { if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); } imsg_free(&imsg); if (err || finished) break; } if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (gotconfig) gotconfig_free(gotconfig); imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-gotconfig/Makefile.am0000664000175000017500000000127615066536114016751 libexec_PROGRAMS = got-read-gotconfig include $(top_builddir)/Makefile.common got_read_gotconfig_SOURCES = \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ got-read-gotconfig.c \ gotconfig.h \ parse.y got_read_gotconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(libbsd_LIBS) $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-gotconfig/parse.y0000664000175000017500000004463015066536114016222 /* * Copyright (c) 2020, 2021 Tracey Emery * Copyright (c) 2020 Stefan Sperling * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "gotconfig.h" static struct file { FILE *stream; const char *name; size_t ungetpos; size_t ungetsize; u_char *ungetbuf; int eof_reached; int lineno; } *file; static const struct got_error* newfile(struct file**, const char *, int *); static void closefile(struct file *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); static int parseport(char *, long long *); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); int cmdline_symset(char *); char *symget(const char *); static int atoul(char *, u_long *); static const struct got_error* gerror; static struct gotconfig_remote_repo *remote; static struct gotconfig gotconfig; static const struct got_error* new_remote(struct gotconfig_remote_repo **); static const struct got_error* new_fetch_config(struct fetch_config **); static const struct got_error* new_send_config(struct send_config **); typedef struct { union { long long number; char *string; struct node_branch *branch; struct node_ref *ref; } v; int lineno; } YYSTYPE; #if defined(__APPLE__) && !defined(YYSTYPE) #warning "Setting YYSTYPE - is GNU Bison installed?" #define YYSTYPE YYSTYPE #endif %} %token ERROR %token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH %token AUTHOR ALLOWED_SIGNERS REVOKED_SIGNERS SIGNER_ID FETCH_ALL_BRANCHES %token REFERENCE FETCH SEND %token STRING %token NUMBER %type boolean portplain %type numberstring %type branch xbranch branch_list %type ref xref ref_list %% grammar : /* empty */ | grammar '\n' | grammar author '\n' | grammar remote '\n' | grammar allowed_signers '\n' | grammar revoked_signers '\n' | grammar signer_id '\n' ; boolean : STRING { if (strcasecmp($1, "true") == 0 || strcasecmp($1, "yes") == 0) $$ = 1; else if (strcasecmp($1, "false") == 0 || strcasecmp($1, "no") == 0) $$ = 0; else { yyerror("invalid boolean value '%s'", $1); free($1); YYERROR; } free($1); } ; numberstring : NUMBER { char *s; if (asprintf(&s, "%lld", $1) == -1) { yyerror("string: asprintf"); YYERROR; } $$ = s; } | STRING ; portplain : numberstring { if (parseport($1, &$$) == -1) { free($1); YYERROR; } free($1); } ; branch : /* empty */ { $$ = NULL; } | xbranch { $$ = $1; } | '{' optnl branch_list '}' { $$ = $3; } ; xbranch : STRING { $$ = calloc(1, sizeof(struct node_branch)); if ($$ == NULL) { yyerror("calloc"); YYERROR; } $$->branch_name = $1; $$->tail = $$; } ; branch_list : xbranch optnl { $$ = $1; } | branch_list comma xbranch optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; ref : /* empty */ { $$ = NULL; } | xref { $$ = $1; } | '{' optnl ref_list '}' { $$ = $3; } ; xref : STRING { $$ = calloc(1, sizeof(struct node_ref)); if ($$ == NULL) { yyerror("calloc"); YYERROR; } $$->ref_name = $1; $$->tail = $$; } ; ref_list : xref optnl { $$ = $1; } | ref_list comma xref optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; remoteopts2 : remoteopts2 remoteopts1 nl | remoteopts1 optnl ; remoteopts1 : REPOSITORY STRING { remote->repository = $2; } | SERVER STRING { remote->server = $2; } | PROTOCOL STRING { remote->protocol = $2; } | MIRROR_REFERENCES boolean { remote->mirror_references = $2; } | FETCH_ALL_BRANCHES boolean { remote->fetch_all_branches = $2; } | PORT portplain { remote->port = $2; } | BRANCH branch { remote->branch = $2; } | REFERENCE ref { remote->fetch_ref = $2; } | FETCH { static const struct got_error* error; if (remote->fetch_config != NULL) { yyerror("fetch block already exists"); YYERROR; } error = new_fetch_config(&remote->fetch_config); if (error) { yyerror("%s", error->msg); YYERROR; } } '{' optnl fetchempty '}' | SEND { static const struct got_error* error; if (remote->send_config != NULL) { yyerror("send block already exists"); YYERROR; } error = new_send_config(&remote->send_config); if (error) { yyerror("%s", error->msg); YYERROR; } } '{' optnl sendempty '}' ; fetchempty : /* empty */ | fetchopts2 ; fetchopts2 : fetchopts2 fetchopts1 nl | fetchopts1 optnl ; fetchopts1 : REPOSITORY STRING { remote->fetch_config->repository = $2; } | SERVER STRING { remote->fetch_config->server = $2; } | PROTOCOL STRING { remote->fetch_config->protocol = $2; } | PORT portplain { remote->fetch_config->port = $2; } | BRANCH branch { remote->fetch_config->branch = $2; } ; sendempty : /* empty */ | sendopts2 ; sendopts2 : sendopts2 sendopts1 nl | sendopts1 optnl ; sendopts1 : REPOSITORY STRING { remote->send_config->repository = $2; } | SERVER STRING { remote->send_config->server = $2; } | PROTOCOL STRING { remote->send_config->protocol = $2; } | PORT portplain { remote->send_config->port = $2; } | BRANCH branch { remote->send_config->branch = $2; } ; remote : REMOTE STRING { static const struct got_error* error; error = new_remote(&remote); if (error) { free($2); yyerror("%s", error->msg); YYERROR; } remote->name = $2; } '{' optnl remoteopts2 '}' { TAILQ_INSERT_TAIL(&gotconfig.remotes, remote, entry); gotconfig.nremotes++; } ; author : AUTHOR STRING { gotconfig.author = $2; } ; allowed_signers : ALLOWED_SIGNERS STRING { gotconfig.allowed_signers_file = $2; } ; revoked_signers : REVOKED_SIGNERS STRING { gotconfig.revoked_signers_file = $2; } ; signer_id : SIGNER_ID STRING { gotconfig.signer_id = $2; } ; optnl : '\n' optnl | /* empty */ ; nl : '\n' optnl ; comma : ',' | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; char *err = NULL; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) { gerror = got_error_from_errno("vasprintf"); return 0; } va_end(ap); if (asprintf(&err, "%s: line %d: %s", file->name, yylval.lineno, msg) == -1) { gerror = got_error_from_errno("asprintf"); return(0); } gerror = got_error_msg(GOT_ERR_PARSE_CONFIG, err); free(msg); return(0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { {"allowed_signers", ALLOWED_SIGNERS}, {"author", AUTHOR}, {"branch", BRANCH}, {"fetch", FETCH}, {"fetch-all-branches", FETCH_ALL_BRANCHES}, /* deprecated */ {"fetch_all_branches", FETCH_ALL_BRANCHES}, {"mirror-references", MIRROR_REFERENCES}, /* deprecated */ {"mirror_references", MIRROR_REFERENCES}, {"port", PORT}, {"protocol", PROTOCOL}, {"reference", REFERENCE}, {"remote", REMOTE}, {"repository", REPOSITORY}, {"revoked_signers", REVOKED_SIGNERS}, {"send", SEND}, {"server", SERVER}, {"signer_id", SIGNER_ID}, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c, next; if (quotec) { c = igetc(); if (c == EOF) { yyerror("reached end of file while parsing " "quoted string"); } return (c); } c = igetc(); while (c == '\\') { next = igetc(); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "%s", __func__); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* Skip to either EOF or the first real EOL. */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } static long long getservice(char *n) { struct servent *s; u_long ulval; if (atoul(n, &ulval) == 0) { if (ulval == 0 || ulval > 65535) { yyerror("illegal port value %lu", ulval); return (-1); } return ulval; } else { s = getservbyname(n, "tcp"); if (s == NULL) s = getservbyname(n, "udp"); if (s == NULL) { yyerror("unknown port %s", n); return (-1); } return (s->s_port); } } static int parseport(char *port, long long *pn) { if ((*pn = getservice(port)) == -1) { *pn = 0LL; return (-1); } return (0); } int yylex(void) { char buf[8096]; char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && !expanding) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } p = val + strlen(val) - 1; lungetc(DONE_EXPAND); while (p >= val) { lungetc((unsigned char)*p); p--; } lungetc(START_EXPAND); goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc((unsigned char)*--p); c = (unsigned char)*--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((size_t)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "%s", __func__); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } static const struct got_error* newfile(struct file **nfile, const char *filename, int *fd) { const struct got_error* error = NULL; (*nfile) = calloc(1, sizeof(struct file)); if ((*nfile) == NULL) return got_error_from_errno("calloc"); (*nfile)->stream = fdopen(*fd, "r"); if ((*nfile)->stream == NULL) { error = got_error_from_errno("fdopen"); free((*nfile)); return error; } *fd = -1; /* Stream owns the file descriptor now. */ (*nfile)->name = filename; (*nfile)->lineno = 1; (*nfile)->ungetsize = 16; (*nfile)->ungetbuf = malloc((*nfile)->ungetsize); if ((*nfile)->ungetbuf == NULL) { error = got_error_from_errno("malloc"); fclose((*nfile)->stream); free((*nfile)); return error; } return NULL; } static const struct got_error* new_remote(struct gotconfig_remote_repo **remote) { const struct got_error *error = NULL; *remote = calloc(1, sizeof(**remote)); if (*remote == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_fetch_config(struct fetch_config **fetch_config) { const struct got_error *error = NULL; *fetch_config = calloc(1, sizeof(**fetch_config)); if (*fetch_config == NULL) error = got_error_from_errno("calloc"); return error; } static const struct got_error* new_send_config(struct send_config **send_config) { const struct got_error *error = NULL; *send_config = calloc(1, sizeof(**send_config)); if (*send_config == NULL) error = got_error_from_errno("calloc"); return error; } static void closefile(struct file *file) { fclose(file->stream); free(file->ungetbuf); free(file); } const struct got_error * gotconfig_parse(struct gotconfig **conf, const char *filename, int *fd) { const struct got_error *err = NULL; struct sym *sym, *next; *conf = NULL; err = newfile(&file, filename, fd); if (err) return err; TAILQ_INIT(&gotconfig.remotes); yyparse(); closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (gerror == NULL) *conf = &gotconfig; return gerror; } static void free_fetch_config(struct fetch_config *fetch_config) { free(fetch_config->repository); free(fetch_config->server); free(fetch_config->protocol); free(fetch_config); } static void free_send_config(struct send_config *send_config) { free(send_config->repository); free(send_config->server); free(send_config->protocol); free(send_config); } void gotconfig_free(struct gotconfig *conf) { struct gotconfig_remote_repo *remote; free(conf->author); free(conf->allowed_signers_file); free(conf->revoked_signers_file); free(conf->signer_id); while (!TAILQ_EMPTY(&conf->remotes)) { remote = TAILQ_FIRST(&conf->remotes); TAILQ_REMOVE(&conf->remotes, remote, entry); if (remote->fetch_config != NULL) free_fetch_config(remote->fetch_config); if (remote->send_config != NULL) free_send_config(remote->send_config); free(remote->name); free(remote->repository); free(remote->server); free(remote->protocol); free(remote); } } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; size_t len; val = strrchr(s, '='); if (val == NULL) return (-1); len = strlen(s) - strlen(val) + 1; sym = malloc(len); if (sym == NULL) errx(1, "cmdline_symset: malloc"); strlcpy(sym, s, len); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } static int atoul(char *s, u_long *ulvalp) { u_long ulval; char *ep; errno = 0; ulval = strtoul(s, &ep, 0); if (s[0] == '\0' || *ep != '\0') return (-1); if (errno == ERANGE && ulval == ULONG_MAX) return (-1); *ulvalp = ulval; return (0); } got-portable-0.119/libexec/got-read-gotconfig/gotconfig.h0000664000175000017500000000423715066535722017051 /* * Copyright (c) 2022 Josh Rickmar * Copyright (c) 2020, 2021 Tracey Emery * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * We maintain two different structures for fetch and send configuration * settings in case they diverge in the future. */ struct fetch_config { char *repository; char *server; char *protocol; int port; struct node_branch *branch; }; struct send_config { char *repository; char *server; char *protocol; int port; struct node_branch *branch; }; struct node_branch { char *branch_name; struct node_branch *next; struct node_branch *tail; }; struct node_ref { char *ref_name; struct node_ref *next; struct node_ref *tail; }; struct gotconfig_remote_repo { TAILQ_ENTRY(gotconfig_remote_repo) entry; char *name; char *repository; char *server; char *protocol; int port; int mirror_references; int fetch_all_branches; struct node_branch *branch; struct node_ref *fetch_ref; struct fetch_config *fetch_config; struct send_config *send_config; }; TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo); struct gotconfig { char *author; struct gotconfig_remote_repo_list remotes; int nremotes; char *allowed_signers_file; char *revoked_signers_file; char *signer_id; }; /* * Parse individual gotconfig repository files */ const struct got_error *gotconfig_parse(struct gotconfig **, const char *, int *); void gotconfig_free(struct gotconfig *); got-portable-0.119/libexec/got-read-gotconfig/Makefile.in0000664000175000017500000006107115066537207016765 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-gotconfig$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-gotconfig ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_gotconfig_OBJECTS = $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ got-read-gotconfig.$(OBJEXT) parse.$(OBJEXT) got_read_gotconfig_OBJECTS = $(am_got_read_gotconfig_OBJECTS) got_read_gotconfig_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-gotconfig.Po ./$(DEPDIR)/parse.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(got_read_gotconfig_SOURCES) DIST_SOURCES = $(got_read_gotconfig_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_gotconfig_SOURCES = \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ got-read-gotconfig.c \ gotconfig.h \ parse.y got_read_gotconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(libbsd_LIBS) \ $(zlib_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-gotconfig/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-gotconfig/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-gotconfig$(EXEEXT): $(got_read_gotconfig_OBJECTS) $(got_read_gotconfig_DEPENDENCIES) $(EXTRA_got_read_gotconfig_DEPENDENCIES) @rm -f got-read-gotconfig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_gotconfig_OBJECTS) $(got_read_gotconfig_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -$(am__rm_f) parse.c clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gotconfig.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gotconfig.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-blob/0000775000175000017500000000000015066537275013737 5got-portable-0.119/libexec/got-read-blob/got-read-blob.c0000664000175000017500000001260215066536114016431 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_inflate.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg, imsg_outfd; FILE *f = NULL; int fd = -1, outfd = -1, finished = 0; size_t size; struct got_object *obj = NULL; uint8_t *buf = NULL; struct got_object_id id; struct got_object_id expected_id; struct got_inflate_checksum csum; struct got_hash ctx; memset(&imsg, 0, sizeof(imsg)); memset(&imsg_outfd, 0, sizeof(imsg_outfd)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { finished = 1; goto done; } if (imsg.hdr.type != GOT_IMSG_BLOB_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(expected_id)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&expected_id, imsg.data, sizeof(expected_id)); fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0); if (err) { if (imsg.hdr.len == 0) err = NULL; break; } if (imsg_outfd.hdr.type == GOT_IMSG_STOP) break; if (imsg_outfd.hdr.type != GOT_IMSG_BLOB_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } outfd = imsg_get_fd(&imsg_outfd); if (outfd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_object_read_header(&obj, fd); if (err) goto done; if (lseek(fd, 0L, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } f = fdopen(fd, "rb"); if (f == NULL) { err = got_error_from_errno("fdopen"); goto done; } fd = -1; got_hash_init(&ctx, expected_id.algo); memset(&csum, 0, sizeof(csum)); csum.output_ctx = &ctx; if (obj->size + obj->hdrlen <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX) { err = got_inflate_to_mem(&buf, &size, NULL, &csum, f); if (err) goto done; } else { err = got_inflate_to_fd(&size, f, &csum, outfd); if (err) goto done; } got_hash_final_object_id(&ctx, &id); if (got_object_id_cmp(&expected_id, &id) != 0) { err = got_error_checksum(&expected_id); goto done; } if (size < obj->hdrlen) { err = got_error(GOT_ERR_BAD_OBJ_HDR); goto done; } err = got_privsep_send_blob(&ibuf, size, obj->hdrlen, buf); done: free(buf); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (outfd != -1 && close(outfd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); imsg_free(&imsg_outfd); if (obj) { got_object_close(obj); obj = NULL; } if (err || finished) break; } if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-blob/Makefile.am0000664000175000017500000000121515066536114015701 libexec_PROGRAMS = got-read-blob include $(top_builddir)/Makefile.common got_read_blob_SOURCES = got-read-blob.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_blob_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-blob/Makefile.in0000664000175000017500000005734615066537207015736 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-blob$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-blob ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_blob_OBJECTS = got-read-blob.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_blob_OBJECTS = $(am_got_read_blob_OBJECTS) got_read_blob_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-blob.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_blob_SOURCES) DIST_SOURCES = $(got_read_blob_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_blob_SOURCES = got-read-blob.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_blob_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-blob/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-blob/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-blob$(EXEEXT): $(got_read_blob_OBJECTS) $(got_read_blob_DEPENDENCIES) $(EXTRA_got_read_blob_DEPENDENCIES) @rm -f got-read-blob$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_blob_OBJECTS) $(got_read_blob_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-blob.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-blob.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-blob.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-fetch-pack/0000775000175000017500000000000015066537275014115 5got-portable-0.119/libexec/got-fetch-pack/Makefile.am0000664000175000017500000000136015066536114016060 libexec_PROGRAMS = got-fetch-pack include $(top_builddir)/Makefile.common got_fetch_pack_SOURCES = \ got-fetch-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c got_fetch_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-fetch-pack/got-fetch-pack.c0000664000175000017500000007343715066536114017002 /* * Copyright (c) 2019 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_version.h" #include "got_fetch.h" #include "got_reference.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_parse.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" #include "got_lib_poll.h" #include "got_lib_gitproto.h" #include "got_lib_ratelimit.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct got_object *indexed; static int chattygot; static const struct got_capability got_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, { GOT_CAPA_SIDE_BAND_64K, NULL }, }; static void match_remote_ref(struct got_pathlist_head *have_refs, struct got_object_id *my_id, const char *refname) { struct got_pathlist_entry *pe; /* XXX zero-hash signifies we don't have this ref; * we should use a flag instead */ memset(my_id, 0, sizeof(*my_id)); RB_FOREACH(pe, got_pathlist_head, have_refs) { struct got_object_id *id = pe->data; if (strcmp(pe->path, refname) == 0) { memcpy(my_id, id, sizeof(*my_id)); break; } } } static int match_branch(const char *branch, const char *wanted_branch) { if (strncmp(branch, "refs/heads/", 11) != 0) return 0; if (strncmp(wanted_branch, "refs/heads/", 11) == 0) wanted_branch += 11; return (strcmp(branch + 11, wanted_branch) == 0); } static int match_wanted_ref(const char *refname, const char *wanted_ref) { if (strncmp(refname, "refs/", 5) != 0) return 0; refname += 5; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ if (strncmp(refname, "got/", 4) == 0) return 0; if (strncmp(refname, "remotes/", 8) == 0) return 0; if (strncmp(wanted_ref, "refs/", 5) == 0) wanted_ref += 5; /* Allow prefix match. */ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) return 1; /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); } static const struct got_error * send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg, size_t msglen) { if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); if (msglen == 0) return NULL; if (imsg_compose(ibuf, GOT_IMSG_FETCH_SERVER_PROGRESS, 0, 0, -1, msg, msglen) == -1) return got_error_from_errno( "imsg_compose FETCH_SERVER_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_download_progress(struct imsgbuf *ibuf, off_t bytes, struct got_ratelimit *rl) { const struct got_error *err; int elapsed = 0; if (rl) { err = got_ratelimit_check(&elapsed, rl); if (err || !elapsed) return err; } if (imsg_compose(ibuf, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, 0, 0, -1, &bytes, sizeof(bytes)) == -1) return got_error_from_errno( "imsg_compose FETCH_DOWNLOAD_PROGRESS"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_done(struct imsgbuf *ibuf, uint8_t *pack_sha1) { if (imsg_compose(ibuf, GOT_IMSG_FETCH_DONE, 0, 0, -1, pack_sha1, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_compose FETCH"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len) { size_t i; if (len == 0) return NULL; /* * Truncate messages which exceed the maximum imsg payload size. * Server may send up to 64k. */ if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) len = MAX_IMSGSIZE - IMSG_HEADER_SIZE; /* * We only allow printable ASCII for safety reasons and silently * ignore non-ASCII messages, which may be somewhat legitimately * caused by Git servers running in a non-English language locale. */ for (i = 0; i < len; i++) { if (isprint((unsigned char)buf[i]) || isspace((unsigned char)buf[i])) continue; return NULL; } return send_fetch_server_progress(ibuf, buf, len); } static const struct got_error * fetch_error(const char *buf, size_t len) { static char msg[1024]; size_t i; for (i = 0; i < len && i < sizeof(msg) - 1; i++) { if (!isprint((unsigned char)buf[i])) return got_error_msg(GOT_ERR_BAD_PACKET, "non-printable error message received from server"); msg[i] = buf[i]; } msg[i] = '\0'; return got_error_msg(GOT_ERR_FETCH_FAILED, msg); } static const struct got_error * send_fetch_symrefs(struct imsgbuf *ibuf, struct got_pathlist_head *symrefs) { struct ibuf *wbuf; size_t len, nsymrefs = 0; struct got_pathlist_entry *pe; len = sizeof(struct got_imsg_fetch_symrefs); RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *target = pe->data; len += sizeof(struct got_imsg_fetch_symref) + pe->path_len + strlen(target); nsymrefs++; } if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_SYMREFS, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create FETCH_SYMREFS"); /* Keep in sync with struct got_imsg_fetch_symrefs definition! */ if (imsg_add(wbuf, &nsymrefs, sizeof(nsymrefs)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *name = pe->path; size_t name_len = pe->path_len; const char *target = pe->data; size_t target_len = strlen(target); /* Keep in sync with struct got_imsg_fetch_symref definition! */ if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, &target_len, sizeof(target_len)) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, name, name_len) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); if (imsg_add(wbuf, target, target_len) == -1) return got_error_from_errno("imsg_add FETCH_SYMREFS"); } imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_fetch_ref(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { struct ibuf *wbuf; size_t len, reflen = strlen(refname); len = sizeof(struct got_imsg_fetch_ref) + reflen; if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REF, 0, 0, len); if (wbuf == NULL) return got_error_from_errno("imsg_create FETCH_REF"); /* Keep in sync with struct got_imsg_fetch_ref definition! */ if (imsg_add(wbuf, refid, sizeof(*refid)) == -1) return got_error_from_errno("imsg_add FETCH_REF"); if (imsg_add(wbuf, refname, reflen) == -1) return got_error_from_errno("imsg_add FETCH_REF"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * fetch_ref(struct imsgbuf *ibuf, struct got_pathlist_head *have_refs, struct got_object_id *have, struct got_object_id *want, const char *refname, const char *id_str) { const struct got_error *err; char *theirs = NULL, *mine = NULL; if (!got_parse_object_id(want, id_str, GOT_HASH_SHA1)) { err = got_error(GOT_ERR_BAD_OBJ_ID_STR); goto done; } match_remote_ref(have_refs, have, refname); err = send_fetch_ref(ibuf, want, refname); if (err) goto done; if (chattygot) fprintf(stderr, "%s: %s will be fetched\n", getprogname(), refname); if (chattygot > 1) { err = got_object_id_str(&theirs, want); if (err) goto done; err = got_object_id_str(&mine, have); if (err) goto done; fprintf(stderr, "%s: remote: %s\n%s: local: %s\n", getprogname(), theirs, getprogname(), mine); } done: free(theirs); free(mine); return err; } static const struct got_error * fetch_pack(int fd, int packfd, uint8_t *pack_sha1, struct got_pathlist_head *have_refs, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int list_refs_only, const char *worktree_branch, const char *remote_head, int no_head, struct imsgbuf *ibuf) { const struct got_error *err = NULL; char buf[GOT_PKT_MAX]; char hashstr[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id *have, *want; int is_firstpkt = 1, nref = 0, refsz = 16; int i, n, nwant = 0, nhave = 0, acked = 0, eof = 0; off_t packsz = 0, last_reported_packsz = 0; char *id_str = NULL, *default_id_str = NULL, *refname = NULL; char *server_capabilities = NULL, *my_capabilities = NULL; const char *default_branch = NULL; char *free_default_branch = NULL; struct got_pathlist_head symrefs; struct got_pathlist_entry *pe; int sent_my_capabilites = 0, have_sidebands = 0; int found_branch = 0; struct got_hash ctx; uint8_t sha1_buf[SHA1_DIGEST_LENGTH]; size_t sha1_buf_len = 0; ssize_t w; struct got_ratelimit rl; RB_INIT(&symrefs); got_hash_init(&ctx, GOT_HASH_SHA1); got_ratelimit_init(&rl, 0, 500); have = malloc(refsz * sizeof(have[0])); if (have == NULL) return got_error_from_errno("malloc"); want = malloc(refsz * sizeof(want[0])); if (want == NULL) { err = got_error_from_errno("malloc"); goto done; } while (1) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n == 0) break; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = fetch_error(&buf[4], n - 4); goto done; } free(id_str); free(refname); err = got_gitproto_parse_refline(&id_str, &refname, &server_capabilities, buf, n); if (err) goto done; if (refsz == nref + 1) { struct got_object_id *h, *w; refsz *= 2; h = reallocarray(have, refsz, sizeof(have[0])); if (h == NULL) { err = got_error_from_errno("reallocarray"); goto done; } have = h; w = reallocarray(want, refsz, sizeof(want[0])); if (w == NULL) { err = got_error_from_errno("reallocarray"); goto done; } want = w; } if (is_firstpkt) { if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); err = got_gitproto_match_capabilities(&my_capabilities, &symrefs, server_capabilities, got_capabilities, nitems(got_capabilities)); if (err) goto done; if (chattygot) fprintf(stderr, "%s: my capabilities:%s\n", getprogname(), my_capabilities != NULL ? my_capabilities : ""); err = send_fetch_symrefs(ibuf, &symrefs); if (err) goto done; is_firstpkt = 0; if (!fetch_all_branches) { RB_FOREACH(pe, got_pathlist_head, &symrefs) { const char *name = pe->path; const char *symref_target = pe->data; if (strcmp(name, GOT_REF_HEAD) != 0) continue; default_branch = symref_target; break; } } if (default_branch) continue; } if (strstr(refname, "^{}")) { if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } continue; } if (default_branch == NULL && strcmp(refname, GOT_REF_HEAD) == 0) { default_id_str = strdup(id_str); if (default_id_str == NULL) { err = got_error_from_errno("strdup"); goto done; } } if (default_branch && default_id_str == NULL && strcmp(refname, default_branch) == 0) { default_id_str = strdup(id_str); if (default_id_str == NULL) { err = got_error_from_errno("strdup"); goto done; } } /* If no symrefs is given, go for first matching id_str */ if (default_branch == NULL && default_id_str && strncmp(refname, "refs/heads/", 11) == 0 && strcmp(id_str, default_id_str) == 0) { free_default_branch = strdup(refname); if (free_default_branch == NULL) { err = got_error_from_errno("strdup"); goto done; } default_branch = free_default_branch; } if (list_refs_only || strncmp(refname, "refs/tags/", 10) == 0) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; } else if (strncmp(refname, "refs/heads/", 11) == 0) { if (fetch_all_branches) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; found_branch = 1; continue; } RB_FOREACH(pe, got_pathlist_head, wanted_branches) { if (match_branch(refname, pe->path)) break; } if (pe != NULL || (worktree_branch != NULL && match_branch(refname, worktree_branch))) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; found_branch = 1; } else if (chattygot && (default_branch == NULL || strcmp(default_branch, refname) != 0)) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } } else { RB_FOREACH(pe, got_pathlist_head, wanted_refs) { if (match_wanted_ref(refname, pe->path)) break; } if (pe != NULL) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], refname, id_str); if (err) goto done; nref++; } else if (chattygot) { fprintf(stderr, "%s: ignoring %s\n", getprogname(), refname); } } } if (list_refs_only) goto done; /* * If -b was not used and either none of the requested branches * (got.conf, worktree) were found or the client already has the * remote HEAD symref but its target changed, fetch remote's HEAD. */ if (!no_head && default_branch && default_id_str && strncmp(default_branch, "refs/heads/", 11) == 0) { int remote_head_changed = 0; if (remote_head) { if (strcmp(remote_head, default_branch + 11) != 0) remote_head_changed = 1; } if (!found_branch || remote_head_changed) { err = fetch_ref(ibuf, have_refs, &have[nref], &want[nref], default_branch, default_id_str); if (err) goto done; nref++; } } /* Abort if we haven't found anything to fetch. */ if (nref == 0) { struct got_pathlist_entry *pe; static char msg[PATH_MAX + 33]; pe = RB_MIN(got_pathlist_head, wanted_branches); if (pe) { snprintf(msg, sizeof(msg), "branch \"%s\" not found on server", pe->path); err = got_error_msg(GOT_ERR_FETCH_NO_BRANCH, msg); goto done; } pe = RB_MIN(got_pathlist_head, wanted_refs); if (pe) { snprintf(msg, sizeof(msg), "reference \"%s\" not found on server", pe->path); err = got_error_msg(GOT_ERR_FETCH_NO_BRANCH, msg); goto done; } err = got_error(GOT_ERR_FETCH_NO_BRANCH); goto done; } for (i = 0; i < nref; i++) { if (got_object_id_cmp(&have[i], &want[i]) == 0) continue; got_object_id_hex(&want[i], hashstr, sizeof(hashstr)); n = snprintf(buf, sizeof(buf), "want %s%s\n", hashstr, sent_my_capabilites || my_capabilities == NULL ? "" : my_capabilities); if (n < 0 || (size_t)n >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; sent_my_capabilites = 1; nwant++; } err = got_pkt_flushpkt(fd, chattygot); if (err) goto done; if (nwant == 0) goto done; RB_FOREACH(pe, got_pathlist_head, have_refs) { struct got_object_id *id = pe->data; got_object_id_hex(id, hashstr, sizeof(hashstr)); n = snprintf(buf, sizeof(buf), "have %s\n", hashstr); if (n < 0 || (size_t)n >= sizeof(buf)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; nhave++; } n = strlcpy(buf, "done\n", sizeof(buf)); err = got_pkt_writepkt(fd, buf, n, chattygot); if (err) goto done; while (nhave > 0 && !acked) { struct got_object_id common_id; /* The server should ACK the object IDs we need. */ err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { err = fetch_error(&buf[4], n - 4); goto done; } if (n >= 4 && strncmp(buf, "NAK\n", 4) == 0) { /* * Server could not find a common ancestor. * Perhaps it is an out-of-date mirror, or there * is a repository with unrelated history. */ break; } if (n < 4 + SHA1_DIGEST_STRING_LENGTH || strncmp(buf, "ACK ", 4) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } if (!got_parse_object_id(&common_id, buf + 4, GOT_HASH_SHA1)) { err = got_error_msg(GOT_ERR_BAD_PACKET, "bad object ID in ACK packet from server"); goto done; } acked++; } if (nhave == 0) { err = got_pkt_readpkt(&n, fd, buf, sizeof(buf), chattygot, INFTIM); if (err) goto done; if (n != 4 || strncmp(buf, "NAK\n", n) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } } if (chattygot) fprintf(stderr, "%s: fetching...\n", getprogname()); if (my_capabilities != NULL && strstr(my_capabilities, GOT_CAPA_SIDE_BAND_64K) != NULL) have_sidebands = 1; while (!eof) { ssize_t r = 0; int datalen = -1; if (have_sidebands) { err = got_pkt_readhdr(&datalen, fd, chattygot, INFTIM); if (err) goto done; if (datalen <= 0) break; /* Read sideband channel ID (one byte). */ r = read(fd, buf, 1); if (r == -1) { err = got_error_from_errno("read"); goto done; } if (r != 1) { err = got_error_msg(GOT_ERR_BAD_PACKET, "short packet"); goto done; } if (datalen > sizeof(buf) - 5) { err = got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length"); goto done; } datalen--; /* sideband ID has been read */ if (buf[0] == GOT_SIDEBAND_PACKFILE_DATA) { /* Read packfile data. */ err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } } else if (buf[0] == GOT_SIDEBAND_PROGRESS_INFO) { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } err = fetch_progress(ibuf, buf, r); if (err) goto done; continue; } else if (buf[0] == GOT_SIDEBAND_ERROR_INFO) { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } err = fetch_error(buf, r); goto done; } else if (buf[0] == 'A') { err = got_pkt_readn(&r, fd, buf, datalen, INFTIM); if (err) goto done; if (r != datalen) { err = got_error_msg(GOT_ERR_BAD_PACKET, "packet too short"); goto done; } /* * Git server responds with ACK after 'done' * even though multi_ack is disabled?!? */ buf[r] = '\0'; if (strncmp(buf, "CK ", 3) == 0) continue; /* ignore */ err = got_error_msg(GOT_ERR_BAD_PACKET, "unexpected message from server"); goto done; } else { err = got_error_msg(GOT_ERR_BAD_PACKET, "unknown side-band received from server"); goto done; } } else { /* No sideband channel. Every byte is packfile data. */ size_t n = 0; err = got_poll_read_full_timeout(fd, &n, buf, sizeof buf, 1, INFTIM); if (err) { if (err->code != GOT_ERR_EOF) goto done; r = 0; eof = 1; } else r = n; } /* * An expected SHA1 checksum sits at the end of the pack file. * Since we don't know the file size ahead of time we have to * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing * those bytes into our SHA1 checksum computation until we * know for sure that additional pack file data bytes follow. */ if (r < SHA1_DIGEST_LENGTH) { if (sha1_buf_len < SHA1_DIGEST_LENGTH) { /* * If there's enough buffered + read data to * fill up the buffer then shift a sufficient * amount of bytes out at the front to make * room, mixing those bytes into the checksum. */ if (sha1_buf_len > 0 && sha1_buf_len + r > SHA1_DIGEST_LENGTH) { size_t nshift = MIN(sha1_buf_len + r - SHA1_DIGEST_LENGTH, sha1_buf_len); got_hash_update(&ctx, sha1_buf, nshift); memmove(sha1_buf, sha1_buf + nshift, sha1_buf_len - nshift); sha1_buf_len -= nshift; } /* Buffer potential checksum bytes. */ memcpy(sha1_buf + sha1_buf_len, buf, r); sha1_buf_len += r; } else if (r > 0) { /* * Mix in previously buffered bytes which * are not part of the checksum after all. */ got_hash_update(&ctx, sha1_buf, r); /* Update potential checksum buffer. */ memmove(sha1_buf, sha1_buf + r, sha1_buf_len - r); memcpy(sha1_buf + sha1_buf_len - r, buf, r); } } else { /* Mix in any previously buffered bytes. */ got_hash_update(&ctx, sha1_buf, sha1_buf_len); /* Mix in bytes read minus potential checksum bytes. */ got_hash_update(&ctx, buf, r - SHA1_DIGEST_LENGTH); /* Buffer potential checksum bytes. */ memcpy(sha1_buf, buf + r - SHA1_DIGEST_LENGTH, SHA1_DIGEST_LENGTH); sha1_buf_len = SHA1_DIGEST_LENGTH; } /* Write packfile data to temporary pack file. */ w = write(packfd, buf, r); if (w == -1) { err = got_error_from_errno("write"); goto done; } if (w != r) { err = got_error(GOT_ERR_IO); goto done; } packsz += w; /* Don't send too many progress privsep messages. */ if (packsz > last_reported_packsz + 1024) { err = send_fetch_download_progress(ibuf, packsz, &rl); if (err) goto done; last_reported_packsz = packsz; } } err = send_fetch_download_progress(ibuf, packsz, NULL); if (err) goto done; got_hash_final(&ctx, pack_sha1); if (sha1_buf_len != SHA1_DIGEST_LENGTH || memcmp(pack_sha1, sha1_buf, sha1_buf_len) != 0) { err = got_error_msg(GOT_ERR_BAD_PACKFILE, "pack file checksum mismatch"); } done: got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); free(have); free(want); free(id_str); free(free_default_branch); free(default_id_str); free(refname); free(server_capabilities); free(my_capabilities); return err; } int main(int argc, char **argv) { const struct got_error *err = NULL; int fetchfd = -1, packfd = -1; uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; struct imsgbuf ibuf; struct imsg imsg; struct got_pathlist_head have_refs; struct got_pathlist_head wanted_branches; struct got_pathlist_head wanted_refs; struct got_imsg_fetch_request fetch_req; struct got_imsg_fetch_have_ref href; struct got_imsg_fetch_wanted_branch wbranch; struct got_imsg_fetch_wanted_ref wref; size_t datalen, i; struct got_pathlist_entry *new; char *remote_head = NULL, *worktree_branch = NULL; #if 0 static int attached; while (!attached) sleep (1); #endif RB_INIT(&have_refs); RB_INIT(&wanted_branches); RB_INIT(&wanted_refs); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(fetch_req)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&fetch_req, imsg.data, sizeof(fetch_req)); fetchfd = imsg_get_fd(&imsg); if (datalen != sizeof(fetch_req) + fetch_req.worktree_branch_len + fetch_req.remote_head_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (fetch_req.worktree_branch_len != 0) { worktree_branch = strndup(imsg.data + sizeof(fetch_req), fetch_req.worktree_branch_len); if (worktree_branch == NULL) { err = got_error_from_errno("strndup"); goto done; } } if (fetch_req.remote_head_len != 0) { remote_head = strndup(imsg.data + sizeof(fetch_req) + fetch_req.worktree_branch_len, fetch_req.remote_head_len); if (remote_head == NULL) { err = got_error_from_errno("strndup"); goto done; } } imsg_free(&imsg); if (fetch_req.verbosity > 0) chattygot += fetch_req.verbosity; for (i = 0; i < fetch_req.n_have_refs; i++) { struct got_object_id *id; char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_HAVE_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(href)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&href, imsg.data, sizeof(href)); if (datalen - sizeof(href) < href.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(href), href.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } id = malloc(sizeof(*id)); if (id == NULL) { free(refname); err = got_error_from_errno("malloc"); goto done; } memcpy(id, &href.id, sizeof(*id)); err = got_pathlist_insert(&new, &have_refs, refname, id); if (err || new == NULL) { free(refname); free(id); if (err) goto done; } imsg_free(&imsg); } for (i = 0; i < fetch_req.n_wanted_branches; i++) { char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_BRANCH) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(wbranch)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&wbranch, imsg.data, sizeof(wbranch)); if (datalen - sizeof(wbranch) < wbranch.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(wbranch), wbranch.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } err = got_pathlist_insert(&new, &wanted_branches, refname, NULL); if (err || new == NULL) { free(refname); if (err) goto done; } imsg_free(&imsg); } for (i = 0; i < fetch_req.n_wanted_refs; i++) { char *refname; err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_REF) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(wref)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&wref, imsg.data, sizeof(wref)); if (datalen - sizeof(wref) < wref.name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg.data + sizeof(wref), wref.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } err = got_pathlist_insert(NULL, &wanted_refs, refname, NULL); if (err) { free(refname); goto done; } imsg_free(&imsg); } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; goto done; } if (imsg.hdr.type == GOT_IMSG_STOP) goto done; if (imsg.hdr.type != GOT_IMSG_FETCH_OUTFD) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } packfd = imsg_get_fd(&imsg); err = fetch_pack(fetchfd, packfd, pack_sha1, &have_refs, fetch_req.fetch_all_branches, &wanted_branches, &wanted_refs, fetch_req.list_refs_only, worktree_branch, remote_head, fetch_req.no_head, &ibuf); done: free(worktree_branch); free(remote_head); got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_PATH); if (fetchfd != -1 && close(fetchfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err != NULL) got_privsep_send_error(&ibuf, err); else err = send_fetch_done(&ibuf, pack_sha1); if (err != NULL) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); exit(1); } imsgbuf_clear(&ibuf); exit(0); } got-portable-0.119/libexec/got-fetch-pack/Makefile.in0000664000175000017500000006210715066537207016103 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-fetch-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-fetch-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_fetch_pack_OBJECTS = got-fetch-pack.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitproto.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pkt.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) got_fetch_pack_OBJECTS = $(am_got_fetch_pack_OBJECTS) got_fetch_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitproto.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pkt.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ ./$(DEPDIR)/got-fetch-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_fetch_pack_SOURCES) DIST_SOURCES = $(got_fetch_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_fetch_pack_SOURCES = \ got-fetch-pack.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitproto.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pkt.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c got_fetch_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-fetch-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-fetch-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitproto.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pkt.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-fetch-pack$(EXEEXT): $(got_fetch_pack_OBJECTS) $(got_fetch_pack_DEPENDENCIES) $(EXTRA_got_fetch_pack_DEPENDENCIES) @rm -f got-fetch-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_fetch_pack_OBJECTS) $(got_fetch_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitproto.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-fetch-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-fetch-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitproto.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pkt.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f ./$(DEPDIR)/got-fetch-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/Makefile.am0000664000175000017500000000041515066536114013264 SUBDIRS = got-fetch-http \ got-fetch-pack \ got-index-pack \ got-read-blob \ got-read-commit \ got-read-gitconfig \ got-read-gotconfig \ got-read-object \ got-read-pack \ got-read-patch \ got-read-tag \ got-read-tree \ got-send-pack got-portable-0.119/libexec/got-read-pack/0000775000175000017500000000000015066537275013737 5got-portable-0.119/libexec/got-read-pack/got-read-pack.c0000664000175000017500000014635715066536114016450 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_qid.h" #include "got_lib_object_cache.h" #include "got_lib_object_parse.h" #include "got_lib_object_idset.h" #include "got_lib_privsep.h" #include "got_lib_pack.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * open_object(struct got_object **obj, struct got_pack *pack, struct got_packidx *packidx, int idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err; err = got_packfile_open_object(obj, pack, packidx, idx, id); if (err) return err; (*obj)->refcnt++; err = got_object_cache_add(objcache, id, *obj); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS || err->code == GOT_ERR_OBJ_TOO_LARGE) err = NULL; return err; } (*obj)->refcnt++; return NULL; } static const struct got_error * object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) goto done; } err = got_privsep_send_obj(ibuf, obj); done: got_object_close(obj); return err; } static const struct got_error * open_commit(struct got_commit_object **commit, struct got_pack *pack, struct got_packidx *packidx, int obj_idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object *obj = NULL; uint8_t *buf = NULL; size_t len; *commit = NULL; obj = got_object_cache_get(objcache, id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, obj_idx, id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; obj->size = len; err = got_object_parse_commit(commit, buf, len, pack->algo); done: got_object_close(obj); free(buf); return err; } static const struct got_error * commit_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_commit_object *commit = NULL; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); err = open_commit(&commit, pack, packidx, iobj.idx, &id, objcache); if (err) goto done; err = got_privsep_send_commit(ibuf, commit); done: if (commit) got_object_commit_close(commit); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * open_tree(uint8_t **buf, size_t *len, struct got_pack *pack, struct got_packidx *packidx, int obj_idx, struct got_object_id *id, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object *obj = NULL; int cached = 0; *buf = NULL; *len = 0; obj = got_object_cache_get(objcache, id); if (obj) { obj->refcnt++; cached = 1; } else { err = open_object(&obj, pack, packidx, obj_idx, id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(buf, len, obj, pack); if (err) goto done; if (!cached) obj->size = *len; done: got_object_close(obj); if (err) { free(*buf); *buf = NULL; } return err; } static const struct got_error * tree_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_parsed_tree_entry **entries, size_t *nentries, size_t *nentries_alloc) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; uint8_t *buf = NULL; size_t len = 0; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); err = open_tree(&buf, &len, pack, packidx, iobj.idx, &id, objcache); if (err) return err; err = got_object_parse_tree(entries, nentries, nentries_alloc, buf, len, id.algo); if (err) goto done; err = got_privsep_send_tree(ibuf, *entries, *nentries); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } done: free(buf); return err; } static const struct got_error * receive_file(FILE **f, struct imsgbuf *ibuf, uint32_t imsg_code) { const struct got_error *err; struct imsg imsg; size_t datalen; int fd; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; if (imsg.hdr.type != imsg_code) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } *f = fdopen(fd, "w+"); if (*f == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } done: imsg_free(&imsg); return err; } static const struct got_error * receive_tempfile(FILE **f, const char *mode, struct imsg *imsg, struct imsgbuf *ibuf) { const struct got_error *err; size_t datalen; int fd; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); *f = fdopen(fd, mode); if (*f == NULL) { err = got_error_from_errno("fdopen"); close(fd); return err; } return NULL; } static const struct got_error * blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, FILE *basefile, FILE *accumfile) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj = NULL; FILE *outfile = NULL; struct got_object_id id; size_t datalen; uint64_t blob_size; uint8_t *buf = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD); if (err) goto done; if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { err = got_pack_get_max_delta_object_size(&blob_size, obj, pack); if (err) goto done; } else blob_size = obj->size; if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX) err = got_packfile_extract_object_to_mem(&buf, &obj->size, obj, pack); else err = got_packfile_extract_object(pack, obj, outfile, basefile, accumfile); if (err) goto done; err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf); done: free(buf); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); got_object_close(obj); if (err && err->code != GOT_ERR_PRIVSEP_PIPE) got_privsep_send_error(ibuf, err); return err; } static const struct got_error * tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_packed_object iobj; struct got_object *obj = NULL; struct got_tag_object *tag = NULL; uint8_t *buf = NULL; size_t len; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; obj->size = len; err = got_object_parse_tag(&tag, buf, len, id.algo); if (err) goto done; err = got_privsep_send_tag(ibuf, tag); done: free(buf); got_object_close(obj); if (tag) got_object_tag_close(tag); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * tree_path_changed(int *changed, uint8_t **buf1, size_t *len1, uint8_t **buf2, size_t *len2, const char *path, struct got_pack *pack, struct got_packidx *packidx, struct imsgbuf *ibuf, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_parsed_tree_entry pte1, pte2; const char *seg, *s; size_t seglen, digest_len; size_t remain1 = *len1, remain2 = *len2, elen; uint8_t *next_entry1 = *buf1; uint8_t *next_entry2 = *buf2; memset(&pte1, 0, sizeof(pte1)); memset(&pte2, 0, sizeof(pte2)); *changed = 0; digest_len = got_hash_digest_length(pack->algo); /* We not do support comparing the root path. */ if (got_path_is_root_dir(path)) return got_error_path(path, GOT_ERR_BAD_PATH); s = path; while (*s == '/') s++; seg = s; seglen = 0; while (*s) { if (*s != '/') { s++; seglen++; if (*s) continue; } /* * As an optimization we compare entries in on-disk order * rather than in got_path_cmp() order. We only need to * find out if any entries differ. Parsing all entries and * sorting them slows us down significantly when tree objects * have thousands of entries. We can assume that on-disk entry * ordering is stable, as per got_object_tree_create() and * sort_tree_entries_the_way_git_likes_it(). Other orderings * are incompatible with Git and would yield false positives * here, too. */ while (remain1 > 0) { err = got_object_parse_tree_entry(&pte1, &elen, next_entry1, remain1, digest_len, pack->algo); if (err) return err; next_entry1 += elen; remain1 -= elen; if (strncmp(pte1.name, seg, seglen) != 0 || pte1.name[seglen] != '\0') { memset(&pte1, 0, sizeof(pte1)); continue; } else break; } if (pte1.name == NULL) { err = got_error(GOT_ERR_NO_OBJ); break; } if (remain2 == 0) { *changed = 1; break; } while (remain2 > 0) { err = got_object_parse_tree_entry(&pte2, &elen, next_entry2, remain2, digest_len, pack->algo); if (err) return err; next_entry2 += elen; remain2 -= elen; if (strncmp(pte2.name, seg, seglen) != 0 || pte2.name[seglen] != '\0') { memset(&pte2, 0, sizeof(pte2)); continue; } else break; } if (pte2.name == NULL) { *changed = 1; break; } if (pte1.mode != pte2.mode) { *changed = 1; break; } if (memcmp(pte1.id, pte2.id, pte1.digest_len) == 0) { *changed = 0; break; } if (*s == '\0') { /* final path element */ *changed = 1; break; } seg = s + 1; s++; seglen = 0; if (*s) { struct got_object_id id1, id2; int idx; memcpy(id1.hash, pte1.id, pte1.digest_len); id1.algo = pack->algo; idx = got_packidx_get_object_idx(packidx, &id1); if (idx == -1) { err = got_error_no_obj(&id1); break; } free(*buf1); *buf1 = NULL; err = open_tree(buf1, len1, pack, packidx, idx, &id1, objcache); memset(&pte1, 0, sizeof(pte1)); if (err) break; next_entry1 = *buf1; remain1 = *len1; memcpy(id2.hash, pte2.id, pte2.digest_len); id2.algo = pack->algo; idx = got_packidx_get_object_idx(packidx, &id2); if (idx == -1) { err = got_error_no_obj(&id2); break; } free(*buf2); *buf2 = NULL; err = open_tree(buf2, len2, pack, packidx, idx, &id2, objcache); memset(&pte2, 0, sizeof(pte2)); if (err) break; next_entry2 = *buf2; remain2 = *len2; } } return err; } static const struct got_error * send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits, struct imsgbuf *ibuf) { struct ibuf *wbuf; size_t i; wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0, sizeof(struct got_imsg_traversed_commits) + ncommits * sizeof(commit_ids[0])); if (wbuf == NULL) return got_error_from_errno("imsg_create TRAVERSED_COMMITS"); if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1) return got_error_from_errno("imsg_add TRAVERSED_COMMITS"); for (i = 0; i < ncommits; i++) { struct got_object_id *id = &commit_ids[i]; if (imsg_add(wbuf, id, sizeof(*id)) == -1) { return got_error_from_errno( "imsg_add TRAVERSED_COMMITS"); } } imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_commit_traversal_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose TRAVERSAL_DONE"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * commit_traversal_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_imsg_commit_traversal_request ctreq; struct got_object_qid *pid; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_object_id id; size_t datalen; char *path = NULL; const int min_alloc = 64; int changed = 0, ncommits = 0, nallocated = 0; struct got_object_id *commit_ids = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ctreq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ctreq, imsg->data, sizeof(ctreq)); memcpy(&id, &ctreq.iobj.id, sizeof(id)); if (datalen != sizeof(ctreq) + ctreq.path_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (ctreq.path_len == 0) return got_error(GOT_ERR_PRIVSEP_LEN); path = strndup(imsg->data + sizeof(ctreq), ctreq.path_len); if (path == NULL) return got_error_from_errno("strndup"); nallocated = min_alloc; commit_ids = reallocarray(NULL, nallocated, sizeof(*commit_ids)); if (commit_ids == NULL) return got_error_from_errno("reallocarray"); do { const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE; int idx; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } if (commit == NULL) { idx = got_packidx_get_object_idx(packidx, &id); if (idx == -1) break; err = open_commit(&commit, pack, packidx, idx, &id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } } if (sizeof(struct got_imsg_traversed_commits) + (ncommits + 1) * sizeof(commit_ids[0]) >= max_datalen) { err = send_traversed_commits(commit_ids, ncommits, ibuf); if (err) goto done; ncommits = 0; } ncommits++; if (ncommits > nallocated) { struct got_object_id *new; nallocated += min_alloc; new = reallocarray(commit_ids, nallocated, sizeof(*commit_ids)); if (new == NULL) { err = got_error_from_errno("reallocarray"); goto done; } commit_ids = new; } memcpy(&commit_ids[ncommits - 1], &id, sizeof(id)); pid = STAILQ_FIRST(&commit->parent_ids); if (pid == NULL) break; idx = got_packidx_get_object_idx(packidx, &pid->id); if (idx == -1) break; err = open_commit(&pcommit, pack, packidx, idx, &pid->id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } if (path[0] == '/' && path[1] == '\0') { if (got_object_id_cmp(pcommit->tree_id, commit->tree_id) != 0) { changed = 1; break; } } else { int pidx; uint8_t *buf = NULL, *pbuf = NULL; size_t len = 0, plen = 0; idx = got_packidx_get_object_idx(packidx, commit->tree_id); if (idx == -1) break; pidx = got_packidx_get_object_idx(packidx, pcommit->tree_id); if (pidx == -1) break; err = open_tree(&buf, &len, pack, packidx, idx, commit->tree_id, objcache); if (err) goto done; err = open_tree(&pbuf, &plen, pack, packidx, pidx, pcommit->tree_id, objcache); if (err) { free(buf); goto done; } err = tree_path_changed(&changed, &buf, &len, &pbuf, &plen, path, pack, packidx, ibuf, objcache); free(buf); free(pbuf); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; break; } } if (!changed) { memcpy(&id, &pid->id, sizeof(id)); got_object_commit_close(commit); commit = pcommit; pcommit = NULL; } } while (!changed); if (ncommits > 0) { err = send_traversed_commits(commit_ids, ncommits, ibuf); if (err) goto done; if (changed) { err = got_privsep_send_commit(ibuf, commit); if (err) goto done; } } err = send_commit_traversal_done(ibuf); done: free(path); free(commit_ids); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, FILE *basefile, FILE *accumfile) { const struct got_error *err = NULL; uint8_t *buf = NULL; uint64_t size = 0; FILE *outfile = NULL; struct got_imsg_packed_object iobj; struct got_object *obj; struct got_object_id id; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iobj)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iobj, imsg->data, sizeof(iobj)); memcpy(&id, &iobj.id, sizeof(id)); obj = got_object_cache_get(objcache, &id); if (obj) { obj->refcnt++; } else { err = open_object(&obj, pack, packidx, iobj.idx, &id, objcache); if (err) return err; } err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD); if (err) return err; if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { err = got_pack_get_max_delta_object_size(&size, obj, pack); if (err) goto done; } else size = obj->size; if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) err = got_packfile_extract_object_to_mem(&buf, &obj->size, obj, pack); else err = got_packfile_extract_object(pack, obj, outfile, basefile, accumfile); if (err) goto done; err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf); done: free(buf); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); got_object_close(obj); if (err && err->code != GOT_ERR_PRIVSEP_PIPE) got_privsep_send_error(ibuf, err); return err; } static const struct got_error * get_base_object_id(struct got_object_id *base_id, struct got_packidx *packidx, off_t base_offset) { const struct got_error *err; int idx; err = got_packidx_get_offset_idx(&idx, packidx, base_offset); if (err) return err; if (idx == -1) return got_error(GOT_ERR_BAD_PACKIDX); return got_packidx_get_object_id(base_id, packidx, idx); } static const struct got_error * raw_delta_request(struct imsg *imsg, struct imsgbuf *ibuf, FILE *delta_outfile, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; struct got_imsg_raw_delta_request req; size_t datalen, delta_size, delta_compressed_size; off_t delta_offset, delta_data_offset; uint8_t *delta_buf = NULL; struct got_object_id id, base_id; off_t base_offset, delta_out_offset = 0; uint64_t base_size = 0, result_size = 0; size_t w; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(req)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&req, imsg->data, sizeof(req)); memcpy(&id, &req.id, sizeof(id)); err = got_packfile_extract_raw_delta(&delta_buf, &delta_size, &delta_compressed_size, &delta_offset, &delta_data_offset, &base_offset, &base_id, &base_size, &result_size, pack, packidx, req.idx); if (err) goto done; /* * If this is an offset delta we must determine the base * object ID ourselves. */ if (base_offset != 0) { err = get_base_object_id(&base_id, packidx, base_offset); if (err) goto done; } delta_out_offset = ftello(delta_outfile); w = fwrite(delta_buf, 1, delta_compressed_size, delta_outfile); if (w != delta_compressed_size) { err = got_ferror(delta_outfile, GOT_ERR_IO); goto done; } if (fflush(delta_outfile) == -1) { err = got_error_from_errno("fflush"); goto done; } err = got_privsep_send_raw_delta(ibuf, base_size, result_size, delta_size, delta_compressed_size, delta_offset, delta_out_offset, &base_id); done: free(delta_buf); return err; } struct search_deltas_arg { struct imsgbuf *ibuf; struct got_packidx *packidx; struct got_pack *pack; struct got_object_idset *idset; struct got_imsg_reused_delta deltas[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS]; size_t ndeltas; }; static const struct got_error * search_delta_for_object(struct got_object_id *id, void *data, void *arg) { const struct got_error *err; struct search_deltas_arg *a = arg; int obj_idx; uint8_t *delta_buf = NULL; uint64_t base_size, result_size; size_t delta_size, delta_compressed_size; off_t delta_offset, delta_data_offset, base_offset; struct got_object_id base_id; if (sigint_received) return got_error(GOT_ERR_CANCELLED); obj_idx = got_packidx_get_object_idx(a->packidx, id); if (obj_idx == -1) return NULL; /* object not present in our pack file */ err = got_packfile_extract_raw_delta(&delta_buf, &delta_size, &delta_compressed_size, &delta_offset, &delta_data_offset, &base_offset, &base_id, &base_size, &result_size, a->pack, a->packidx, obj_idx); if (err) { if (err->code == GOT_ERR_OBJ_TYPE) return NULL; /* object not stored as a delta */ return err; } /* * If this is an offset delta we must determine the base * object ID ourselves. */ if (base_offset != 0) { err = get_base_object_id(&base_id, a->packidx, base_offset); if (err) goto done; } if (got_object_idset_contains(a->idset, &base_id)) { struct got_imsg_reused_delta *delta; delta = &a->deltas[a->ndeltas++]; memcpy(&delta->id, id, sizeof(delta->id)); memcpy(&delta->base_id, &base_id, sizeof(delta->base_id)); delta->base_size = base_size; delta->result_size = result_size; delta->delta_size = delta_size; delta->delta_compressed_size = delta_compressed_size; delta->delta_offset = delta_data_offset; if (a->ndeltas >= GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS) { err = got_privsep_send_reused_deltas(a->ibuf, a->deltas, a->ndeltas); if (err) goto done; a->ndeltas = 0; } } done: free(delta_buf); return err; } static const struct got_error * recv_object_ids(struct got_object_idset *idset, struct imsgbuf *ibuf) { const struct got_error *err = NULL; int done = 0; struct got_object_id *ids; size_t nids, i; for (;;) { err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf); if (err || done) break; for (i = 0; i < nids; i++) { err = got_object_idset_add(idset, &ids[i], NULL); if (err) { free(ids); return err; } } free(ids); } return err; } static const struct got_error * recv_object_id_queue(size_t *nids_total, struct got_object_id_queue *queue, void *data, struct got_object_idset *queued_ids, struct imsgbuf *ibuf) { const struct got_error *err = NULL; int done = 0; struct got_object_qid *qid; struct got_object_id *ids; size_t nids, i; *nids_total = 0; for (;;) { err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf); if (err || done) break; *nids_total += nids; for (i = 0; i < nids; i++) { err = got_object_qid_alloc_partial(&qid); if (err) goto done; memcpy(&qid->id, &ids[i], sizeof(qid->id)); if (data) qid->data = data; STAILQ_INSERT_TAIL(queue, qid, entry); if (queued_ids) { err = got_object_idset_add(queued_ids, &qid->id, NULL); if (err) goto done; } } free(ids); ids = NULL; } done: free(ids); return err; } static const struct got_error * delta_reuse_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err = NULL; struct got_object_idset *idset; struct search_deltas_arg sda; idset = got_object_idset_alloc(); if (idset == NULL) return got_error_from_errno("got_object_idset_alloc"); err = recv_object_ids(idset, ibuf); if (err) return err; memset(&sda, 0, sizeof(sda)); sda.ibuf = ibuf; sda.idset = idset; sda.pack = pack; sda.packidx = packidx; err = got_object_idset_for_each(idset, search_delta_for_object, &sda); if (err) goto done; if (sda.ndeltas > 0) { err = got_privsep_send_reused_deltas(ibuf, sda.deltas, sda.ndeltas); if (err) goto done; } err = got_privsep_send_reused_deltas_done(ibuf); done: got_object_idset_free(idset); return err; } static const struct got_error * receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; struct got_imsg_packidx ipackidx; size_t datalen; struct got_packidx *p; *packidx = NULL; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; p = calloc(1, sizeof(*p)); if (p == NULL) { err = got_error_from_errno("calloc"); goto done; } if (imsg.hdr.type != GOT_IMSG_PACKIDX) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ipackidx)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ipackidx, imsg.data, sizeof(ipackidx)); p->algo = ipackidx.algo; p->fd = imsg_get_fd(&imsg); p->len = ipackidx.len; if (p->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (lseek(p->fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } #ifndef GOT_PACK_NO_MMAP if (p->len > 0 && p->len <= SIZE_MAX) { p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); if (p->map == MAP_FAILED) p->map = NULL; /* fall back to read(2) */ } #endif err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size); done: if (err) { if (p != NULL) got_packidx_close(p); } else *packidx = p; imsg_free(&imsg); return err; } static const struct got_error * send_tree_enumeration_done(struct imsgbuf *ibuf) { if (imsg_compose(ibuf, GOT_IMSG_TREE_ENUMERATION_DONE, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE"); return got_privsep_flush_imsg(ibuf); } struct enumerated_tree { struct got_object_id id; char *path; uint8_t *buf; struct got_parsed_tree_entry *entries; int nentries; }; static const struct got_error * enumerate_tree(int *have_all_entries, struct imsgbuf *ibuf, size_t *totlen, struct got_object_id *tree_id, const char *path, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_object_idset *idset, struct enumerated_tree **trees, size_t *nalloc, size_t *ntrees) { const struct got_error *err = NULL; struct got_object_id_queue ids; struct got_object_qid *qid; uint8_t *buf = NULL; size_t len = 0; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0, i; struct enumerated_tree *tree; *ntrees = 0; *have_all_entries = 1; STAILQ_INIT(&ids); err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, tree_id, sizeof(*tree_id)); qid->data = strdup(path); if (qid->data == NULL) { err = got_error_from_errno("strdup"); goto done; } STAILQ_INSERT_TAIL(&ids, qid, entry); qid = NULL; /* Traverse the tree hierarchy, gather tree object IDs and paths. */ do { const char *path; int idx, i; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(&ids); STAILQ_REMOVE_HEAD(&ids, entry); path = qid->data; idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { *have_all_entries = 0; break; } err = open_tree(&buf, &len, pack, packidx, idx, &qid->id, objcache); if (err) { if (err->code != GOT_ERR_NO_OBJ) goto done; } err = got_object_parse_tree(&entries, &nentries, &nentries_alloc, buf, len, pack->algo); if (err) goto done; err = got_object_idset_add(idset, &qid->id, NULL); if (err) goto done; for (i = 0; i < nentries; i++) { struct got_object_qid *eqid = NULL; struct got_parsed_tree_entry *pte = &entries[i]; char *p; if (!S_ISDIR(pte->mode)) continue; err = got_object_qid_alloc_partial(&eqid); if (err) goto done; eqid->id.algo = pte->algo; memcpy(eqid->id.hash, pte->id, pte->digest_len); if (got_object_idset_contains(idset, &eqid->id)) { got_object_qid_free(eqid); continue; } if (asprintf(&p, "%s%s%s", path, got_path_is_root_dir(path) ? "" : "/", pte->name) == -1) { err = got_error_from_errno("asprintf"); got_object_qid_free(eqid); goto done; } eqid->data = p; STAILQ_INSERT_TAIL(&ids, eqid, entry); } if (*ntrees >= *nalloc) { struct enumerated_tree *new; new = recallocarray(*trees, *nalloc, *nalloc + 16, sizeof(*new)); if (new == NULL) { err = got_error_from_errno("malloc"); goto done; } *trees = new; *nalloc += 16; } tree = &(*trees)[*ntrees]; (*ntrees)++; memcpy(&tree->id, &qid->id, sizeof(tree->id)); tree->path = qid->data; tree->buf = buf; buf = NULL; tree->entries = entries; entries = NULL; nentries_alloc = 0; tree->nentries = nentries; nentries = 0; got_object_qid_free(qid); qid = NULL; } while (!STAILQ_EMPTY(&ids)); if (*have_all_entries) { int i; /* * We have managed to traverse all entries in the hierarchy. * Tell the main process what we have found. */ for (i = 0; i < *ntrees; i++) { tree = &(*trees)[i]; err = got_privsep_send_enumerated_tree(totlen, ibuf, &tree->id, tree->path, tree->entries, tree->nentries); if (err) goto done; free(tree->buf); tree->buf = NULL; free(tree->path); tree->path = NULL; free(tree->entries); tree->entries = NULL; } *ntrees = 0; /* don't loop again below to free memory */ err = send_tree_enumeration_done(ibuf); } else { /* * We can only load fully packed tree hierarchies on * behalf of the main process, otherwise the main process * gets a wrong idea about which tree objects have * already been traversed. * Indicate a missing entry for the root of this tree. * The main process should continue by loading this * entire tree the slow way. */ err = got_privsep_send_enumerated_tree(totlen, ibuf, tree_id, "/", NULL, -1); if (err) goto done; } done: free(buf); free(entries); for (i = 0; i < *ntrees; i++) { tree = &(*trees)[i]; free(tree->buf); tree->buf = NULL; free(tree->path); tree->path = NULL; free(tree->entries); tree->entries = NULL; } if (qid) free(qid->data); got_object_qid_free(qid); got_object_id_queue_free(&ids); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; else got_privsep_send_error(ibuf, err); } return err; } static const struct got_error * resolve_tag(struct got_object **obj, struct got_object_id *id, struct got_packidx *packidx, struct got_pack *pack, struct got_object_cache *objcache) { const struct got_error *err; struct got_object *tagged_obj; struct got_tag_object *tag; uint8_t *buf; size_t len; int idx; err = got_packfile_extract_object_to_mem(&buf, &len, *obj, pack); if (err) return err; (*obj)->size = len; err = got_object_parse_tag(&tag, buf, len, id->algo); if (err) goto done; idx = got_packidx_get_object_idx(packidx, &tag->id); if (idx == -1) { got_object_close(*obj); *obj = NULL; return NULL; } tagged_obj = got_object_cache_get(objcache, &tag->id); if (tagged_obj) { tagged_obj->refcnt++; } else { err = open_object(&tagged_obj, pack, packidx, idx, &tag->id, objcache); if (err) goto done; } got_object_close(*obj); *obj = tagged_obj; done: got_object_tag_close(tag); free(buf); return err; } static const struct got_error * enumeration_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_object_id_queue commit_ids; const struct got_object_id_queue *parents = NULL; struct got_object_qid *qid = NULL; struct got_object *obj = NULL; struct got_commit_object *commit = NULL; struct got_object_id *tree_id = NULL; size_t totlen = 0; struct got_object_idset *idset, *queued_ids = NULL; int i, idx, have_all_entries = 1; struct enumerated_tree *trees = NULL; size_t ntrees = 0, nalloc = 16, nids = 0; STAILQ_INIT(&commit_ids); trees = calloc(nalloc, sizeof(*trees)); if (trees == NULL) return got_error_from_errno("calloc"); idset = got_object_idset_alloc(); if (idset == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } queued_ids = got_object_idset_alloc(); if (queued_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = recv_object_id_queue(&nids, &commit_ids, NULL, queued_ids, ibuf); if (err) goto done; if (STAILQ_EMPTY(&commit_ids)) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } err = recv_object_ids(idset, ibuf); if (err) goto done; while (!STAILQ_EMPTY(&commit_ids)) { if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(&commit_ids); STAILQ_REMOVE_HEAD(&commit_ids, entry); if (got_object_idset_contains(idset, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { have_all_entries = 0; break; } err = open_object(&obj, pack, packidx, idx, &qid->id, objcache); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) { while (obj->type == GOT_OBJ_TYPE_TAG) { err = resolve_tag(&obj, &qid->id, packidx, pack, objcache); if (err) goto done; if (obj == NULL) break; } if (obj == NULL) { have_all_entries = 0; break; } if (obj->type != GOT_OBJ_TYPE_COMMIT) { got_object_qid_free(qid); qid = NULL; got_object_close(obj); obj = NULL; continue; } err = open_commit(&commit, pack, packidx, idx, &obj->id, objcache); if (err) goto done; } else if (obj->type == GOT_OBJ_TYPE_COMMIT) { err = open_commit(&commit, pack, packidx, idx, &qid->id, objcache); if (err) goto done; } else { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } got_object_close(obj); obj = NULL; err = got_privsep_send_enumerated_commit(ibuf, &qid->id, got_object_commit_get_committer_time(commit)); if (err) goto done; tree_id = got_object_commit_get_tree_id(commit); idx = got_packidx_get_object_idx(packidx, tree_id); if (idx == -1) { have_all_entries = 0; err = got_privsep_send_enumerated_tree(&totlen, ibuf, tree_id, "/", NULL, -1); if (err) goto done; break; } if (got_object_idset_contains(idset, tree_id)) { got_object_qid_free(qid); qid = NULL; err = send_tree_enumeration_done(ibuf); if (err) goto done; got_object_commit_close(commit); commit = NULL; continue; } err = enumerate_tree(&have_all_entries, ibuf, &totlen, tree_id, "/", pack, packidx, objcache, idset, &trees, &nalloc, &ntrees); if (err) goto done; if (!have_all_entries) break; got_object_qid_free(qid); qid = NULL; parents = got_object_commit_get_parent_ids(commit); if (parents) { struct got_object_qid *pid; STAILQ_FOREACH(pid, parents, entry) { if (got_object_idset_contains(idset, &pid->id)) continue; if (got_object_idset_contains(queued_ids, &pid->id)) continue; err = got_object_qid_alloc_partial(&qid); if (err) goto done; memcpy(&qid->id, &pid->id, sizeof(qid->id)); STAILQ_INSERT_TAIL(&commit_ids, qid, entry); qid = NULL; } } got_object_commit_close(commit); commit = NULL; } if (have_all_entries) { err = got_privsep_send_object_enumeration_done(ibuf); if (err) goto done; } else { err = got_privsep_send_object_enumeration_incomplete(ibuf); if (err) goto done; } done: if (obj) got_object_close(obj); if (commit) got_object_commit_close(commit); got_object_qid_free(qid); got_object_id_queue_free(&commit_ids); if (idset) got_object_idset_free(idset); if (queued_ids) got_object_idset_free(queued_ids); for (i = 0; i < ntrees; i++) { struct enumerated_tree *tree = &trees[i]; free(tree->buf); free(tree->path); free(tree->entries); } free(trees); return err; } enum findtwixt_color { COLOR_KEEP = 0, COLOR_DROP, COLOR_SKIP, COLOR_MAX, }; static const struct got_error * paint_commit(struct got_object_qid *qid, intptr_t color) { if (color < 0 || color >= COLOR_MAX) return got_error(GOT_ERR_RANGE); qid->data = (void *)color; return NULL; } static const struct got_error * queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id, intptr_t color) { const struct got_error *err; struct got_object_qid *qid; err = got_object_qid_alloc_partial(&qid); if (err) return err; memcpy(&qid->id, id, sizeof(qid->id)); if (color == COLOR_KEEP) STAILQ_INSERT_TAIL(ids, qid, entry); else STAILQ_INSERT_HEAD(ids, qid, entry); return paint_commit(qid, color); } static const struct got_error * paint_commits(struct got_object_id_queue *ids, int *nids, struct got_object_idset *keep, struct got_object_idset *drop, struct got_object_idset *skip, struct got_pack *pack, struct got_packidx *packidx, struct imsgbuf *ibuf, struct got_object_cache *objcache) { const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_object_id_queue painted; const struct got_object_id_queue *parents; struct got_object_qid *qid = NULL; int nqueued = *nids, nskip = 0, npainted = 0; STAILQ_INIT(&painted); while (!STAILQ_EMPTY(ids) && nskip != nqueued) { int idx; intptr_t color; if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); goto done; } qid = STAILQ_FIRST(ids); idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { qid = NULL; break; } STAILQ_REMOVE_HEAD(ids, entry); nqueued--; color = (intptr_t)qid->data; if (color == COLOR_SKIP) nskip--; if (got_object_idset_contains(skip, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } if (color == COLOR_KEEP && got_object_idset_contains(keep, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } if (color == COLOR_DROP && got_object_idset_contains(drop, &qid->id)) { got_object_qid_free(qid); qid = NULL; continue; } switch (color) { case COLOR_KEEP: if (got_object_idset_contains(drop, &qid->id)) { err = paint_commit(qid, COLOR_SKIP); if (err) goto done; err = got_object_idset_add(skip, &qid->id, NULL); if (err) goto done; break; } if (!got_object_idset_contains(keep, &qid->id)) { err = got_object_idset_add(keep, &qid->id, NULL); if (err) goto done; } break; case COLOR_DROP: if (got_object_idset_contains(keep, &qid->id)) { err = paint_commit(qid, COLOR_SKIP); if (err) goto done; err = got_object_idset_add(skip, &qid->id, NULL); if (err) goto done; break; } if (!got_object_idset_contains(drop, &qid->id)) { err = got_object_idset_add(drop, &qid->id, NULL); if (err) goto done; } break; case COLOR_SKIP: err = got_object_idset_add(skip, &qid->id, NULL); if (err) goto done; break; default: /* should not happen */ err = got_error_fmt(GOT_ERR_NOT_IMPL, "%s invalid commit color %"PRIdPTR, __func__, color); goto done; } err = open_commit(&commit, pack, packidx, idx, &qid->id, objcache); if (err) goto done; parents = got_object_commit_get_parent_ids(commit); if (parents) { struct got_object_qid *pid; color = (intptr_t)qid->data; STAILQ_FOREACH(pid, parents, entry) { err = queue_commit_id(ids, &pid->id, color); if (err) goto done; nqueued++; if (color == COLOR_SKIP) nskip++; } } got_object_commit_close(commit); commit = NULL; STAILQ_INSERT_TAIL(&painted, qid, entry); qid = NULL; npainted++; err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 0); if (err) goto done; } err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 1); if (err) goto done; *nids = nqueued; done: if (commit) got_object_commit_close(commit); got_object_qid_free(qid); return err; } static void commit_painting_free(struct got_object_idset **keep, struct got_object_idset **drop, struct got_object_idset **skip) { if (*keep) { got_object_idset_free(*keep); *keep = NULL; } if (*drop) { got_object_idset_free(*drop); *drop = NULL; } if (*skip) { got_object_idset_free(*skip); *skip = NULL; } } static const struct got_error * commit_painting_init(struct imsgbuf *ibuf, struct got_object_idset **keep, struct got_object_idset **drop, struct got_object_idset **skip) { const struct got_error *err = NULL; *keep = got_object_idset_alloc(); if (*keep == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } *drop = got_object_idset_alloc(); if (*drop == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } *skip = got_object_idset_alloc(); if (*skip == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = recv_object_ids(*keep, ibuf); if (err) goto done; err = recv_object_ids(*drop, ibuf); if (err) goto done; err = recv_object_ids(*skip, ibuf); if (err) goto done; done: if (err) commit_painting_free(keep, drop, skip); return err; } static const struct got_error * commit_painting_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx, struct got_object_cache *objcache, struct got_object_idset *keep, struct got_object_idset *drop, struct got_object_idset *skip) { const struct got_error *err = NULL; size_t datalen; struct got_object_id_queue ids; size_t nids; int nqueued = 0, done = 0; STAILQ_INIT(&ids); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); while (!done) { err = got_privsep_recv_object_id_queue(&done, &ids, &nids, ibuf); if (err) goto done; if (nqueued + nids > INT_MAX) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } nqueued += nids; } err = paint_commits(&ids, &nqueued, keep, drop, skip, pack, packidx, ibuf, objcache); if (err) goto done; err = got_privsep_send_painted_commits(ibuf, &ids, &nqueued, 0, 1); if (err) goto done; err = got_privsep_send_painting_commits_done(ibuf); done: got_object_id_queue_free(&ids); return err; } static const struct got_error * receive_pack(struct got_pack **packp, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; struct got_imsg_pack ipack; size_t datalen; struct got_pack *pack; *packp = NULL; err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) return err; pack = calloc(1, sizeof(*pack)); if (pack == NULL) { err = got_error_from_errno("calloc"); goto done; } if (imsg.hdr.type != GOT_IMSG_PACK) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ipack)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ipack, imsg.data, sizeof(ipack)); pack->algo = ipack.algo; pack->filesize = ipack.filesize; pack->fd = imsg_get_fd(&imsg); if (pack->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (lseek(pack->fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } pack->path_packfile = strdup(ipack.path_packfile); if (pack->path_packfile == NULL) { err = got_error_from_errno("strdup"); goto done; } err = got_delta_cache_alloc(&pack->delta_cache); if (err) goto done; #ifndef GOT_PACK_NO_MMAP if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) { pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, pack->fd, 0); if (pack->map == MAP_FAILED) pack->map = NULL; /* fall back to read(2) */ } #endif done: if (err) { if (pack != NULL) got_pack_close(pack); } else *packp = pack; imsg_free(&imsg); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; struct imsg imsg; struct got_packidx *packidx = NULL; struct got_pack *pack = NULL; struct got_object_cache objcache; FILE *basefile = NULL, *accumfile = NULL, *delta_outfile = NULL; struct got_object_idset *keep = NULL, *drop = NULL, *skip = NULL; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0; //static int attached; //while (!attached) sleep(1); signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ); if (err) { err = got_error_from_errno("got_object_cache_init"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif err = receive_packidx(&packidx, &ibuf); if (err) { got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } err = receive_pack(&pack, &ibuf); if (err) { got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } for (;;) { if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { imsg_free(&imsg); break; } switch (imsg.hdr.type) { case GOT_IMSG_TMPFD: if (basefile == NULL) { err = receive_tempfile(&basefile, "w+", &imsg, &ibuf); } else if (accumfile == NULL) { err = receive_tempfile(&accumfile, "w+", &imsg, &ibuf); } else err = got_error(GOT_ERR_PRIVSEP_MSG); break; case GOT_IMSG_PACKED_OBJECT_REQUEST: err = object_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST: if (basefile == NULL || accumfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = raw_object_request(&imsg, &ibuf, pack, packidx, &objcache, basefile, accumfile); break; case GOT_IMSG_RAW_DELTA_OUTFD: if (delta_outfile != NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = receive_tempfile(&delta_outfile, "w", &imsg, &ibuf); break; case GOT_IMSG_RAW_DELTA_REQUEST: if (delta_outfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } err = raw_delta_request(&imsg, &ibuf, delta_outfile, pack, packidx); break; case GOT_IMSG_DELTA_REUSE_REQUEST: err = delta_reuse_request(&imsg, &ibuf, pack, packidx); break; case GOT_IMSG_COMMIT_REQUEST: err = commit_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_TREE_REQUEST: err = tree_request(&imsg, &ibuf, pack, packidx, &objcache, &entries, &nentries, &nentries_alloc); break; case GOT_IMSG_BLOB_REQUEST: if (basefile == NULL || accumfile == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = blob_request(&imsg, &ibuf, pack, packidx, &objcache, basefile, accumfile); break; case GOT_IMSG_TAG_REQUEST: err = tag_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST: err = commit_traversal_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_OBJECT_ENUMERATION_REQUEST: err = enumeration_request(&imsg, &ibuf, pack, packidx, &objcache); break; case GOT_IMSG_COMMIT_PAINTING_INIT: commit_painting_free(&keep, &drop, &skip); err = commit_painting_init(&ibuf, &keep, &drop, &skip); break; case GOT_IMSG_COMMIT_PAINTING_REQUEST: if (keep == NULL || drop == NULL || skip == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = commit_painting_request(&imsg, &ibuf, pack, packidx, &objcache, keep, drop, skip); break; case GOT_IMSG_COMMIT_PAINTING_DONE: commit_painting_free(&keep, &drop, &skip); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); if (err) break; } free(entries); commit_painting_free(&keep, &drop, &skip); if (packidx) got_packidx_close(packidx); if (pack) { got_pack_close(pack); free(pack); } got_object_cache_close(&objcache); if (basefile && fclose(basefile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (accumfile && fclose(accumfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (delta_outfile && fclose(delta_outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-pack/Makefile.am0000664000175000017500000000152115066536114015701 libexec_PROGRAMS = got-read-pack include $(top_builddir)/Makefile.common got_read_pack_SOURCES = got-read-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-pack/Makefile.in0000664000175000017500000006470415066537207015732 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-pack$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-pack ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_pack_OBJECTS = got-read-pack.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_pack_OBJECTS = $(am_got_read_pack_OBJECTS) got_read_pack_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-pack.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_pack_SOURCES) DIST_SOURCES = $(got_read_pack_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_pack_SOURCES = got-read-pack.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_pack_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-pack/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-pack/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-pack$(EXEEXT): $(got_read_pack_OBJECTS) $(got_read_pack_DEPENDENCIES) $(EXTRA_got_read_pack_DEPENDENCIES) @rm -f got-read-pack$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_pack_OBJECTS) $(got_read_pack_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-pack.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-pack.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-pack.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/got-read-gitconfig/0000775000175000017500000000000015066537275014772 5got-portable-0.119/libexec/got-read-gitconfig/got-read-gitconfig.c0000664000175000017500000002741215066536114020524 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_object.h" #include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_privsep.h" #include "got_lib_gitconfig.h" static volatile sig_atomic_t sigint_received; static void catch_sigint(int signo) { sigint_received = 1; } static const struct got_error * send_gitconfig_int(struct imsgbuf *ibuf, int value) { if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_INT_VAL, 0, 0, -1, &value, sizeof(value)) == -1) return got_error_from_errno("imsg_compose GITCONFIG_INT_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * gitconfig_num_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, const char *section, const char *tag, int def) { int value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_num(gitconfig, section, tag, def); return send_gitconfig_int(ibuf, value); } static const struct got_error * send_gitconfig_str(struct imsgbuf *ibuf, const char *value) { size_t len = value ? strlen(value) : 0; if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_STR_VAL, 0, 0, -1, value, len) == -1) return got_error_from_errno("imsg_compose GITCONFIG_STR_VAL"); return got_privsep_flush_imsg(ibuf); } static const struct got_error * send_gitconfig_pair(struct imsgbuf *ibuf, const char *key, const char *val) { struct ibuf *wbuf; size_t klen = key ? strlen(key) : 0; size_t vlen = val ? strlen(val) : 0; size_t tot = sizeof(klen) + sizeof(vlen) + klen + vlen; if (tot > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_PAIR, 0, 0, tot); if (wbuf == NULL) return got_error_from_errno("imsg_create GITCONFIG_PAIR"); /* Keep in sync with got_imsg_gitconfig_pair */ if (imsg_add(wbuf, &klen, sizeof(klen)) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, &vlen, sizeof(vlen)) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, key, klen) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); if (imsg_add(wbuf, val, vlen) == -1) return got_error_from_errno("imsg_add GITCONFIG_PAIR"); imsg_close(ibuf, wbuf); return got_privsep_flush_imsg(ibuf); } static const struct got_error * gitconfig_str_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig, const char *section, const char *tag) { char *value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_str(gitconfig, section, tag); return send_gitconfig_str(ibuf, value); } static const struct got_error * send_gitconfig_remotes(struct imsgbuf *ibuf, struct got_remote_repo *remotes, int nremotes) { const struct got_error *err = NULL; struct got_imsg_remotes iremotes; int i; iremotes.nremotes = nremotes; if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1, &iremotes, sizeof(iremotes)) == -1) return got_error_from_errno("imsg_compose GITCONFIG_REMOTES"); err = got_privsep_flush_imsg(ibuf); if (err) return err; for (i = 0; i < nremotes; i++) { struct got_imsg_remote iremote; size_t len = sizeof(iremote); struct ibuf *wbuf; iremote.mirror_references = remotes[i].mirror_references; iremote.name_len = strlen(remotes[i].name); len += iremote.name_len; iremote.fetch_url_len = strlen(remotes[i].fetch_url); len += iremote.fetch_url_len; iremote.send_url_len = strlen(remotes[i].send_url); len += iremote.send_url_len; wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len); if (wbuf == NULL) return got_error_from_errno( "imsg_create GITCONFIG_REMOTE"); if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].fetch_url, iremote.fetch_url_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); if (imsg_add(wbuf, remotes[i].send_url, iremote.send_url_len) == -1) return got_error_from_errno( "imsg_add GITCONFIG_REMOTE"); imsg_close(ibuf, wbuf); err = got_privsep_flush_imsg(ibuf); if (err) return err; } return NULL; } static int get_boolean_val(char *val) { return (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 || strcasecmp(val, "yes") == 0 || strcmp(val, "1") == 0); } static int skip_node(struct got_gitconfig *gitconfig, struct got_gitconfig_list_node *node) { /* * Skip config nodes which do not describe remotes, and remotes * which do not have a fetch URL defined (as used by git-annex). */ return (strncasecmp("remote \"", node->field, 8) != 0 || got_gitconfig_get_str(gitconfig, node->field, "url") == NULL); } static const struct got_error * gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { const struct got_error *err = NULL; struct got_gitconfig_list *sections; struct got_gitconfig_list_node *node; struct got_remote_repo *remotes = NULL; int nremotes = 0, i; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); err = got_gitconfig_get_section_list(§ions, gitconfig); if (err) return err; TAILQ_FOREACH(node, §ions->fields, link) { if (skip_node(gitconfig, node)) continue; nremotes++; } if (nremotes == 0) { err = send_gitconfig_remotes(ibuf, NULL, 0); goto done; } remotes = recallocarray(NULL, 0, nremotes, sizeof(*remotes)); if (remotes == NULL) { err = got_error_from_errno("recallocarray"); goto done; } i = 0; TAILQ_FOREACH(node, §ions->fields, link) { char *name, *end, *mirror; if (skip_node(gitconfig, node)) continue; name = strdup(node->field + 8); if (name == NULL) { err = got_error_from_errno("strdup"); goto done; } end = strrchr(name, '"'); if (end) *end = '\0'; remotes[i].name = name; remotes[i].fetch_url = got_gitconfig_get_str(gitconfig, node->field, "url"); remotes[i].send_url = got_gitconfig_get_str(gitconfig, node->field, "pushurl"); if (remotes[i].send_url == NULL) remotes[i].send_url = remotes[i].fetch_url; remotes[i].mirror_references = 0; mirror = got_gitconfig_get_str(gitconfig, node->field, "mirror"); if (mirror != NULL && get_boolean_val(mirror)) remotes[i].mirror_references = 1; i++; } err = send_gitconfig_remotes(ibuf, remotes, nremotes); done: for (i = 0; i < nremotes; i++) free(remotes[i].name); free(remotes); got_gitconfig_free_list(sections); return err; } static const struct got_error * gitconfig_owner_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { char *value; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); value = got_gitconfig_get_str(gitconfig, "gotweb", "owner"); if (value) return send_gitconfig_str(ibuf, value); value = got_gitconfig_get_str(gitconfig, "gitweb", "owner"); return send_gitconfig_str(ibuf, value); } static const struct got_error * gitconfig_extensions_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) { const struct got_error *err = NULL; struct got_gitconfig_list *tags; struct got_gitconfig_list_node *node; int nextensions = 0; char *val; if (gitconfig == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); tags = got_gitconfig_get_tag_list(gitconfig, "extensions"); if (tags == NULL) return send_gitconfig_int(ibuf, 0); TAILQ_FOREACH(node, &tags->fields, link) nextensions++; err = send_gitconfig_int(ibuf, nextensions); if (err) goto done; TAILQ_FOREACH(node, &tags->fields, link) { val = got_gitconfig_get_str(gitconfig, "extensions", node->field); err = send_gitconfig_pair(ibuf, node->field, val); if (err) goto done; } done: got_gitconfig_free_list(tags); return err; } int main(int argc, char *argv[]) { const struct got_error *err = NULL; struct imsgbuf ibuf; size_t datalen; struct got_gitconfig *gitconfig = NULL; #if 0 static int attached; while (!attached) sleep(1); #endif signal(SIGINT, catch_sigint); if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) { warn("imsgbuf_init"); return 1; } imsgbuf_allow_fdpass(&ibuf); #ifndef PROFILE /* revoke access to most system calls */ if (pledge("stdio recvfd", NULL) == -1) { err = got_error_from_errno("pledge"); got_privsep_send_error(&ibuf, err); imsgbuf_clear(&ibuf); return 1; } /* revoke fs access */ if (landlock_no_fs() == -1) { err = got_error_from_errno("landlock_no_fs"); got_privsep_send_error(&ibuf, err); return 1; } if (cap_enter() == -1) { err = got_error_from_errno("cap_enter"); got_privsep_send_error(&ibuf, err); return 1; } #endif for (;;) { struct imsg imsg; int fd = -1, finished = 0; memset(&imsg, 0, sizeof(imsg)); if (sigint_received) { err = got_error(GOT_ERR_CANCELLED); break; } err = got_privsep_recv_imsg(&imsg, &ibuf, 0); if (err) { if (err->code == GOT_ERR_PRIVSEP_PIPE) err = NULL; break; } if (imsg.hdr.type == GOT_IMSG_STOP) { finished = 1; goto done; } switch (imsg.hdr.type) { case GOT_IMSG_GITCONFIG_PARSE_REQUEST: datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); break; } fd = imsg_get_fd(&imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } if (gitconfig) got_gitconfig_close(gitconfig); err = got_gitconfig_open(&gitconfig, fd); break; case GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST: err = gitconfig_num_request(&ibuf, gitconfig, "core", "repositoryformatversion", 0); break; case GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST: err = gitconfig_extensions_request(&ibuf, gitconfig); break; case GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST: err = gitconfig_str_request(&ibuf, gitconfig, "user", "name"); break; case GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST: err = gitconfig_str_request(&ibuf, gitconfig, "user", "email"); break; case GOT_IMSG_GITCONFIG_REMOTES_REQUEST: err = gitconfig_remotes_request(&ibuf, gitconfig); break; case GOT_IMSG_GITCONFIG_OWNER_REQUEST: err = gitconfig_owner_request(&ibuf, gitconfig); break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break; } done: if (fd != -1) { if (close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); } imsg_free(&imsg); if (err || finished) break; } if (err) { if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) { fprintf(stderr, "%s: %s\n", getprogname(), err->msg); got_privsep_send_error(&ibuf, err); } } if (gitconfig) got_gitconfig_close(gitconfig); imsgbuf_clear(&ibuf); if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL) err = got_error_from_errno("close"); return err ? 1 : 0; } got-portable-0.119/libexec/got-read-gitconfig/Makefile.am0000664000175000017500000000130215066536114016731 libexec_PROGRAMS = got-read-gitconfig include $(top_builddir)/Makefile.common got_read_gitconfig_SOURCES = got-read-gitconfig.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_gitconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/libexec/got-read-gitconfig/Makefile.in0000664000175000017500000006046515066537207016765 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-read-gitconfig$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = libexec/got-read-gitconfig ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_read_gitconfig_OBJECTS = got-read-gitconfig.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) got_read_gitconfig_OBJECTS = $(am_got_read_gitconfig_OBJECTS) got_read_gitconfig_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ ./$(DEPDIR)/got-read-gitconfig.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_read_gitconfig_SOURCES) DIST_SOURCES = $(got_read_gitconfig_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_read_gitconfig_SOURCES = got-read-gitconfig.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c got_read_gitconfig_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/got-read-gitconfig/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/got-read-gitconfig/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-read-gitconfig$(EXEEXT): $(got_read_gitconfig_OBJECTS) $(got_read_gitconfig_DEPENDENCIES) $(EXTRA_got_read_gitconfig_DEPENDENCIES) @rm -f got-read-gitconfig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_read_gitconfig_OBJECTS) $(got_read_gitconfig_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-read-gitconfig.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gitconfig.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f ./$(DEPDIR)/got-read-gitconfig.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/libexec/Makefile.in0000664000175000017500000004656215066537207013316 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = libexec ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = got-fetch-http \ got-fetch-pack \ got-index-pack \ got-read-blob \ got-read-commit \ got-read-gitconfig \ got-read-gotconfig \ got-read-object \ got-read-pack \ got-read-patch \ got-read-tag \ got-read-tree \ got-send-pack all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libexec/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign libexec/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/template/0000775000175000017500000000000015066537276011522 5got-portable-0.119/template/Makefile.common.in0000664000175000017500000000134215066536114014764 AM_CFLAGS += \ @AM_CFLAGS@ \ -Wunused-variable \ -Wwrite-strings # Ideally, we should be enabling further flags, but this requires upstream # changes. Leaving these here for now. # # -g -Wall -Wno-long-long -W -Wformat=2 -Wmissing-prototypes \ # -Wstrict-prototypes -Wmissing-declarations -Wwrite-strings \ # -Wshadow -Wpointer-arith -Wno-sign-compare -Wundef \ # -Wbad-function-cast -Winline -Wcast-align \ # -Wdeclaration-after-statement -Wno-pointer-sign \ # -Wno-attributes -Wno-unused-result AM_CPPFLAGS += \ @AM_CPPFLAGS@ \ -DGOT_VERSION=@VERSION@ \ -DGOT_VERSION_NUMBER=@VERSION@ \ -DGOT_LIBEXECDIR="$(libexecdir)" \ -I$(top_srcdir)/template \ -I. got-portable-0.119/template/got_compat.h0000664000175000017500000000263715066536114013745 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef COMPAT_H #define COMPAT_H #ifndef __OpenBSD__ #define pledge(s, p) (0) #define unveil(s, p) (0) #endif #ifndef __dead #define __dead __attribute__((__noreturn__)) #endif #ifndef HAVE_ASPRINTF int asprintf(char **, const char *, ...); int vasprintf(char **, const char *, va_list); #endif #ifndef HAVE_ERR __dead void err(int, const char *, ...); __dead void errx(int, const char *, ...); void warn(const char *, ...); void warnx(const char *, ...); #else # include #endif #ifndef HAVE_GETPROGNAME const char *getprogname(void); #endif #ifndef HAVE_REALLOCARRAY void *reallocarray(void *, size_t, size_t); #endif #endif got-portable-0.119/template/missing0000755000175000017500000001706015066537205013033 #! /bin/sh # Common wrapper for a few potentially missing GNU and other programs. scriptversion=2024-06-07.14; # UTC # shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells # Copyright (C) 1996-2024 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autogen autoheader autom4te automake autoreconf bison flex help2man lex makeinfo perl yacc Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Report bugs to . GNU Automake home page: . General help using GNU software: ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing (GNU Automake) $scriptversion" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake|autoreconf) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; *) : ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" autoheader_deps="'acconfig.h'" automake_deps="'Makefile.am'" aclocal_deps="'acinclude.m4'" case $normalized_program in aclocal*) echo "You should only need it if you modified $aclocal_deps or" echo "$configure_deps." ;; autoconf*) echo "You should only need it if you modified $configure_deps." ;; autogen*) echo "You should only need it if you modified a '.def' or '.tpl' file." echo "You may want to install the GNU AutoGen package:" echo "<$gnu_software_URL/autogen/>" ;; autoheader*) echo "You should only need it if you modified $autoheader_deps or" echo "$configure_deps." ;; automake*) echo "You should only need it if you modified $automake_deps or" echo "$configure_deps." ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." ;; autoreconf*) echo "You should only need it if you modified $aclocal_deps or" echo "$automake_deps or $autoheader_deps or $automake_deps or" echo "$configure_deps." ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; perl*) echo "You should only need it to run GNU Autoconf, GNU Automake, " echo " assorted other tools, or if you modified a Perl source file." echo "You may want to install the Perl 5 language interpreter:" echo "<$perl_URL>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac program_details "$normalized_program" } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.119/template/parse.c0000664000175000017500000017473515066537254012735 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "parse.y" #include #include #include #include #include #include #include #include #include #include "got_compat.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; size_t ungetpos; size_t ungetsize; unsigned char *ungetbuf; int eof_reached; int lineno; int errors; } *file, *topfile; int parse(FILE *, const char *); struct file *pushfile(const char *, int); int popfile(void); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); void dbg(void); void printq(const char *); extern int nodebug; static FILE *fp; static int block; static int in_define; static int errors; static int lastline = -1; typedef struct { union { char *string; } v; int lineno; } YYSTYPE; #line 138 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ DEFINE = 258, /* DEFINE */ ELSE = 259, /* ELSE */ END = 260, /* END */ ERROR = 261, /* ERROR */ FINALLY = 262, /* FINALLY */ FOR = 263, /* FOR */ IF = 264, /* IF */ INCLUDE = 265, /* INCLUDE */ PRINTF = 266, /* PRINTF */ RENDER = 267, /* RENDER */ TQFOREACH = 268, /* TQFOREACH */ UNSAFE = 269, /* UNSAFE */ URLESCAPE = 270, /* URLESCAPE */ WHILE = 271, /* WHILE */ STRING = 272 /* STRING */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define DEFINE 258 #define ELSE 259 #define END 260 #define ERROR 261 #define FINALLY 262 #define FOR 263 #define IF 264 #define INCLUDE 265 #define PRINTF 266 #define RENDER 267 #define TQFOREACH 268 #define UNSAFE 269 #define URLESCAPE 270 #define WHILE 271 #define STRING 272 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_DEFINE = 3, /* DEFINE */ YYSYMBOL_ELSE = 4, /* ELSE */ YYSYMBOL_END = 5, /* END */ YYSYMBOL_ERROR = 6, /* ERROR */ YYSYMBOL_FINALLY = 7, /* FINALLY */ YYSYMBOL_FOR = 8, /* FOR */ YYSYMBOL_IF = 9, /* IF */ YYSYMBOL_INCLUDE = 10, /* INCLUDE */ YYSYMBOL_PRINTF = 11, /* PRINTF */ YYSYMBOL_RENDER = 12, /* RENDER */ YYSYMBOL_TQFOREACH = 13, /* TQFOREACH */ YYSYMBOL_UNSAFE = 14, /* UNSAFE */ YYSYMBOL_URLESCAPE = 15, /* URLESCAPE */ YYSYMBOL_WHILE = 16, /* WHILE */ YYSYMBOL_STRING = 17, /* STRING */ YYSYMBOL_18_ = 18, /* '!' */ YYSYMBOL_19_ = 19, /* '{' */ YYSYMBOL_20_ = 20, /* '}' */ YYSYMBOL_21_ = 21, /* '|' */ YYSYMBOL_YYACCEPT = 22, /* $accept */ YYSYMBOL_grammar = 23, /* grammar */ YYSYMBOL_include = 24, /* include */ YYSYMBOL_verbatim = 25, /* verbatim */ YYSYMBOL_verbatim1 = 26, /* verbatim1 */ YYSYMBOL_verbatims = 27, /* verbatims */ YYSYMBOL_raw = 28, /* raw */ YYSYMBOL_block = 29, /* block */ YYSYMBOL_define = 30, /* define */ YYSYMBOL_body = 31, /* body */ YYSYMBOL_special = 32, /* special */ YYSYMBOL_printf = 33, /* printf */ YYSYMBOL_34_1 = 34, /* $@1 */ YYSYMBOL_printfargs = 35, /* printfargs */ YYSYMBOL_if = 36, /* if */ YYSYMBOL_endif = 37, /* endif */ YYSYMBOL_elsif = 38, /* elsif */ YYSYMBOL_else = 39, /* else */ YYSYMBOL_loop = 40, /* loop */ YYSYMBOL_41_2 = 41, /* $@2 */ YYSYMBOL_42_3 = 42, /* $@3 */ YYSYMBOL_43_4 = 43, /* $@4 */ YYSYMBOL_end = 44, /* end */ YYSYMBOL_finally = 45, /* finally */ YYSYMBOL_46_5 = 46, /* $@5 */ YYSYMBOL_nstring = 47, /* nstring */ YYSYMBOL_string = 48, /* string */ YYSYMBOL_stringy = 49 /* stringy */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 98 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 22 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 28 /* YYNRULES -- Number of rules. */ #define YYNRULES 53 /* YYNSTATES -- Number of states. */ #define YYNSTATES 100 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 272 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 21, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 99, 99, 100, 101, 102, 103, 106, 121, 128, 129, 138, 139, 142, 153, 159, 166, 177, 178, 179, 180, 183, 189, 190, 191, 192, 200, 208, 218, 218, 232, 233, 239, 246, 247, 248, 251, 258, 264, 264, 270, 270, 279, 279, 287, 290, 290, 296, 302, 305, 311, 314, 315, 321 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "DEFINE", "ELSE", "END", "ERROR", "FINALLY", "FOR", "IF", "INCLUDE", "PRINTF", "RENDER", "TQFOREACH", "UNSAFE", "URLESCAPE", "WHILE", "STRING", "'!'", "'{'", "'}'", "'|'", "$accept", "grammar", "include", "verbatim", "verbatim1", "verbatims", "raw", "block", "define", "body", "special", "printf", "$@1", "printfargs", "if", "endif", "elsif", "else", "loop", "$@2", "$@3", "$@4", "end", "finally", "$@5", "nstring", "string", "stringy", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-33) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -33, 11, -33, -33, 22, -33, 15, -33, -33, -33, -33, -33, 2, 33, 5, -33, -33, 33, 31, 37, 51, -33, -33, -33, -33, -33, -33, -33, 36, -33, -33, -33, -33, 45, 46, -12, -12, -33, 33, 52, -12, 23, 8, 65, -33, -33, -33, -12, -12, 53, 54, -33, 55, 63, 61, -33, 17, 29, -33, -33, -33, -33, -33, -33, -33, -33, -33, -7, -33, 71, -33, 69, 72, -3, 8, 30, 75, -33, -33, -33, 76, -33, -33, -33, -12, -33, -33, 74, -33, -33, 30, -33, 30, 77, -33, -33, -33, -33, 30, -33 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 6, 0, 9, 0, 3, 4, 5, 17, 7, 0, 0, 0, 10, 8, 50, 0, 48, 0, 18, 19, 20, 22, 17, 24, 14, 0, 13, 49, 16, 47, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 15, 44, 45, 51, 0, 0, 0, 30, 0, 0, 0, 27, 0, 0, 23, 17, 17, 33, 11, 52, 53, 38, 32, 0, 21, 0, 42, 0, 0, 0, 0, 0, 46, 17, 31, 29, 0, 17, 25, 26, 0, 37, 35, 0, 34, 12, 0, 40, 0, 0, 39, 17, 43, 36, 0, 41 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -33, -33, -33, 1, -33, -33, -33, -33, -33, -24, -33, -33, -33, -33, -33, -2, -33, -33, -33, -33, -33, -33, -14, -33, -33, 79, -10, -32 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 7, 21, 12, 76, 22, 9, 10, 14, 23, 24, 51, 67, 25, 58, 59, 60, 26, 77, 95, 81, 61, 28, 62, 29, 41, 49 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 27, 42, 8, 18, 50, 47, 84, 30, 54, 48, 78, 2, 3, 79, 44, 63, 64, 85, 13, 15, 16, 4, 19, 5, 20, 19, 5, 57, 52, 5, 6, 71, 72, 73, 33, 74, 75, 35, 36, 11, 37, 38, 39, 55, 56, 40, 17, 19, 5, 87, 17, 31, 93, 90, 19, 43, 33, 92, 34, 35, 36, 88, 37, 38, 39, 45, 46, 40, 17, 53, 33, 98, 86, 65, 66, 68, 94, 89, 96, 33, 69, 70, 35, 36, 99, 37, 38, 39, 80, 82, 40, 17, 83, 5, 0, 0, 91, 97, 32 }; static const yytype_int8 yycheck[] = { 14, 25, 1, 13, 36, 17, 9, 17, 40, 21, 17, 0, 1, 20, 28, 47, 48, 20, 3, 17, 18, 10, 17, 18, 19, 17, 18, 19, 38, 18, 19, 14, 15, 4, 5, 59, 60, 8, 9, 17, 11, 12, 13, 20, 21, 16, 17, 17, 18, 19, 17, 20, 84, 77, 17, 19, 5, 81, 7, 8, 9, 75, 11, 12, 13, 20, 20, 16, 17, 17, 5, 95, 74, 20, 20, 20, 90, 76, 92, 5, 17, 20, 8, 9, 98, 11, 12, 13, 17, 20, 16, 17, 20, 18, -1, -1, 20, 20, 19 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 23, 0, 1, 10, 18, 19, 24, 25, 29, 30, 17, 26, 3, 31, 17, 18, 17, 48, 17, 19, 25, 28, 32, 33, 36, 40, 44, 45, 47, 48, 20, 47, 5, 7, 8, 9, 11, 12, 13, 16, 48, 31, 19, 44, 20, 20, 17, 21, 49, 49, 34, 48, 17, 49, 20, 21, 19, 37, 38, 39, 44, 46, 49, 49, 20, 20, 35, 20, 17, 20, 14, 15, 4, 31, 31, 27, 41, 17, 20, 17, 43, 20, 20, 9, 20, 37, 19, 44, 25, 31, 20, 31, 49, 44, 42, 44, 20, 31, 44 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 22, 23, 23, 23, 23, 23, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 34, 33, 35, 35, 36, 37, 37, 37, 38, 39, 41, 40, 42, 40, 43, 40, 44, 46, 45, 47, 47, 48, 48, 49, 49, 49 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 2, 2, 2, 2, 3, 0, 2, 0, 2, 1, 3, 4, 4, 0, 2, 2, 2, 4, 1, 3, 1, 5, 5, 3, 0, 5, 0, 2, 4, 1, 3, 3, 5, 3, 0, 7, 0, 9, 0, 7, 3, 0, 5, 2, 1, 2, 1, 1, 2, 2 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 6: /* grammar: grammar error */ #line 103 "parse.y" { file->errors++; } #line 1297 "parse.c" break; case 7: /* include: INCLUDE STRING */ #line 106 "parse.y" { struct file *nfile; if ((nfile = pushfile((yyvsp[0].v.string), 0)) == NULL) { yyerror("failed to include file %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); file = nfile; lungetc('\n'); } #line 1315 "parse.c" break; case 8: /* verbatim: '!' verbatim1 '!' */ #line 121 "parse.y" { if (in_define) { /* TODO: check template status and exit in case */ } } #line 1325 "parse.c" break; case 10: /* verbatim1: verbatim1 STRING */ #line 129 "parse.y" { if (*(yyvsp[0].v.string) != '\0') { dbg(); fprintf(fp, "%s\n", (yyvsp[0].v.string)); } free((yyvsp[0].v.string)); } #line 1337 "parse.c" break; case 13: /* raw: nstring */ #line 142 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_write(tp, "); printq((yyvsp[0].v.string)); fprintf(fp, ", %zu)) == -1) goto err;\n", strlen((yyvsp[0].v.string))); free((yyvsp[0].v.string)); } #line 1351 "parse.c" break; case 14: /* block: define body end */ #line 153 "parse.y" { fputs("err:\n", fp); fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } #line 1362 "parse.c" break; case 15: /* block: define body finally end */ #line 159 "parse.y" { fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } #line 1372 "parse.c" break; case 16: /* define: '{' DEFINE string '}' */ #line 166 "parse.y" { in_define = 1; dbg(); fprintf(fp, "int\n%s\n{\n", (yyvsp[-1].v.string)); fputs("int tp_ret = 0;\n", fp); free((yyvsp[-1].v.string)); } #line 1386 "parse.c" break; case 21: /* special: '{' RENDER string '}' */ #line 183 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = %s) == -1) goto err;\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1397 "parse.c" break; case 23: /* special: if body endif */ #line 190 "parse.y" { fputs("}\n", fp); } #line 1403 "parse.c" break; case 25: /* special: '{' string '|' UNSAFE '}' */ #line 192 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_writes(tp, %s)) == -1)\n", (yyvsp[-3].v.string)); fputs("goto err;\n", fp); free((yyvsp[-3].v.string)); } #line 1416 "parse.c" break; case 26: /* special: '{' string '|' URLESCAPE '}' */ #line 200 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_urlescape(tp, %s)) == -1)\n", (yyvsp[-3].v.string)); fputs("goto err;\n", fp); free((yyvsp[-3].v.string)); } #line 1429 "parse.c" break; case 27: /* special: '{' string '}' */ #line 208 "parse.y" { dbg(); fprintf(fp, "if ((tp_ret = tp_htmlescape(tp, %s)) == -1)\n", (yyvsp[-1].v.string)); fputs("goto err;\n", fp); free((yyvsp[-1].v.string)); } #line 1442 "parse.c" break; case 28: /* $@1: %empty */ #line 218 "parse.y" { dbg(); fprintf(fp, "if (asprintf(&tp->tp_tmp, "); } #line 1451 "parse.c" break; case 29: /* printf: '{' PRINTF $@1 printfargs '}' */ #line 221 "parse.y" { fputs(") == -1)\n", fp); fputs("goto err;\n", fp); fputs("if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) " "== -1)\n", fp); fputs("goto err;\n", fp); fputs("free(tp->tp_tmp);\n", fp); fputs("tp->tp_tmp = NULL;\n", fp); } #line 1465 "parse.c" break; case 31: /* printfargs: printfargs STRING */ #line 233 "parse.y" { fprintf(fp, " %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1474 "parse.c" break; case 32: /* if: '{' IF stringy '}' */ #line 239 "parse.y" { dbg(); fprintf(fp, "if (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1484 "parse.c" break; case 36: /* elsif: '{' ELSE IF stringy '}' */ #line 251 "parse.y" { dbg(); fprintf(fp, "} else if (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1494 "parse.c" break; case 37: /* else: '{' ELSE '}' */ #line 258 "parse.y" { dbg(); fputs("} else {\n", fp); } #line 1503 "parse.c" break; case 38: /* $@2: %empty */ #line 264 "parse.y" { fprintf(fp, "for (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1512 "parse.c" break; case 39: /* loop: '{' FOR stringy '}' $@2 body end */ #line 267 "parse.y" { fputs("}\n", fp); } #line 1520 "parse.c" break; case 40: /* $@3: %empty */ #line 270 "parse.y" { fprintf(fp, "TAILQ_FOREACH(%s, %s, %s) {\n", (yyvsp[-3].v.string), (yyvsp[-2].v.string), (yyvsp[-1].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[-1].v.string)); } #line 1532 "parse.c" break; case 41: /* loop: '{' TQFOREACH STRING STRING STRING '}' $@3 body end */ #line 276 "parse.y" { fputs("}\n", fp); } #line 1540 "parse.c" break; case 42: /* $@4: %empty */ #line 279 "parse.y" { fprintf(fp, "while (%s) {\n", (yyvsp[-1].v.string)); free((yyvsp[-1].v.string)); } #line 1549 "parse.c" break; case 43: /* loop: '{' WHILE stringy '}' $@4 body end */ #line 282 "parse.y" { fputs("}\n", fp); } #line 1557 "parse.c" break; case 45: /* $@5: %empty */ #line 290 "parse.y" { dbg(); fputs("err:\n", fp); } #line 1566 "parse.c" break; case 47: /* nstring: STRING nstring */ #line 296 "parse.y" { if (asprintf(&(yyval.v.string), "%s%s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1577 "parse.c" break; case 49: /* string: STRING string */ #line 305 "parse.y" { if (asprintf(&(yyval.v.string), "%s %s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1588 "parse.c" break; case 52: /* stringy: STRING stringy */ #line 315 "parse.y" { if (asprintf(&(yyval.v.string), "%s %s", (yyvsp[-1].v.string), (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[-1].v.string)); free((yyvsp[0].v.string)); } #line 1599 "parse.c" break; case 53: /* stringy: '|' stringy */ #line 321 "parse.y" { if (asprintf(&(yyval.v.string), "|%s", (yyvsp[0].v.string)) == -1) err(1, "asprintf"); free((yyvsp[0].v.string)); } #line 1609 "parse.c" break; #line 1613 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 328 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) err(1, "yyerror vasprintf"); va_end(ap); fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { { "define", DEFINE }, { "else", ELSE }, { "end", END }, { "finally", FINALLY }, { "for", FOR }, { "if", IF }, { "include", INCLUDE }, { "printf", PRINTF }, { "render", RENDER }, { "tailq-foreach", TQFOREACH }, { "unsafe", UNSAFE }, { "urlescape", URLESCAPE }, { "while", WHILE }, }; const struct keywords *p; p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c; if (quotec) { if ((c = igetc()) == EOF) { yyerror("reached end of filewhile parsing " "quoted string"); if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } return (c); } c = igetc(); if (c == '\t' || c == ' ') { /* Compress blanks to a sigle space. */ do { c = getc(file->stream); } while (c == '\t' || c == ' '); ungetc(c, file->stream); c = ' '; } if (c == EOF) { /* * Fake EOL when hit EOF for the first time. This gets line * count right if last line in included file is syntactically * invalid and has no newline. */ if (file->eof_reached == 0) { file->eof_reached = 1; return ('\n'); } while (c == EOF) { if (file == topfile || popfile() == EOF) return (EOF); c = igetc(); } } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "reallocarray"); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* skip to either EOF or the first real EOL */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { char buf[8096]; char *p = buf; int c; int token; int starting = 0; int ending = 0; int quote = 0; if (!in_define && block == 0) { while ((c = lgetc(0)) != '{' && c != EOF) { if (c == '\n') file->lineno++; } if (c == EOF) return (0); newblock: c = lgetc(0); if (c == '{' || c == '!') { if (c == '{') block = '}'; else block = c; return (c); } if (c == '\n') file->lineno++; } while ((c = lgetc(0)) == ' ' || c == '\t' || c == '\n') { if (c == '\n') file->lineno++; } if (c == EOF) { yyerror("unterminated block"); return (0); } yylval.lineno = file->lineno; if (block != 0 && c == block) { if ((c = lgetc(0)) == '}') { if (block == '!') { block = 0; return ('!'); } block = 0; return ('}'); } lungetc(c); c = block; } if (in_define && block == 0) { if (c == '{') goto newblock; do { if (starting) { if (c == '!' || c == '{') { lungetc(c); lungetc('{'); break; } starting = 0; lungetc(c); c = '{'; } else if (c == '{') { starting = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (block == '!') { do { if (ending) { if (c == '}') { lungetc(c); lungetc(block); break; } ending = 0; lungetc(c); c = block; } else if (c == '!') { ending = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("line too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (c == '|') return (c); do { if (!quote && isspace((unsigned char)c)) break; if (c == '"') quote = !quote; if (!quote && c == '|') { lungetc(c); break; } if (ending) { if (c == '}') { lungetc(c); lungetc('}'); break; } ending = 0; lungetc(c); c = block; } else if (!quote && c == '}') { ending = 1; continue; } *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror(quote ? "unterminated quote" : "unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((token = lookup(buf)) == STRING) if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (token); } struct file * pushfile(const char *name, int secret) { struct file *nfile; if ((nfile = calloc(1, sizeof(*nfile))) == NULL) err(1, "calloc"); if ((nfile->name = strdup(name)) == NULL) err(1, "strdup"); if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { warn("can't open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; nfile->ungetsize = 16; nfile->ungetbuf = malloc(nfile->ungetsize); if (nfile->ungetbuf == NULL) err(1, "malloc"); TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); } int popfile(void) { struct file *prev; if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; TAILQ_REMOVE(&files, file, entry); fclose(file->stream); free(file->name); free(file->ungetbuf); free(file); file = prev; return (file ? 0 : EOF); } int parse(FILE *outfile, const char *filename) { fp = outfile; if ((file = pushfile(filename, 0)) == 0) return (-1); topfile = file; yyparse(); errors = file->errors; popfile(); return (errors ? -1 : 0); } void dbg(void) { if (nodebug) return; if (yylval.lineno == lastline + 1) { lastline = yylval.lineno; return; } lastline = yylval.lineno; fprintf(fp, "#line %d ", yylval.lineno); printq(file->name); putc('\n', fp); } void printq(const char *str) { putc('"', fp); for (; *str; ++str) { if (*str == '"') putc('\\', fp); putc(*str, fp); } putc('"', fp); } got-portable-0.119/template/compile0000755000175000017500000001670515066537205013017 #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2024-06-19.01; # UTC # Copyright (C) 1999-2024 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.lo | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . GNU Automake home page: . General help using GNU software: . EOF exit $? ;; -v | --v*) echo "compile (GNU Automake) $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.119/template/install-sh0000755000175000017500000003611515066537205013442 #!/bin/sh # install - install a program, script, or datafile scriptversion=2024-06-19.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Report bugs to . GNU Automake home page: . General help using GNU software: ." while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibility with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.119/template/configure0000775000175000017500000064550415066537204013356 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.72 for template 1.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case e in #( e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else case e in #( e) exitcode=1; echo positional parameters were not saved. ;; esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else case e in #( e) as_have_required=no ;; esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi ;; esac fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and op@openbsd.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi ;; esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' t clear :clear s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='template' PACKAGE_TARNAME='template' PACKAGE_VERSION='1.0' PACKAGE_STRING='template 1.0' PACKAGE_BUGREPORT='op@openbsd.org' PACKAGE_URL='' ac_config_libobj_dir=../compat # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS AM_LDFLAGS AM_CFLAGS AM_CPPFLAGS LIBOBJS LIBBSD_LIBS LIBBSD_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG YFLAGS YACC am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC HOSTCFLAGS HOSTCC am__xargs_n am__rm_f_notfound AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking ' ac_precious_vars='build_alias host_alias target_alias HOSTCC HOSTCFLAGS CC CFLAGS LDFLAGS LIBS CPPFLAGS YACC YFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBBSD_CFLAGS LIBBSD_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: '$ac_option' Try '$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF 'configure' configures template 1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, 'make install' will install all the files in '$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify an installation prefix other than '$ac_default_prefix' using '--prefix', for instance '--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/template] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of template 1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Some influential environment variables: HOSTCC The C compiler on the host. HOSTCFLAGS CFLAGS for the host compiler CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory YACC The 'Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: 'bison -y', 'byacc', 'yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of '-d' given by some make applications. PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBBSD_CFLAGS C compiler flags for LIBBSD, overriding pkg-config LIBBSD_LIBS linker flags for LIBBSD, overriding pkg-config Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF template configure 1.0 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by template $as_me 1.0, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See 'config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* C89 style stringification. */ #define noexpand_stringify(a) #a const char *stringified = noexpand_stringify(arbitrary+token=sequence); /* C89 style token pasting. Exercises some of the corner cases that e.g. old MSVC gets wrong, but not very hard. */ #define noexpand_concat(a,b) a##b #define expand_concat(a,b) noexpand_concat(a,b) extern int vA; extern int vbee; #define aye A #define bee B int *pvA = &expand_concat(v,aye); int *pvbee = &noexpand_concat(v,bee); /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' /* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif // See if C++-style comments work. #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Work around memory leak warnings. free (ia); // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' /* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" # Auxiliary files required by this configure script. ac_aux_files="compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; esac fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.17' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir ;; esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 printf %s "checking whether sleep supports fractional seconds... " >&6; } if test ${am_cv_sleep_fractional_seconds+y} then : printf %s "(cached) " >&6 else case e in #( e) if sleep 0.001 2>/dev/null then : am_cv_sleep_fractional_seconds=yes else case e in #( e) am_cv_sleep_fractional_seconds=no ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 printf "%s\n" "$am_cv_sleep_fractional_seconds" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 printf %s "checking filesystem timestamp resolution... " >&6; } if test ${am_cv_filesystem_timestamp_resolution+y} then : printf %s "(cached) " >&6 else case e in #( e) # Default to the worst case. am_cv_filesystem_timestamp_resolution=2 # Only try to go finer than 1 sec if sleep can do it. # Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, # - 1 sec is not much of a win compared to 2 sec, and # - it takes 2 seconds to perform the test whether 1 sec works. # # Instead, just use the default 2s on platforms that have 1s resolution, # accept the extra 1s delay when using $sleep in the Automake tests, in # exchange for not incurring the 2s delay for running the test for all # packages. # am_try_resolutions= if test "$am_cv_sleep_fractional_seconds" = yes; then # Even a millisecond often causes a bunch of false positives, # so just try a hundredth of a second. The time saved between .001 and # .01 is not terribly consequential. am_try_resolutions="0.01 0.1 $am_try_resolutions" fi # In order to catch current-generation FAT out, we must *modify* files # that already exist; the *creation* timestamp is finer. Use names # that make ls -t sort them differently when they have equal # timestamps than when they have distinct timestamps, keeping # in mind that ls -t prints the *newest* file first. rm -f conftest.ts? : > conftest.ts1 : > conftest.ts2 : > conftest.ts3 # Make sure ls -t actually works. Do 'set' in a subshell so we don't # clobber the current shell's arguments. (Outer-level square brackets # are removed by m4; they're present so that m4 does not expand # ; be careful, easy to get confused.) if ( set X `ls -t conftest.ts[12]` && { test "$*" != "X conftest.ts1 conftest.ts2" || test "$*" != "X conftest.ts2 conftest.ts1"; } ); then :; else # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". printf "%s\n" ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "ls -t produces unexpected output. Make sure there is not a broken ls alias in your environment. See 'config.log' for more details" "$LINENO" 5; } fi for am_try_res in $am_try_resolutions; do # Any one fine-grained sleep might happen to cross the boundary # between two values of a coarser actual resolution, but if we do # two fine-grained sleeps in a row, at least one of them will fall # entirely within a coarse interval. echo alpha > conftest.ts1 sleep $am_try_res echo beta > conftest.ts2 sleep $am_try_res echo gamma > conftest.ts3 # We assume that 'ls -t' will make use of high-resolution # timestamps if the operating system supports them at all. if (set X `ls -t conftest.ts?` && test "$2" = conftest.ts3 && test "$3" = conftest.ts2 && test "$4" = conftest.ts1); then # # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, # because we don't need to test make. make_ok=true if test $am_try_res != 1; then # But if we've succeeded so far with a subsecond resolution, we # have one more thing to check: make. It can happen that # everything else supports the subsecond mtimes, but make doesn't; # notably on macOS, which ships make 3.81 from 2006 (the last one # released under GPLv2). https://bugs.gnu.org/68808 # # We test $MAKE if it is defined in the environment, else "make". # It might get overridden later, but our hope is that in practice # it does not matter: it is the system "make" which is (by far) # the most likely to be broken, whereas if the user overrides it, # probably they did so with a better, or at least not worse, make. # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html # # Create a Makefile (real tab character here): rm -f conftest.mk echo 'conftest.ts1: conftest.ts2' >conftest.mk echo ' touch conftest.ts2' >>conftest.mk # # Now, running # touch conftest.ts1; touch conftest.ts2; make # should touch ts1 because ts2 is newer. This could happen by luck, # but most often, it will fail if make's support is insufficient. So # test for several consecutive successes. # # (We reuse conftest.ts[12] because we still want to modify existing # files, not create new ones, per above.) n=0 make=${MAKE-make} until test $n -eq 3; do echo one > conftest.ts1 sleep $am_try_res echo two > conftest.ts2 # ts2 should now be newer than ts1 if $make -f conftest.mk | grep 'up to date' >/dev/null; then make_ok=false break # out of $n loop fi n=`expr $n + 1` done fi # if $make_ok; then # Everything we know to check worked out, so call this resolution good. am_cv_filesystem_timestamp_resolution=$am_try_res break # out of $am_try_res loop fi # Otherwise, we'll go on to check the next resolution. fi done rm -f conftest.ts? # (end _am_filesystem_timestamp_resolution) ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 printf "%s\n" "$am_cv_filesystem_timestamp_resolution" >&6; } # This check should not be cached, as it may vary across builds of # different projects. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). am_build_env_is_sane=no am_has_slept=no rm -f conftest.file for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi test "$2" = conftest.file ); then am_build_env_is_sane=yes break fi # Just in case. sleep "$am_cv_filesystem_timestamp_resolution" am_has_slept=yes done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 printf "%s\n" "$am_build_env_is_sane" >&6; } if test "$am_build_env_is_sane" = no; then as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 then : else case e in #( e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! ;; esac fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was 's,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ *'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS ;; esac fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use plain mkdir -p, # in the hope it doesn't have the bugs of ancient mkdir. MKDIR_P='mkdir -p' fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else case e in #( e) cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make ;; esac fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AM_DEFAULT_VERBOSITY=1 # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else case e in #( e) if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } AM_BACKSLASH='\' am__rm_f_notfound= if (rm -f && rm -fr && rm -rf) 2>/dev/null then : else case e in #( e) am__rm_f_notfound='""' ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 printf %s "checking xargs -n works... " >&6; } if test ${am_cv_xargs_n_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 3" then : am_cv_xargs_n_works=yes else case e in #( e) am_cv_xargs_n_works=no ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 printf "%s\n" "$am_cv_xargs_n_works" >&6; } if test "$am_cv_xargs_n_works" = yes then : am__xargs_n='xargs -n' else case e in #( e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' ;; esac fi if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='template' VERSION='1.0' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. # So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else case e in #( e) ac_file='' ;; esac fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See 'config.log' for more details" "$LINENO" 5; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) # catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will # work properly (i.e., refer to 'conftest.exe'), while it won't with # 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); if (!f) return 1; return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use '--host'. See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext \ conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else case e in #( e) ac_cv_safe_to_define___extensions__=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else case e in #( e) MINIX= ;; esac fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" test -n "$HOSTCC" && export CC="$HOSTCC" test -n "$HOSTCFLAGS" && export CFLAGS="$SAVED_CFLAGS $HOSTCFLAGS" YACC_OVERRIDE=yes ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi if test -z "$YACC"; then YACC_OVERRIDE="no" for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 printf "%s\n" "$YACC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbsd-overlay" >&5 printf %s "checking for libbsd-overlay... " >&6; } if test -n "$LIBBSD_CFLAGS"; then pkg_cv_LIBBSD_CFLAGS="$LIBBSD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_CFLAGS=`$PKG_CONFIG --cflags "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBBSD_LIBS"; then pkg_cv_LIBBSD_LIBS="$LIBBSD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_LIBS=`$PKG_CONFIG --libs "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBBSD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libbsd-overlay" 2>&1` else LIBBSD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libbsd-overlay" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBBSD_PKG_ERRORS" >&5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libbsd not found" >&5 printf "%s\n" "$as_me: libbsd not found" >&6;} elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libbsd not found" >&5 printf "%s\n" "$as_me: libbsd not found" >&6;} else LIBBSD_CFLAGS=$pkg_cv_LIBBSD_CFLAGS LIBBSD_LIBS=$pkg_cv_LIBBSD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } AM_CFLAGS="$LIBBSD_CFLAGS $AM_CFLAGS" CFLAGS="$AM_CFLAGS $SAVED_CFLAGS" LIBS="$LIBBSD_LIBS $LIBS" printf "%s\n" "#define HAVE_LIBBSD 1" >>confdefs.h fi AM_CPPFLAGS="$CFLAGS" ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = xyes then : printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" asprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "err" "ac_cv_func_err" if test "x$ac_cv_func_err" = xyes then : printf "%s\n" "#define HAVE_ERR 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" err.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS err.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "getprogname" "ac_cv_func_getprogname" if test "x$ac_cv_func_getprogname" = xyes then : printf "%s\n" "#define HAVE_GETPROGNAME 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" getprogname.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getprogname.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes then : printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else case e in #( e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; esac fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "TAILQ_REMOVE" "ac_cv_have_decl_TAILQ_REMOVE" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_REMOVE" = xyes then : else case e in #( e) as_fn_error $? "\"*** sys/queue.h is missing key defines ***\"" "$LINENO" 5 ;; esac fi CPPFLAGS="$SAVED_CPPFLAGS" CFLAGS="$SAVED_CFLAGS" LDFLAGS="$SAVED_LDFLAGS" ac_config_files="$ac_config_files Makefile Makefile.common:Makefile.common.in" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # 'ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[][ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; esac if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by template $as_me 1.0, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ '$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ template config.status 1.0 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: '$1' Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile.common") CONFIG_FILES="$CONFIG_FILES Makefile.common:Makefile.common.in" ;; *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See 'config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi got-portable-0.119/template/configure.ac0000664000175000017500000000302315066536114013714 AC_INIT([template], 1.0, [op@openbsd.org]) AC_CONFIG_LIBOBJ_DIR(../compat) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_ARG_VAR(HOSTCC, [The C compiler on the host.]) AC_ARG_VAR(HOSTCFLAGS, [CFLAGS for the host compiler]) AC_USE_SYSTEM_EXTENSIONS # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" test -n "$HOSTCC" && export CC="$HOSTCC" test -n "$HOSTCFLAGS" && export CFLAGS="$SAVED_CFLAGS $HOSTCFLAGS" YACC_OVERRIDE=yes AC_PROG_CC if test -z "$YACC"; then YACC_OVERRIDE="no" AC_PROG_YACC fi PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(LIBBSD, libbsd-overlay, [ AM_CFLAGS="$LIBBSD_CFLAGS $AM_CFLAGS" CFLAGS="$AM_CFLAGS $SAVED_CFLAGS" LIBS="$LIBBSD_LIBS $LIBS" AC_DEFINE(HAVE_LIBBSD) ], [AC_MSG_NOTICE([libbsd not found])]) AM_CPPFLAGS="$CFLAGS" AC_REPLACE_FUNCS([ \ asprintf \ err \ getprogname \ reallocarray \ ]) AC_CHECK_DECL([TAILQ_REMOVE], [], [AC_MSG_ERROR("*** sys/queue.h is missing key defines ***")], [#include ]) AC_SUBST(AM_CPPFLAGS) CPPFLAGS="$SAVED_CPPFLAGS" AC_SUBST(AM_CFLAGS) CFLAGS="$SAVED_CFLAGS" AC_SUBST(AM_LDFLAGS) LDFLAGS="$SAVED_LDFLAGS" AC_CONFIG_FILES([Makefile Makefile.common:Makefile.common.in ]) AC_OUTPUT got-portable-0.119/template/aclocal.m40000664000175000017500000016770515066537203013310 # generated automatically by aclocal 1.17 -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, [m4_warning([this file was generated for autoconf 2.72. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.17' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.17], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.17])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([_AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl AC_REQUIRE([_AM_PROG_RM_F]) AC_REQUIRE([_AM_PROG_XARGS_N]) dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2022-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_RM_F # --------------- # Check whether 'rm -f' without any arguments works. # https://bugs.gnu.org/10828 AC_DEFUN([_AM_PROG_RM_F], [am__rm_f_notfound= AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) AC_SUBST(am__rm_f_notfound) ]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SLEEP_FRACTIONAL_SECONDS # ---------------------------- AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl AC_CACHE_CHECK([whether sleep supports fractional seconds], am_cv_sleep_fractional_seconds, [dnl AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], [am_cv_sleep_fractional_seconds=no]) ])]) # _AM_FILESYSTEM_TIMESTAMP_RESOLUTION # ----------------------------------- # Determine the filesystem's resolution for file modification # timestamps. The coarsest we know of is FAT, with a resolution # of only two seconds, even with the most recent "exFAT" extensions. # The finest (e.g. ext4 with large inodes, XFS, ZFS) is one # nanosecond, matching clock_gettime. However, it is probably not # possible to delay execution of a shell script for less than one # millisecond, due to process creation overhead and scheduling # granularity, so we don't check for anything finer than that. (See below.) AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) AC_CACHE_CHECK([filesystem timestamp resolution], am_cv_filesystem_timestamp_resolution, [dnl # Default to the worst case. am_cv_filesystem_timestamp_resolution=2 # Only try to go finer than 1 sec if sleep can do it. # Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, # - 1 sec is not much of a win compared to 2 sec, and # - it takes 2 seconds to perform the test whether 1 sec works. # # Instead, just use the default 2s on platforms that have 1s resolution, # accept the extra 1s delay when using $sleep in the Automake tests, in # exchange for not incurring the 2s delay for running the test for all # packages. # am_try_resolutions= if test "$am_cv_sleep_fractional_seconds" = yes; then # Even a millisecond often causes a bunch of false positives, # so just try a hundredth of a second. The time saved between .001 and # .01 is not terribly consequential. am_try_resolutions="0.01 0.1 $am_try_resolutions" fi # In order to catch current-generation FAT out, we must *modify* files # that already exist; the *creation* timestamp is finer. Use names # that make ls -t sort them differently when they have equal # timestamps than when they have distinct timestamps, keeping # in mind that ls -t prints the *newest* file first. rm -f conftest.ts? : > conftest.ts1 : > conftest.ts2 : > conftest.ts3 # Make sure ls -t actually works. Do 'set' in a subshell so we don't # clobber the current shell's arguments. (Outer-level square brackets # are removed by m4; they're present so that m4 does not expand # ; be careful, easy to get confused.) if ( set X `[ls -t conftest.ts[12]]` && { test "$[]*" != "X conftest.ts1 conftest.ts2" || test "$[]*" != "X conftest.ts2 conftest.ts1"; } ); then :; else # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". _AS_ECHO_UNQUOTED( ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], [AS_MESSAGE_LOG_FD]) AC_MSG_FAILURE([ls -t produces unexpected output. Make sure there is not a broken ls alias in your environment.]) fi for am_try_res in $am_try_resolutions; do # Any one fine-grained sleep might happen to cross the boundary # between two values of a coarser actual resolution, but if we do # two fine-grained sleeps in a row, at least one of them will fall # entirely within a coarse interval. echo alpha > conftest.ts1 sleep $am_try_res echo beta > conftest.ts2 sleep $am_try_res echo gamma > conftest.ts3 # We assume that 'ls -t' will make use of high-resolution # timestamps if the operating system supports them at all. if (set X `ls -t conftest.ts?` && test "$[]2" = conftest.ts3 && test "$[]3" = conftest.ts2 && test "$[]4" = conftest.ts1); then # # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, # because we don't need to test make. make_ok=true if test $am_try_res != 1; then # But if we've succeeded so far with a subsecond resolution, we # have one more thing to check: make. It can happen that # everything else supports the subsecond mtimes, but make doesn't; # notably on macOS, which ships make 3.81 from 2006 (the last one # released under GPLv2). https://bugs.gnu.org/68808 # # We test $MAKE if it is defined in the environment, else "make". # It might get overridden later, but our hope is that in practice # it does not matter: it is the system "make" which is (by far) # the most likely to be broken, whereas if the user overrides it, # probably they did so with a better, or at least not worse, make. # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html # # Create a Makefile (real tab character here): rm -f conftest.mk echo 'conftest.ts1: conftest.ts2' >conftest.mk echo ' touch conftest.ts2' >>conftest.mk # # Now, running # touch conftest.ts1; touch conftest.ts2; make # should touch ts1 because ts2 is newer. This could happen by luck, # but most often, it will fail if make's support is insufficient. So # test for several consecutive successes. # # (We reuse conftest.ts[12] because we still want to modify existing # files, not create new ones, per above.) n=0 make=${MAKE-make} until test $n -eq 3; do echo one > conftest.ts1 sleep $am_try_res echo two > conftest.ts2 # ts2 should now be newer than ts1 if $make -f conftest.mk | grep 'up to date' >/dev/null; then make_ok=false break # out of $n loop fi n=`expr $n + 1` done fi # if $make_ok; then # Everything we know to check worked out, so call this resolution good. am_cv_filesystem_timestamp_resolution=$am_try_res break # out of $am_try_res loop fi # Otherwise, we'll go on to check the next resolution. fi done rm -f conftest.ts? # (end _am_filesystem_timestamp_resolution) ])]) # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) # This check should not be cached, as it may vary across builds of # different projects. AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). am_build_env_is_sane=no am_has_slept=no rm -f conftest.file for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[]*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi test "$[]2" = conftest.file ); then am_build_env_is_sane=yes break fi # Just in case. sleep "$am_cv_filesystem_timestamp_resolution" am_has_slept=yes done AC_MSG_RESULT([$am_build_env_is_sane]) if test "$am_build_env_is_sane" = no; then AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! ]) AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SILENT_RULES # ---------------- # Enable less verbose build rules support. AC_DEFUN([_AM_SILENT_RULES], [AM_DEFAULT_VERBOSITY=1 AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls dnl to AM_SILENT_RULES to change the default value. AC_CONFIG_COMMANDS_PRE([dnl case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; esac if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi ])dnl ]) # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or # empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_REQUIRE([_AM_SILENT_RULES]) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test x$am_uid = xunknown; then AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) elif test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test x$gm_gid = xunknown; then AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) elif test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR # Copyright (C) 2022-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_XARGS_N # ---------------- # Check whether 'xargs -n' works. It should work everywhere, so the fallback # is not optimized at all as we never expect to use it. AC_DEFUN([_AM_PROG_XARGS_N], [AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' ])dnl AC_SUBST(am__xargs_n) ]) got-portable-0.119/template/Makefile.am0000664000175000017500000000023515066536114013464 noinst_PROGRAMS = template include $(top_builddir)/Makefile.common template_SOURCES = template.c \ parse.y EXTRA_DIST = got_compat.h LDADD = $(LIBOBJS) got-portable-0.119/template/parse.y0000664000175000017500000003246515066536114012746 /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2007-2016 Reyk Floeter * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include #include #include #include #include #include #include #include #include #include "got_compat.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; size_t ungetpos; size_t ungetsize; unsigned char *ungetbuf; int eof_reached; int lineno; int errors; } *file, *topfile; int parse(FILE *, const char *); struct file *pushfile(const char *, int); int popfile(void); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); int lgetc(int); void lungetc(int); int findeol(void); void dbg(void); void printq(const char *); extern int nodebug; static FILE *fp; static int block; static int in_define; static int errors; static int lastline = -1; typedef struct { union { char *string; } v; int lineno; } YYSTYPE; %} %token DEFINE ELSE END ERROR FINALLY FOR IF INCLUDE PRINTF %token RENDER TQFOREACH UNSAFE URLESCAPE WHILE %token STRING %type string nstring %type stringy %% grammar : /* empty */ | grammar include | grammar verbatim | grammar block | grammar error { file->errors++; } ; include : INCLUDE STRING { struct file *nfile; if ((nfile = pushfile($2, 0)) == NULL) { yyerror("failed to include file %s", $2); free($2); YYERROR; } free($2); file = nfile; lungetc('\n'); } ; verbatim : '!' verbatim1 '!' { if (in_define) { /* TODO: check template status and exit in case */ } } ; verbatim1 : /* empty */ | verbatim1 STRING { if (*$2 != '\0') { dbg(); fprintf(fp, "%s\n", $2); } free($2); } ; verbatims : /* empty */ | verbatims verbatim ; raw : nstring { dbg(); fprintf(fp, "if ((tp_ret = tp_write(tp, "); printq($1); fprintf(fp, ", %zu)) == -1) goto err;\n", strlen($1)); free($1); } ; block : define body end { fputs("err:\n", fp); fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } | define body finally end { fputs("return tp_ret;\n", fp); fputs("}\n", fp); in_define = 0; } ; define : '{' DEFINE string '}' { in_define = 1; dbg(); fprintf(fp, "int\n%s\n{\n", $3); fputs("int tp_ret = 0;\n", fp); free($3); } ; body : /* empty */ | body verbatim | body raw | body special ; special : '{' RENDER string '}' { dbg(); fprintf(fp, "if ((tp_ret = %s) == -1) goto err;\n", $3); free($3); } | printf | if body endif { fputs("}\n", fp); } | loop | '{' string '|' UNSAFE '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_writes(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } | '{' string '|' URLESCAPE '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_urlescape(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } | '{' string '}' { dbg(); fprintf(fp, "if ((tp_ret = tp_htmlescape(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); } ; printf : '{' PRINTF { dbg(); fprintf(fp, "if (asprintf(&tp->tp_tmp, "); } printfargs '}' { fputs(") == -1)\n", fp); fputs("goto err;\n", fp); fputs("if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) " "== -1)\n", fp); fputs("goto err;\n", fp); fputs("free(tp->tp_tmp);\n", fp); fputs("tp->tp_tmp = NULL;\n", fp); } ; printfargs : /* empty */ | printfargs STRING { fprintf(fp, " %s", $2); free($2); } ; if : '{' IF stringy '}' { dbg(); fprintf(fp, "if (%s) {\n", $3); free($3); } ; endif : end | else body end | elsif body endif ; elsif : '{' ELSE IF stringy '}' { dbg(); fprintf(fp, "} else if (%s) {\n", $4); free($4); } ; else : '{' ELSE '}' { dbg(); fputs("} else {\n", fp); } ; loop : '{' FOR stringy '}' { fprintf(fp, "for (%s) {\n", $3); free($3); } body end { fputs("}\n", fp); } | '{' TQFOREACH STRING STRING STRING '}' { fprintf(fp, "TAILQ_FOREACH(%s, %s, %s) {\n", $3, $4, $5); free($3); free($4); free($5); } body end { fputs("}\n", fp); } | '{' WHILE stringy '}' { fprintf(fp, "while (%s) {\n", $3); free($3); } body end { fputs("}\n", fp); } ; end : '{' END '}' ; finally : '{' FINALLY '}' { dbg(); fputs("err:\n", fp); } verbatims ; nstring : STRING nstring { if (asprintf(&$$, "%s%s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | STRING ; string : STRING string { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | STRING ; stringy : STRING | STRING stringy { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "asprintf"); free($1); free($2); } | '|' stringy { if (asprintf(&$$, "|%s", $2) == -1) err(1, "asprintf"); free($2); } ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) err(1, "yyerror vasprintf"); va_end(ap); fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { { "define", DEFINE }, { "else", ELSE }, { "end", END }, { "finally", FINALLY }, { "for", FOR }, { "if", IF }, { "include", INCLUDE }, { "printf", PRINTF }, { "render", RENDER }, { "tailq-foreach", TQFOREACH }, { "unsafe", UNSAFE }, { "urlescape", URLESCAPE }, { "while", WHILE }, }; const struct keywords *p; p = bsearch(s, keywords, nitems(keywords), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define START_EXPAND 1 #define DONE_EXPAND 2 static int expanding; int igetc(void) { int c; while (1) { if (file->ungetpos > 0) c = file->ungetbuf[--file->ungetpos]; else c = getc(file->stream); if (c == START_EXPAND) expanding = 1; else if (c == DONE_EXPAND) expanding = 0; else break; } return (c); } int lgetc(int quotec) { int c; if (quotec) { if ((c = igetc()) == EOF) { yyerror("reached end of filewhile parsing " "quoted string"); if (file == topfile || popfile() == EOF) return (EOF); return (quotec); } return (c); } c = igetc(); if (c == '\t' || c == ' ') { /* Compress blanks to a sigle space. */ do { c = getc(file->stream); } while (c == '\t' || c == ' '); ungetc(c, file->stream); c = ' '; } if (c == EOF) { /* * Fake EOL when hit EOF for the first time. This gets line * count right if last line in included file is syntactically * invalid and has no newline. */ if (file->eof_reached == 0) { file->eof_reached = 1; return ('\n'); } while (c == EOF) { if (file == topfile || popfile() == EOF) return (EOF); c = igetc(); } } return (c); } void lungetc(int c) { if (c == EOF) return; if (file->ungetpos >= file->ungetsize) { void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); if (p == NULL) err(1, "reallocarray"); file->ungetbuf = p; file->ungetsize *= 2; } file->ungetbuf[file->ungetpos++] = c; } int findeol(void) { int c; /* skip to either EOF or the first real EOL */ while (1) { c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { char buf[8096]; char *p = buf; int c; int token; int starting = 0; int ending = 0; int quote = 0; if (!in_define && block == 0) { while ((c = lgetc(0)) != '{' && c != EOF) { if (c == '\n') file->lineno++; } if (c == EOF) return (0); newblock: c = lgetc(0); if (c == '{' || c == '!') { if (c == '{') block = '}'; else block = c; return (c); } if (c == '\n') file->lineno++; } while ((c = lgetc(0)) == ' ' || c == '\t' || c == '\n') { if (c == '\n') file->lineno++; } if (c == EOF) { yyerror("unterminated block"); return (0); } yylval.lineno = file->lineno; if (block != 0 && c == block) { if ((c = lgetc(0)) == '}') { if (block == '!') { block = 0; return ('!'); } block = 0; return ('}'); } lungetc(c); c = block; } if (in_define && block == 0) { if (c == '{') goto newblock; do { if (starting) { if (c == '!' || c == '{') { lungetc(c); lungetc('{'); break; } starting = 0; lungetc(c); c = '{'; } else if (c == '{') { starting = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (block == '!') { do { if (ending) { if (c == '}') { lungetc(c); lungetc(block); break; } ending = 0; lungetc(c); c = block; } else if (c == '!') { ending = 1; continue; } else if (c == '\n') break; *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("line too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror("unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (STRING); } if (c == '|') return (c); do { if (!quote && isspace((unsigned char)c)) break; if (c == '"') quote = !quote; if (!quote && c == '|') { lungetc(c); break; } if (ending) { if (c == '}') { lungetc(c); lungetc('}'); break; } ending = 0; lungetc(c); c = block; } else if (!quote && c == '}') { ending = 1; continue; } *p++ = c; if ((size_t)(p - buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } } while ((c = lgetc(0)) != EOF); *p = '\0'; if (c == EOF) { yyerror(quote ? "unterminated quote" : "unterminated block"); return (0); } if (c == '\n') file->lineno++; if ((token = lookup(buf)) == STRING) if ((yylval.v.string = strdup(buf)) == NULL) err(1, "strdup"); return (token); } struct file * pushfile(const char *name, int secret) { struct file *nfile; if ((nfile = calloc(1, sizeof(*nfile))) == NULL) err(1, "calloc"); if ((nfile->name = strdup(name)) == NULL) err(1, "strdup"); if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { warn("can't open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; nfile->ungetsize = 16; nfile->ungetbuf = malloc(nfile->ungetsize); if (nfile->ungetbuf == NULL) err(1, "malloc"); TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); } int popfile(void) { struct file *prev; if ((prev = TAILQ_PREV(file, files, entry)) != NULL) prev->errors += file->errors; TAILQ_REMOVE(&files, file, entry); fclose(file->stream); free(file->name); free(file->ungetbuf); free(file); file = prev; return (file ? 0 : EOF); } int parse(FILE *outfile, const char *filename) { fp = outfile; if ((file = pushfile(filename, 0)) == 0) return (-1); topfile = file; yyparse(); errors = file->errors; popfile(); return (errors ? -1 : 0); } void dbg(void) { if (nodebug) return; if (yylval.lineno == lastline + 1) { lastline = yylval.lineno; return; } lastline = yylval.lineno; fprintf(fp, "#line %d ", yylval.lineno); printq(file->name); putc('\n', fp); } void printq(const char *str) { putc('"', fp); for (; *str; ++str) { if (*str == '"') putc('\\', fp); putc(*str, fp); } putc('"', fp); } got-portable-0.119/template/ylwrap0000755000175000017500000001545715066537205012710 #! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2024-06-19.01; # UTC # Copyright (C) 1996-2024 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard () { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . GNU Automake home page: . General help using GNU software: . EOF exit $? ;; -v|--v*) echo "ylwrap (GNU Automake) $scriptversion" exit $? ;; esac # The input. input=$1 shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input=`pwd`/$input ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test $# -ne 0; do if test x"$1" = x"--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog=$1 shift # Make any relative path in $prog absolute. case $prog in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog=`pwd`/$prog ;; esac dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target=../$to;; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget=$target target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.119/template/tmpl.c0000664000175000017500000000654715066536114012564 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "got_compat.h" #include "tmpl.h" int tp_write(struct template *tp, const char *str, size_t len) { size_t avail; while (len > 0) { avail = tp->tp_cap - tp->tp_len; if (avail == 0) { if (template_flush(tp) == -1) return (-1); avail = tp->tp_cap; } if (len < avail) avail = len; memcpy(tp->tp_buf + tp->tp_len, str, avail); tp->tp_len += avail; str += avail; len -= avail; } return (0); } int tp_writes(struct template *tp, const char *str) { return (tp_write(tp, str, strlen(str))); } int tp_writef(struct template *tp, const char *fmt, ...) { va_list ap; char *str; int r; va_start(ap, fmt); r = vasprintf(&str, fmt, ap); va_end(ap); if (r == -1) return (-1); r = tp_write(tp, str, r); free(str); return (r); } int tp_urlescape(struct template *tp, const char *str) { int r; char tmp[4]; if (str == NULL) return (0); for (; *str; ++str) { if (iscntrl((unsigned char)*str) || isspace((unsigned char)*str) || *str == '\'' || *str == '"' || *str == '\\') { r = snprintf(tmp, sizeof(tmp), "%%%2X", *str); if (r < 0 || (size_t)r >= sizeof(tmp)) return (0); if (tp_write(tp, tmp, r) == -1) return (-1); } else { if (tp_write(tp, str, 1) == -1) return (-1); } } return (0); } static inline int htmlescape(struct template *tp, char c) { switch (c) { case '<': return tp_write(tp, "<", 4); case '>': return tp_write(tp, ">", 4); case '&': return tp_write(tp, "&", 5); case '"': return tp_write(tp, """, 6); case '\'': return tp_write(tp, "'", 6); default: return tp_write(tp, &c, 1); } } int tp_htmlescape(struct template *tp, const char *str) { if (str == NULL) return (0); for (; *str; ++str) { if (htmlescape(tp, *str) == -1) return (-1); } return (0); } int tp_write_htmlescape(struct template *tp, const char *str, size_t len) { size_t i; for (i = 0; i < len; ++i) { if (htmlescape(tp, str[i]) == -1) return (-1); } return (0); } struct template * template(void *arg, tmpl_write writefn, char *buf, size_t siz) { struct template *tp; if ((tp = calloc(1, sizeof(*tp))) == NULL) return (NULL); tp->tp_arg = arg; tp->tp_write = writefn; tp->tp_buf = buf; tp->tp_cap = siz; return (tp); } int template_flush(struct template *tp) { if (tp->tp_len == 0) return (0); if (tp->tp_write(tp->tp_arg, tp->tp_buf, tp->tp_len) == -1) return (-1); tp->tp_len = 0; return (0); } void template_free(struct template *tp) { free(tp->tp_tmp); free(tp); } got-portable-0.119/template/template.c0000664000175000017500000000371615066536114013416 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "got_compat.h" int parse(FILE *, const char *); int nodebug; static void __dead usage(void) { fprintf(stderr, "usage: %s [-G] [-o out] [file ...]\n", getprogname()); exit(1); } int main(int argc, char **argv) { FILE *fp = stdout; const char *out = NULL; int ch, i; while ((ch = getopt(argc, argv, "Go:")) != -1) { switch (ch) { case 'G': nodebug = 1; break; case 'o': out = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (out && (fp = fopen(out, "w")) == NULL) err(1, "can't open %s", out); if (out && unveil(out, "wc") == -1) err(1, "unveil %s", out); if (unveil("/", "r") == -1) err(1, "unveil /"); if (pledge(out ? "stdio rpath cpath" : "stdio rpath", NULL) == -1) err(1, "pledge"); if (argc == 0) { nodebug = 1; if (parse(fp, "/dev/stdin") == -1) goto err; } else { for (i = 0; i < argc; ++i) if (parse(fp, argv[i]) == -1) goto err; } if (ferror(fp)) goto err; if (fclose(fp) == -1) { fp = NULL; goto err; } return (0); err: if (fp) fclose(fp); if (out && unlink(out) == -1) err(1, "unlink %s", out); return (1); } got-portable-0.119/template/depcomp0000755000175000017500000005621715066537205013020 #! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2024-06-19.01; # UTC # Copyright (C) 1999-2024 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . GNU Automake home page: . General help using GNU software: . EOF exit $? ;; -v | --v*) echo "depcomp (GNU Automake) $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interference from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsolete pre-3.x GCC compilers. ## but also to in-use compilers like IBM xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: got-portable-0.119/template/tmpl.h0000664000175000017500000000302315066535722012557 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef TMPL_H #define TMPL_H struct template; typedef int (*tmpl_write)(void *, const void *, size_t); struct template { void *tp_arg; char *tp_tmp; tmpl_write tp_write; char *tp_buf; size_t tp_len; size_t tp_cap; }; int tp_write(struct template *, const char *, size_t); int tp_writes(struct template *, const char *); int tp_writef(struct template *, const char *, ...) __attribute__((__format__ (printf, 2, 3))); int tp_urlescape(struct template *, const char *); int tp_htmlescape(struct template *, const char *); int tp_write_htmlescape(struct template *, const char *, size_t); struct template *template(void *, tmpl_write, char *, size_t); int template_flush(struct template *); void template_free(struct template *); #endif got-portable-0.119/template/Makefile.in0000664000175000017500000006162315066537205013507 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : noinst_PROGRAMS = template$(EXEEXT) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = Makefile.common CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) LIBOBJDIR = ../compat/ am__dirstamp = $(am__leading_dot)dirstamp am_template_OBJECTS = template.$(OBJEXT) parse.$(OBJEXT) template_OBJECTS = $(am_template_OBJECTS) template_LDADD = $(LDADD) template_DEPENDENCIES = $(LIBOBJS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ../compat/$(DEPDIR)/asprintf.Po \ ../compat/$(DEPDIR)/err.Po ../compat/$(DEPDIR)/getprogname.Po \ ../compat/$(DEPDIR)/reallocarray.Po ./$(DEPDIR)/parse.Po \ ./$(DEPDIR)/template.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/ylwrap SOURCES = $(template_SOURCES) DIST_SOURCES = $(template_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(srcdir)/Makefile.common.in $(srcdir)/Makefile.in \ $(top_srcdir)/../compat/asprintf.c \ $(top_srcdir)/../compat/err.c \ $(top_srcdir)/../compat/getprogname.c \ $(top_srcdir)/../compat/reallocarray.c compile depcomp \ install-sh missing parse.c ylwrap DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -700 -exec chmod u+rwx {} ';' \ ; rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = -9 DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = \ find . \( -type f -a \! \ \( -name .nfs* -o -name .smb* -o -name .__afs* \) \) -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ HOSTCC = @HOSTCC@ HOSTCFLAGS = @HOSTCFLAGS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ template_SOURCES = template.c \ parse.y EXTRA_DIST = got_compat.h LDADD = $(LIBOBJS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): Makefile.common: $(top_builddir)/config.status $(srcdir)/Makefile.common.in cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstPROGRAMS: -$(am__rm_f) $(noinst_PROGRAMS) ../compat/$(am__dirstamp): @$(MKDIR_P) ../compat/ @: >>../compat/$(am__dirstamp) ../compat/asprintf.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/err.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/getprogname.$(OBJEXT): ../compat/$(am__dirstamp) ../compat/reallocarray.$(OBJEXT): ../compat/$(am__dirstamp) template$(EXEEXT): $(template_OBJECTS) $(template_DEPENDENCIES) $(EXTRA_template_DEPENDENCIES) @rm -f template$(EXEEXT) $(AM_V_CCLD)$(LINK) $(template_OBJECTS) $(template_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/asprintf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/err.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/getprogname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@../compat/$(DEPDIR)/reallocarray.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/template.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) $(AM_V_at)$(MKDIR_P) "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -$(am__rm_f) ../compat/asprintf.$(OBJEXT) -$(am__rm_f) ../compat/err.$(OBJEXT) -$(am__rm_f) ../compat/getprogname.$(OBJEXT) -$(am__rm_f) ../compat/reallocarray.$(OBJEXT) clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) ../compat/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -$(am__rm_f) parse.c clean: clean-am clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f ../compat/$(DEPDIR)/asprintf.Po -rm -f ../compat/$(DEPDIR)/err.Po -rm -f ../compat/$(DEPDIR)/getprogname.Po -rm -f ../compat/$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/template.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f ../compat/$(DEPDIR)/asprintf.Po -rm -f ../compat/$(DEPDIR)/err.Po -rm -f ../compat/$(DEPDIR)/getprogname.Po -rm -f ../compat/$(DEPDIR)/reallocarray.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/template.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles am--refresh check \ check-am clean clean-cscope clean-generic clean-noinstPROGRAMS \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ dist-zstd distcheck distclean distclean-compile \ distclean-generic distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/cvg/0000775000175000017500000000000015066537276010466 5got-portable-0.119/cvg/Makefile.am0000664000175000017500000000452315066536113012433 sbin_PROGRAMS = cvg include $(top_builddir)/Makefile.common cvg_SOURCES = cvg.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_cvg.c \ $(top_srcdir)/lib/worktree_open.c cvg_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = cvg.1 man1_MANS = cvg.1 LDADD = -L$(top_builddir)/compat \ -lopenbsd-compat -lm LDADD += $(libbsd_LIBS) \ $(zlib_LIBS) \ $(libuuid_LIBS) \ $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/cvg/cvg.10000664000175000017500000020026715066535721011247 .\" .\" Copyright (c) 2017 Martin Pieuchot .\" Copyright (c) 2018, 2019, 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt CVG 1 .Os .Sh NAME .Nm cvg .Nd CVS-like Git client .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Sh DESCRIPTION .Nm is a Git-compatible version control system with a user interface similar to .Xr cvs 1 . .Pp .Nm supports local and remote Git repositories. The Git repository format is described in .Xr git-repository 5 . .Pp Files managed by .Nm must be checked out from the repository for modification. Checked out files are stored in a .Em work tree which can be placed at an arbitrary directory in the filesystem hierarchy. The on-disk format of this work tree is described in .Xr cvg-worktree 5 . .Pp .Nm provides global and command-specific options. Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information and exit immediately. .It Fl V , -version Display program version and exit immediately. .El .Pp The commands for .Nm are as follows: .Bl -tag -width checkout .Tg im .It Xo .Cm import .Op Fl b Ar branch .Op Fl I Ar pattern .Op Fl m Ar message .Op Fl r Ar repository-path .Ar directory .Xc .Dl Pq alias: Cm im Create an initial commit in a repository from the file hierarchy within the specified .Ar directory . The created commit will not have any parent commits, i.e. it will be a root commit. Also create a new reference which provides a branch name for the newly created commit. Show the path of each imported file to indicate progress. .Pp The .Cm got import command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got import are as follows: .Bl -tag -width Ds .It Fl b Ar branch Create the specified .Ar branch . If this option is not specified, a branch corresponding to the repository's HEAD reference will be used. Use of this option is required if the branch resolved via the repository's HEAD reference already exists. .It Fl I Ar pattern Ignore files or directories with a name which matches the specified .Ar pattern . This option may be specified multiple times to build a list of ignore patterns. The .Ar pattern follows the globbing rules documented in .Xr glob 7 . Ignore patterns which end with a slash, .Dq / , will only match directories. .It Fl m Ar message Use the specified log message when creating the new commit. Without the .Fl m option, .Cm got import opens a temporary file in an editor where a log message can be written. Quitting the editor without saving the file will abort the import operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. .El .Tg cl .It Xo .Cm clone .Op Fl almqv .Op Fl b Ar branch .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Fl R Ar reference .Ar repository-URL .Op Ar directory .Xc .Dl Pq alias: Cm cl Clone a Git repository at the specified .Ar repository-URL into the specified .Ar directory . If no .Ar directory is specified, the directory name will be derived from the name of the cloned repository. .Cm got clone will refuse to run if the .Ar directory already exists. .Pp The .Ar repository-URL specifies a protocol scheme, a server hostname, an optional port number separated from the hostname by a colon, and a path to the repository on the server: .Lk scheme://hostname:port/path/to/repository .Pp The following protocol schemes are supported: .Bl -tag -width git+ssh .It git The Git protocol as implemented by the .Xr git-daemon 1 server. Use of this protocol is discouraged since it supports neither authentication nor encryption. .It git+ssh The Git protocol wrapped in an authenticated and encrypted .Xr ssh 1 tunnel. With this protocol the hostname may contain an embedded username for .Xr ssh 1 to use: .Mt user@hostname .It ssh Short alias for git+ssh. .El .Pp Objects in the cloned repository are stored in a pack file which is downloaded from the server. This pack file will then be indexed to facilitate access to the objects stored within. If any objects in the pack file are stored in deltified form, all deltas will be fully resolved in order to compute the ID of such objects. This can take some time. More details about the pack file format are documented in .Xr git-repository 5 . .Pp .Cm got clone creates a remote repository entry in the .Xr got.conf 5 and .Pa config files of the cloned repository to store the .Ar repository-url and any .Ar branch or .Ar reference arguments for future use by .Cm got fetch or .Xr git-fetch 1 . .Pp The options for .Cm got clone are as follows: .Bl -tag -width Ds .It Fl a Fetch all branches from the remote repository's .Dq refs/heads/ reference namespace and set .Cm fetch_all_branches in the cloned repository's .Xr got.conf 5 file for future use by .Cm got fetch . If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl b option. .It Fl b Ar branch Fetch the specified .Ar branch from the remote repository's .Dq refs/heads/ reference namespace. This option may be specified multiple times to build a list of branches to fetch. If the branch corresponding to the remote repository's HEAD reference is not in this list, the cloned repository's HEAD reference will be set to the first branch which was fetched. If this option is not specified, a branch resolved via the remote repository's HEAD reference will be fetched. Cannot be used together with the .Fl a option. .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl l List branches and tags available for fetching from the remote repository and exit immediately. Cannot be used together with any of the other options except .Fl q and .Fl v . .It Fl m Create the cloned repository as a mirror of the original repository. This is useful if the cloned repository will not be used to store locally created commits. .Pp The repository's .Xr got.conf 5 and .Pa config files will be set up with the .Dq mirror option enabled, such that .Cm got fetch or .Xr git-fetch 1 will write incoming changes directly to branches in the .Dq refs/heads/ reference namespace, rather than to branches in the .Dq refs/remotes/ namespace. This avoids the usual requirement of having to run .Cm got rebase or .Cm got merge after .Cm got fetch in order to make incoming changes appear on branches in the .Dq refs/heads/ namespace. But maintaining custom changes in the cloned repository becomes difficult since such changes will be at risk of being discarded whenever incoming changes are fetched. .It Fl q Suppress progress reporting output. The same option will be passed to .Xr ssh 1 if applicable. .It Fl R Ar reference In addition to the branches and tags that will be fetched, fetch an arbitrary .Ar reference from the remote repository's .Dq refs/ namespace. This option may be specified multiple times to build a list of additional references to fetch. The specified .Ar reference may either be a path to a specific reference, or a reference namespace which will cause all references in this namespace to be fetched. .Pp Each reference will be mapped into the cloned repository's .Dq refs/remotes/ namespace, unless the .Fl m option is used to mirror references directly into the cloned repository's .Dq refs/ namespace. .Pp .Cm got clone will refuse to fetch references from the remote repository's .Dq refs/remotes/ or .Dq refs/got/ namespace. .It Fl v Verbose mode. Causes .Cm got clone to print debugging messages to standard error output. This option will be passed to .Xr ssh 1 if applicable. Multiple -v options increase the verbosity. The maximum is 3. .El .Tg co .It Xo .Cm checkout .Op Fl Eq .Op Fl b Ar branch .Op Fl c Ar commit .Op Fl p Ar path-prefix .Ar repository-path .Op Ar work-tree-path .Xc .Dl Pq alias: Cm co Copy files from a repository into a new work tree. Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It A Ta new file was added .It E Ta file already exists in work tree's meta-data .El .Pp If the .Ar work tree path is not specified, either use the last component of .Ar repository path , or if a .Ar path prefix was specified use the last component of .Ar path prefix . .Pp The options for .Cm got checkout are as follows: .Bl -tag -width Ds .It Fl b Ar branch Check out files from a commit on the specified .Ar branch . If this option is not specified, a branch resolved via the repository's HEAD reference will be used. .It Fl c Ar commit Check out files from the specified .Ar commit on the selected branch. The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. If this option is not specified, the most recent commit on the selected branch will be used. .Pp If the specified .Ar commit is not contained in the selected branch, a different branch which contains this commit must be specified with the .Fl b option. If no such branch is known, a new branch must be created for this commit with .Cm got branch before .Cm got checkout can be used. Checking out work trees with an unknown branch is intentionally not supported. .It Fl E Proceed with the checkout operation even if the directory at .Ar work-tree-path is not empty. Existing files will be left intact. .It Fl p Ar path-prefix Restrict the work tree to a subset of the repository's tree hierarchy. Only files beneath the specified .Ar path-prefix will be checked out. .It Fl q Silence progress output. .El .Tg up .It Xo .Cm update .Op Fl q .Op Fl b Ar branch .Op Fl c Ar commit .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Ar path ... .Xc .Dl Pq alias: Cm up Update an existing work tree to a different .Ar commit . Change existing files in the work tree as necessary to match file contents of this commit. Preserve any local changes in the work tree and merge them with the incoming changes. .Pp Files which already contain merge conflicts will not be updated to avoid further complications. Such files will be updated when .Cm got update is run again after merge conflicts have been resolved. If the conflicting changes are no longer needed, affected files can be reverted with .Cm got revert before running .Cm got update again. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It U Ta file was updated and contained no local changes .It G Ta file was updated and local changes were merged cleanly .It C Ta file was updated and conflicts occurred during merge .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta versioned file is obstructed by a non-regular file .It ! Ta a missing versioned file was restored .It # Ta file was not updated because it contains merge conflicts .It ? Ta changes destined for an unversioned file were not merged .El .Pp If no .Ar path is specified, update the entire work tree. Otherwise, restrict the update operation to files at or within the specified paths. Each path is required to exist in the update operation's target commit. Files in the work tree outside specified paths will remain unchanged and will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. Specifying a .Ar path is incompatible with the .Fl b option. .Pp .Cm got update cannot update paths with staged changes. If changes have been staged with .Cm got stage , these changes must first be committed with .Cm got commit or unstaged with .Cm got unstage . .Pp The options for .Cm got update are as follows: .Bl -tag -width Ds .It Fl b Ar branch Switch the work tree's branch reference to the specified .Ar branch before updating the work tree. This option requires that all paths in the work tree are updated. .Pp As usual, any local changes in the work tree will be preserved. This can be useful when switching to a newly created branch in order to commit existing local changes to this branch. .Pp Any local changes must be dealt with separately in order to obtain a work tree with pristine file contents corresponding exactly to the specified .Ar branch . Such changes could first be committed to a different branch with .Cm got commit , or could be discarded with .Cm got revert . .It Fl c Ar commit Update the work tree to the specified .Ar commit . The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. If this option is not specified, the most recent commit on the work tree's branch will be used. .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl q Silence progress output. .El .Tg st .It Xo .Cm status .Op Fl I .Op Fl S Ar status-codes .Op Fl s Ar status-codes .Op Ar path ... .Xc .Dl Pq alias: Cm st Show the current modification status of files in a work tree, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It D Ta file scheduled for deletion in next commit .It C Ta modified or added file which contains merge conflicts .It ! Ta versioned file was expected on disk but is missing .It \(a~ Ta versioned file is obstructed by a non-regular file .It ? Ta unversioned item not tracked by .Nm .It m Ta modified file modes (executable bit only) .It N Ta non-existent .Ar path specified on the command line .El .Pp If no .Ar path is specified, show modifications in the entire work tree. Otherwise, show modifications at or within the specified paths. .Pp If changes have been staged with .Cm got stage , staged changes are shown in the second output column, using the following status codes: .Bl -column YXZ description .It M Ta file modification is staged .It A Ta file addition is staged .It D Ta file deletion is staged .El .Pp Changes created on top of staged changes are indicated in the first column: .Bl -column YXZ description .It MM Ta file was modified after earlier changes have been staged .It MA Ta file was modified after having been staged for addition .El .Pp The options for .Cm got status are as follows: .Bl -tag -width Ds .It Fl I Show unversioned files even if they match an ignore pattern. See .Sx Ignore Patterns . .It Fl S Ar status-codes Suppress the output of files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl s option. .It Fl s Ar status-codes Only show files with a modification status matching any of the single-character status codes contained in the .Ar status-codes argument. Any combination of codes from the above list of possible status codes may be specified. For staged files, status codes displayed in either column will be matched. Cannot be used together with the .Fl S option. .El .It Xo .Cm log .Op Fl bdPpRs .Op Fl C Ar number .Op Fl c Ar commit .Op Fl l Ar N .Op Fl r Ar repository-path .Op Fl S Ar search-pattern .Op Fl x Ar commit .Op Ar path .Xc Display history of a repository. If a .Ar path is specified, show only commits which modified this path. If invoked in a work tree, the .Ar path is interpreted relative to the current working directory, and the work tree's path prefix is implicitly prepended. Otherwise, the path is interpreted relative to the repository root. .Pp The options for .Cm got log are as follows: .Bl -tag -width Ds .It Fl b Display individual commits which were merged into the current branch from other branches. By default, .Cm got log shows the linear history of the current branch only. .It Fl C Ar number Set the number of context lines shown in diffs with .Fl p . By default, 3 lines of context are shown. .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. If this option is not specified, default to the work tree's current branch if invoked in a work tree, or to the repository's HEAD reference. .It Fl d Display diffstat of changes introduced in each commit. Cannot be used with the .Fl s option. .It Fl l Ar N Limit history traversal to a given number of commits. If this option is not specified, a default limit value of zero is used, which is treated as an unbounded limit. The .Ev GOT_LOG_DEFAULT_LIMIT environment variable may be set to change this default value. .It Fl P Display the list of file paths changed in each commit, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Cannot be used with the .Fl s option. .It Fl p Display the patch of modifications made in each commit. If a .Ar path is specified, only show the patch of modifications at or within this path. Cannot be used with the .Fl s option. .It Fl R Determine a set of commits to display as usual, but display these commits in reverse order. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl S Ar search-pattern If specified, show only commits with a log message, author name, committer name, or commit ID matched by the extended regular expression .Ar search-pattern . Lines in committed patches will be matched if .Fl p is specified. File paths changed by a commit will be matched if .Fl P is specified. Regular expression syntax is documented in .Xr re_format 7 . .It Fl s Display a short one-line summary of each commit, instead of the default history format. Cannot be used together with the .Fl p or .Fl P option. .It Fl x Ar commit Stop traversing commit history immediately after the specified .Ar commit has been traversed. This option has no effect if the specified .Ar commit is never traversed. .El .Tg di .It Xo .Cm diff .Op Fl adPsw .Op Fl C Ar number .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar object1 Ar object2 | Ar path ... .Xc .Dl Pq alias: Cm di When invoked within a work tree without any arguments, display all local changes in the work tree. If one or more .Ar path arguments are specified, only show changes within the specified paths. .Pp If two arguments are provided, treat each argument as a reference, a tag name, or an object ID, and display differences between the corresponding objects. Both objects must be of the same type (blobs, trees, or commits). An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. If none of these interpretations produce a valid result or if the .Fl P option is used, and if .Cm got diff is running in a work tree, attempt to interpret the two arguments as paths. .Pp The options for .Cm got diff are as follows: .Bl -tag -width Ds .It Fl a Treat file contents as ASCII text even if binary data is detected. .It Fl C Ar number Set the number of context lines shown in the diff. By default, 3 lines of context are shown. .It Fl c Ar commit Show differences between commits in the repository. This option may be used up to two times. When used only once, show differences between the specified .Ar commit and its first parent commit. When used twice, show differences between the two specified commits. .Pp The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .Pp If the .Fl c option is used, all non-option arguments will be interpreted as paths. If one or more such .Ar path arguments are provided, only show differences for the specified paths. .Pp Cannot be used together with the .Fl P option. .It Fl d Display diffstat of changes before the actual diff by annotating each file path or blob hash being diffed with the total number of lines added and removed. A summary line will display the total number of changes across all files. .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Show changes staged with .Cm got stage instead of showing local changes in the work tree. This option is only valid when .Cm got diff is invoked in a work tree. .It Fl w Ignore whitespace-only changes. .El .Tg bl .It Xo .Cm blame .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar path .Xc .Dl Pq alias: Cm bl Display line-by-line history of a file at the specified path. .Pp The options for .Cm got blame are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .Tg tr .It Xo .Cm tree .Op Fl iR .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc .Dl Pq alias: Cm tr Display a listing of files and directories at the specified directory path in the repository. Entries shown in this listing may carry one of the following trailing annotations: .Bl -column YXZ description .It @ Ta entry is a symbolic link .It / Ta entry is a directory .It * Ta entry is an executable file .It $ Ta entry is a Git submodule .El .Pp Symbolic link entries are also annotated with the target path of the link. .Pp If no .Ar path is specified, list the repository path corresponding to the current directory of the work tree, or the root directory of the repository if there is no work tree. .Pp The options for .Cm got tree are as follows: .Bl -tag -width Ds .It Fl c Ar commit List files and directories as they appear in the specified .Ar commit . The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .It Fl i Show object IDs of files (blob objects) and directories (tree objects). .It Fl R Recurse into sub-directories in the repository. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Xo .Cm tag .Op Fl lVv .Op Fl c Ar commit .Op Fl m Ar message .Op Fl r Ar repository-path .Op Fl s Ar signer-id .Ar name .Xc Manage tags in a repository. .Pp Tags are managed via references which live in the .Dq refs/tags/ reference namespace. The .Cm got tag command operates on references in this namespace only. References in this namespace point at tag objects which contain a pointer to another object, a tag message, as well as author and timestamp information. .Pp Attempt to create a tag with the given .Ar name , and make this tag point at the given .Ar commit . If no commit is specified, default to the latest commit on the work tree's current branch if invoked in a work tree, and to a commit resolved via the repository's HEAD reference otherwise. .Pp The options for .Cm got tag are as follows: .Bl -tag -width Ds .It Fl c Ar commit Make the newly created tag reference point at the specified .Ar commit . The expected .Ar commit argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .It Fl l List all existing tags in the repository instead of creating a new tag. If a .Ar name argument is passed, show only the tag with the given .Ar name . .It Fl m Ar message Use the specified tag message when creating the new tag. Without the .Fl m option, .Cm got tag opens a temporary file in an editor where a tag message can be written. Quitting the editor without saving the file will abort the tag operation. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .It Fl s Ar signer-id While creating a new tag, sign this tag with the identity given in .Ar signer-id . .Pp For SSH-based signatures, .Ar signer-id is the path to a file which may refer to either a private SSH key, or a public SSH key with the private half available via .Xr ssh-agent 1 . .Cm got tag will sign the tag object by invoking .Xr ssh-keygen 1 with the .Fl Y Cm sign command, using the signature namespace .Dq git for compatibility with .Xr git 1 . .It Fl V Verify tag object signatures. If a .Ar name is specified, show and verify the tag object with the provided name. Otherwise, list all tag objects and verify signatures where present. .Pp .Cm got tag verifies SSH-based signatures by invoking .Xr ssh-keygen 1 with the options .Fl Y Cm verify Fl f Ar allowed_signers . A path to the .Ar allowed_signers file must be set in .Xr got.conf 5 , otherwise verification is impossible. .It Fl v Verbose mode. During SSH signature creation and verification this option will be passed to .Xr ssh-keygen 1 . Multiple -v options increase the verbosity. The maximum is 3. .El .Pp By design, the .Cm got tag command will not delete tags or change existing tags. If a tag must be deleted, the .Cm got ref command may be used to delete a tag's reference. This should only be done if the tag has not already been copied to another repository. .It Xo .Cm add .Op Fl IR .Ar path ... .Xc Schedule unversioned files in a work tree for addition to the repository in the next commit. By default, files which match an ignore pattern will not be added. See .Sx Ignore Patterns . .Pp If a .Ar path mentioned in the command line is not an unversioned file then .Cm got add may raise an error. To avoid unnecessary errors from paths picked up by file globbing patterns in the shell, paths in the argument list will be silently ignored if they are not reported by .Cm got status at all, or if they are reported with one of the following status codes and do not have changes staged via .Cm got stage : .Bl -column YXZ description .It M Ta modified file .It A Ta file scheduled for addition in next commit .It C Ta modified or added file which contains merge conflicts .It m Ta modified file modes (executable bit only) .El .Pp The options for .Cm got add are as follows: .Bl -tag -width Ds .It Fl I Add files even if they match an ignore pattern. See .Xs Ignore Patterns . .It Fl R Permit recursion into directories. If this option is not specified, .Cm got add will refuse to run if a specified .Ar path is a directory. .El .Tg rm .It Xo .Cm remove .Op Fl fkR .Op Fl s Ar status-codes .Ar path ... .Xc .Dl Pq alias: Cm rm Remove versioned files from a work tree and schedule them for deletion from the repository in the next commit. .Pp The options for .Cm got remove are as follows: .Bl -tag -width Ds .It Fl f Perform the operation even if a file contains local modifications, and do not raise an error if a specified .Ar path does not exist on disk. .It Fl k Keep affected files on disk. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got remove will refuse to run if a specified .Ar path is a directory. .It Fl s Ar status-codes Only delete files with a modification status matching one of the single-character status codes contained in the .Ar status-codes argument. The following status codes may be specified: .Bl -column YXZ description .It M Ta modified file (this implies the .Fl f option) .It ! Ta versioned file expected on disk but missing .El .El .Tg pa .It Xo .Cm patch .Op Fl nR .Op Fl c Ar commit .Op Fl p Ar strip-count .Op Ar patchfile .Xc .Dl Pq alias: Cm pa Apply changes from .Ar patchfile to files in a work tree. Files added or removed by a patch will be scheduled for addition or removal in the work tree. .Pp The patch must be in the unified diff format as produced by .Cm got diff , .Xr git-diff 1 , or by .Xr diff 1 and .Xr cvs 1 diff when invoked with their .Fl u options. If no .Ar patchfile argument is provided, read unified diff data from standard input instead. .Pp If the .Ar patchfile contains multiple patches, then attempt to apply each of them in sequence. .Pp Show the status of each affected file, using the following status codes: .Bl -column XYZ description .It M Ta file was modified .It G Ta file was merged using a merge-base found in the repository .It C Ta file was merged and conflicts occurred during merge .It D Ta file was deleted .It A Ta file was added .It # Ta failed to patch the file .El .Pp If a change does not match at its exact line number, attempt to apply it somewhere else in the file if a good spot can be found. Otherwise, the patch will fail to apply. .Pp .Nm .Cm patch will refuse to apply a patch if certain preconditions are not met. Files to be deleted must already be under version control, and must not have been scheduled for deletion already. Files to be added must not yet be under version control and must not already be present on disk. Files to be modified must already be under version control and may not contain conflict markers. .Pp If an error occurs, the .Cm patch operation will be aborted. Any changes made to the work tree up to this point will be left behind. Such changes can be viewed with .Cm got diff and can be reverted with .Cm got revert if needed. .Pp The options for .Cm got patch are as follows: .Bl -tag -width Ds .It Fl c Ar commit Attempt to locate files within the specified .Ar commit for use as a merge-base for 3-way merges. Ideally, the specified .Ar commit should contain versions of files which the changes contained in the .Ar patchfile were based on. Files will be located by path, relative to the repository root. If the .Fl p option is used then leading path components will be stripped before paths are looked up in the repository. .Pp If the .Fl c option is not used then .Cm got patch will attempt to locate merge-bases via object IDs found in .Ar patchfile meta-data, such as produced by .Cm got diff or .Xr git-diff 1 . Use of the .Fl c option is only recommended in the absence of such meta-data. .Pp In case no merge-base is available for a file, changes will be applied without doing a 3-way merge. Changes which do not apply cleanly may then be rejected entirely, rather than producing merge conflicts in the patched target file. .It Fl n Do not make any modifications to the work tree. This can be used to check whether a patch would apply without issues. If the .Ar patchfile contains diffs that affect the same file multiple times, the results displayed may be incorrect. .It Fl p Ar strip-count Specify the number of leading path components to strip from paths parsed from .Ar patchfile . If the .Fl p option is not used, .Sq a/ and .Sq b/ path prefixes generated by .Xr git-diff 1 will be recognized and stripped automatically. .It Fl R Reverse the patch before applying it. .El .Tg rv .It Xo .Cm revert .Op Fl pR .Op Fl F Ar response-script .Ar path ... .Xc .Dl Pq alias: Cm rv Revert any local changes in files at the specified paths in a work tree. File contents will be overwritten with those contained in the work tree's base commit. There is no way to bring discarded changes back after .Cm got revert ! .Pp If a file was added with .Cm got add , it will become an unversioned file again. If a file was deleted with .Cm got remove , it will be restored. .Pp The options for .Cm got revert are as follows: .Bl -tag -width Ds .It Fl F Ar response-script With the .Fl p option, read .Dq y , .Dq n , and .Dq q responses line-by-line from the specified .Ar response-script file instead of prompting interactively. .It Fl p Instead of reverting all changes in files, interactively select or reject changes to revert based on .Dq y (revert change), .Dq n (keep change), and .Dq q (quit reverting this file) responses. If a file is in modified status, individual patches derived from the modified file content can be reverted. Files in added or deleted status may only be reverted in their entirety. .It Fl R Permit recursion into directories. If this option is not specified, .Cm got revert will refuse to run if a specified .Ar path is a directory. .El .Tg ci .It Xo .Cm commit .Op Fl CNnS .Op Fl A Ar author .Op Fl F Ar path .Op Fl i Ar identity-file .Op Fl J Ar jumphost .Op Fl m Ar message .Op Ar path ... .Xc .Dl Pq alias: Cm ci Create a new commit in the repository from changes in a work tree and use this commit as the new base commit for the work tree. If no .Ar path is specified, commit all changes in the work tree. Otherwise, commit changes at or within the specified paths. .Pp If changes have been explicitly staged for commit with .Cm got stage , only commit staged changes and reject any specified paths which have not been staged. .Pp .Cm got commit opens a temporary file in an editor where a log message can be written unless the .Fl m option is used or the .Fl F and .Fl N options are used together. Quitting the editor without saving the file will abort the commit operation. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It M Ta modified file .It D Ta file was deleted .It A Ta new file was added .It m Ta modified file modes (executable bit only) .El .Pp Files which are not part of the new commit will retain their previously recorded base commit. Some .Nm commands may refuse to run while the work tree contains files from multiple base commits. The base commit of such a work tree can be made consistent by running .Cm got update across the entire work tree. .Pp The .Cm got commit command requires the .Ev GOT_AUTHOR environment variable to be set, unless an author has been configured in .Xr got.conf 5 or Git's .Dv user.name and .Dv user.email configuration settings can be obtained from the repository's .Pa .git/config file or from Git's global .Pa ~/.gitconfig configuration file. .Pp The options for .Cm got commit are as follows: .Bl -tag -width Ds .It Fl A Ar author Set author information in the newly created commit to .Ar author . This is useful when committing changes on behalf of someone else. The .Ar author argument must use the same format as the .Ev GOT_AUTHOR environment variable. .Pp In addition to storing author information, the newly created commit object will retain .Dq committer information which is obtained, as usual, from the .Ev GOT_AUTHOR environment variable, or .Xr got.conf 5 , or Git configuration settings. .It Fl C Allow committing files in conflicted status. .Pp Committing files with conflict markers should generally be avoided. Cases where conflict markers must be stored in the repository for some legitimate reason should be very rare. There are usually ways to avoid storing conflict markers verbatim by applying appropriate programming tricks. .It Fl F Ar path Use the prepared log message stored in the file found at .Ar path when creating the new commit. .Cm got commit opens a temporary file in an editor where the prepared log message can be reviewed and edited further if needed. Cannot be used together with the .Fl m option. .It Fl m Ar message Use the specified log message when creating the new commit. Cannot be used together with the .Fl F option. .It Fl i Ar identity-file Specify an .Ar identity-file , containing a private SSH key, to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl J Ar jumphost Specify a .Ar jumphost to use with SSH connections. The same option will be passed to .Xr ssh 1 . .It Fl N This option prevents .Cm got commit from opening the commit message in an editor. It has no effect unless it is used together with the .Fl F option and is intended for non-interactive use such as scripting. .It Fl n This option prevents .Cm got commit from generating a diff of the to-be-committed changes in a temporary file which can be viewed while editing a commit message. .It Fl S Allow the addition of symbolic links which point outside of the path space that is under version control. By default, .Cm got commit will reject such symbolic links due to safety concerns. As a precaution, .Nm may decide to represent such a symbolic link as a regular file which contains the link's target path, rather than creating an actual symbolic link which points outside of the work tree. Use of this option is discouraged because external mechanisms such as .Dq make obj are better suited for managing symbolic links to paths not under version control. .El .Pp .Cm got commit will refuse to run if certain preconditions are not met. If the work tree's current branch is not in the .Dq refs/heads/ reference namespace, new commits may not be created on this branch. Local changes may only be committed if they are based on file content found in the most recent commit on the work tree's branch. If a path is found to be out of date, .Cm got update must be used first in order to merge local changes with changes made in the repository. .Tg cy .It Xo .Cm cherrypick .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm cy Merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on a different branch than the work tree's base commit. The expected argument is a reference or a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got cherrypick commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got cherrypick creates a record of commits which have been merged into the work tree. When a file changed by .Cm got cherrypick is committed with .Cm got commit , the log messages of relevant merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for cherrypicking the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got cherrypick will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm cherrypick are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous cherrypick operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by cherrypick operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .Pp .Tg bo .It Xo .Cm backout .Op Fl lX .Op Ar commit .Xc .Dl Pq alias: Cm bo Reverse-merge changes from a single .Ar commit into the work tree. The specified .Ar commit should be on the same branch as the work tree's base commit. The expected argument is a reference or a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .Pp Show the status of each affected file, using the following status codes: .Bl -column YXZ description .It G Ta file was merged .It C Ta file was merged and conflicts occurred during merge .It ! Ta changes destined for a missing file were not merged .It D Ta file was deleted .It d Ta file's deletion was prevented by local modifications .It A Ta new file was added .It \(a~ Ta changes destined for a non-regular file were not merged .It ? Ta changes destined for an unversioned file were not merged .El .Pp The reverse-merged changes will appear as local changes in the work tree, which may be viewed with .Cm got diff , amended manually or with further .Cm got backout commands, committed with .Cm got commit . .Pp If invoked in a work tree where no .Cm rebase , .Cm histedit , or .Cm merge operation is taking place, .Cm got backout creates a record of commits which have been reverse-merged into the work tree. When a file changed by .Cm got backout is committed with .Cm got commit , the log messages of relevant reverse-merged commits will then appear in the editor, where the messages should be further adjusted to convey the reasons for backing out the changes. Upon exiting the editor, if the time stamp of the log message file is unchanged or the log message is empty, .Cm got commit will fail with an unmodified or empty log message error. .Pp If all the changes in all files touched by a given commit are discarded, e.g. with .Cm got revert , this commit's log message record will also disappear. .Pp .Cm got backout will refuse to run if certain preconditions are not met. If the work tree contains multiple base commits, it must first be updated to a single base commit with .Cm got update . If any relevant files already contain merge conflicts, these conflicts must be resolved first. .Pp The options for .Nm .Cm backout are as follows: .Bl -tag -width Ds .It Fl l Display a list of commit log messages recorded by backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only show the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be displayed. Otherwise, all commit log messages will be displayed irrespective of the work tree in which they were created. This option cannot be used with .Fl X . .It Fl X Delete log messages created by previous backout operations, represented by references in the .Dq refs/got/worktree reference namespace. If a .Ar commit is specified, only delete the log message of the specified commit. .Pp If invoked in a work tree, only log messages recorded by backout operations in the current work tree will be deleted. Otherwise, all commit log messages will be deleted irrespective of the work tree in which they were created. This option cannot be used with .Fl l . .El .It Xo .Cm cat .Op Fl P .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar arg ... .Xc Parse and print contents of objects to standard output in a line-based text format. Content of commit, tree, and tag objects is printed in a way similar to the actual content stored in such objects. Blob object contents are printed as they would appear in files on disk. .Pp Attempt to interpret each argument as a reference, a tag name, or an object ID. References will be resolved to an object ID. Tag names will resolved to a tag object. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .Pp If none of the above interpretations produce a valid result, or if the .Fl P option is used, attempt to interpret the argument as a path which will be resolved to the ID of an object found at this path in the repository. .Pp The options for .Cm got cat are as follows: .Bl -tag -width Ds .It Fl c Ar commit Look up paths in the specified .Ar commit . If this option is not used, paths are looked up in the commit resolved via the repository's HEAD reference. The expected argument is a commit ID or an existing reference or tag name which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a commit ID automatically, provided the abbreviation is unique. .It Fl P Interpret all arguments as paths only. This option can be used to resolve ambiguity in cases where paths look like tag names, reference names, or object IDs. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. .El .It Cm info Op Ar path ... Display meta-data stored in a work tree. See .Xr got-worktree 5 for details. .Pp The work tree to use is resolved implicitly by walking upwards from the current working directory. .Pp If one or more .Ar path arguments are specified, show additional per-file information for tracked files located at or within these paths. If a .Ar path argument corresponds to the work tree's root directory, display information for all tracked files. .El .Tg ignore .Ss Ignore Patterns .Cm cvg status and .Cm add read patterns from .Pa .cvsignore and .Pa .gitignore files in each traversed directory and will not display or add unversioned files which match these patterns. The patterns are matched according to .Xr glob 7 rules, with extensions to improve compatibility with .Xr cvs 1 and .Xr git 1 . Patterns from each .Pa .cvsignore or .Pa .gitignore file are matched relative to the directory containing that file. If a pattern begins with two asterisks followed by a slash, .Dq **/ , the remainder of the pattern will match at any directory at or below the directory containing .Pa .cvsignore or .Pa gitignore file. Two asterisks surrounded by slashes, .Dq /**/ , in the middle of a pattern will match one directory or more. Patterns which end with a slash, .Dq / , will only match directories, and any paths below matching directories will be ignored. .Pp Unlike .Xr cvs 1 , .Nm only supports a single ignore pattern per line. Unlike .Xr git 1 , .Nm does not support negated ignore patterns prefixed with .Dq \&! , and does not match patterns at arbitrary depth relative to the .Pa .gitignore file unless they begin with .Dq **/ . For better .Xr git 1 compatibility, patterns beginning with a slash are matched as if the slash were not present. .Sh ENVIRONMENT .Bl -tag -width GOT_IGNORE_GITCONFIG .It Ev GOT_AUTHOR The author's name and email address, such as .Dq An Flan Hacker Aq Mt flan_hacker@openbsd.org . Used by the .Cm got commit , .Cm got import , .Cm got rebase , .Cm got merge , and .Cm got histedit commands. Because .Xr git 1 may fail to parse commits without an email address in author data, .Nm attempts to reject .Ev GOT_AUTHOR environment variables with a missing email address. .Pp .Ev GOT_AUTHOR will be overridden by configuration settings in .Xr got.conf 5 or by Git's .Dv user.name and .Dv user.email configuration settings in the repository's .Pa .git/config file. The .Dv user.name and .Dv user.email configuration settings contained in Git's global .Pa ~/.gitconfig configuration file will only be used if neither .Xr got.conf 5 nor the .Ev GOT_AUTHOR environment variable provide author information. .It Ev GOT_IGNORE_GITCONFIG If this variable is set then any remote repository definitions or author information found in Git configuration files will be ignored. .It Ev GOT_LOG_DEFAULT_LIMIT The default limit on the number of commits traversed by .Cm got log . If set to zero, the limit is unbounded. This variable will be silently ignored if it is set to a non-numeric value. .It Ev VISUAL , EDITOR The editor spawned by .Cm got commit , .Cm got histedit , .Cm got import , or .Cm got tag . If not set, the .Xr vi 1 text editor will be spawned. .El .Sh FILES .Bl -tag -width packed-refs -compact .It Pa got.conf Repository-wide configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file located in the root directory of a Git repository supersedes any relevant settings in Git's .Pa config file. .Pp .It Pa .cvg/got.conf Worktree-specific configuration settings for .Nm . If present, a .Xr got.conf 5 configuration file in the .Pa .cvg meta-data directory of a work tree supersedes any relevant settings in the repository's .Xr got.conf 5 configuration file and Git's .Pa config file. .El .Sh EXIT STATUS .Ex -std got .Sh EXAMPLES Enable tab-completion of .Nm command names in .Xr ksh 1 : .Pp .Dl $ set -A complete_got_1 -- $(got -h 2>&1 | sed -n s/commands://p) .Pp Clone an existing Git repository for use with .Nm : .Pp .Dl $ cd /var/git/ .Dl $ got clone ssh://git@github.com/openbsd/src.git .Pp Unfortunately, many of the popular Git hosting sites do not offer anonymous access via SSH. Such sites will require an account to be created, and a public SSH key to be uploaded to this account, before repository access via ssh:// URLs will work. .Pp Use of HTTP URLs currently requires .Xr git 1 : .Pp .Dl $ cd /var/git/ .Dl $ git clone --bare https://github.com/openbsd/src.git .Pp Alternatively, for quick and dirty local testing of .Nm a new Git repository could be created and populated with files, e.g. from a temporary CVS checkout located at .Pa /tmp/src : .Pp .Dl $ gotadmin init /var/git/src.git .Dl $ got import -r /var/git/src.git -I CVS -I obj /tmp/src .Pp Check out a work tree from the Git repository to /usr/src: .Pp .Dl $ got checkout /var/git/src.git /usr/src .Pp View local changes in a work tree directory: .Pp .Dl $ got diff | less .Pp In a work tree, display files in a potentially problematic state: .Pp .Dl $ got status -s 'C!~?' .Pp Interactively revert selected local changes in a work tree directory: .Pp .Dl $ got revert -p -R\ . .Pp In a work tree or a git repository directory, list all branch references: .Pp .Dl $ got branch -l .Pp As above, but list the most recently modified branches only: .Pp .Dl $ got branch -lt | head .Pp In a work tree or a git repository directory, create a new branch called .Dq unified-buffer-cache which is forked off the .Dq master branch: .Pp .Dl $ got branch -c master unified-buffer-cache .Pp Switch an existing work tree to the branch .Dq unified-buffer-cache . Local changes in the work tree will be preserved and merged if necessary: .Pp .Dl $ got update -b unified-buffer-cache .Pp Create a new commit from local changes in a work tree directory. This new commit will become the head commit of the work tree's current branch: .Pp .Dl $ got commit .Pp In a work tree or a git repository directory, view changes committed in the 3 most recent commits to the work tree's branch, or the branch resolved via the repository's HEAD reference, respectively: .Pp .Dl $ got log -p -l 3 .Pp As above, but display changes in the order in which .Xr patch 1 could apply them in sequence: .Pp .Dl $ got log -p -l 3 -R .Pp In a work tree or a git repository directory, log the history of a subdirectory: .Pp .Dl $ got log sys/uvm .Pp While operating inside a work tree, paths are specified relative to the current working directory, so this command will log the subdirectory .Pa sys/uvm : .Pp .Dl $ cd sys/uvm && got log\ . .Pp And this command has the same effect: .Pp .Dl $ cd sys/dev/usb && got log ../../uvm .Pp And this command displays work tree meta-data about all tracked files: .Pp .Dl $ cd /usr/src .Dl $ got info\ . | less .Pp Add new files and remove obsolete files in a work tree directory: .Pp .Dl $ got add sys/uvm/uvm_ubc.c .Dl $ got remove sys/uvm/uvm_vnode.c .Pp Create a new commit from local changes in a work tree directory with a pre-defined log message. .Pp .Dl $ got commit -m 'unify the buffer cache' .Pp Alternatively, create a new commit from local changes in a work tree directory with a log message that has been prepared in the file .Pa /tmp/msg : .Pp .Dl $ got commit -F /tmp/msg .Pp Update any work tree checked out from the .Dq unified-buffer-cache branch to the latest commit on this branch: .Pp .Dl $ got update .Pp Roll file content on the unified-buffer-cache branch back by one commit, and then fetch the rolled-back change into the work tree as a local change to be amended and perhaps committed again: .Pp .Dl $ got backout unified-buffer-cache .Dl $ got commit -m 'roll back previous' .Dl $ # now back out the previous backout :-) .Dl $ got backout unified-buffer-cache .Pp Fetch new changes on the remote repository's .Dq master branch, making them visible on the local repository's .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got fetch .Pp In a repository created with a HTTP URL and .Cm git clone --bare the .Xr git-fetch 1 command must be used instead: .Pp .Dl $ cd /var/git/src.git .Dl $ git fetch origin master:refs/remotes/origin/master .Pp Rebase the local .Dq master branch to merge the new changes that are now visible on the .Dq origin/master branch: .Pp .Dl $ cd /usr/src .Dl $ got update -b origin/master .Dl $ got rebase master .Pp Rebase the .Dq unified-buffer-cache branch on top of the new head commit of the .Dq master branch. .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Create a patch from all changes on the unified-buffer-cache branch. The patch can be mailed out for review and applied to .Ox Ns 's CVS tree: .Pp .Dl $ got diff master unified-buffer-cache > /tmp/ubc.diff .Pp Edit the entire commit history of the .Dq unified-buffer-cache branch: .Pp .Dl $ got update -b unified-buffer-cache .Dl $ got update -c master .Dl $ got histedit .Pp Before working against existing branches in a repository cloned with .Cm git clone --bare instead of .Cm got clone , a Git .Dq refspec must be configured to map all references in the remote repository into the .Dq refs/remotes namespace of the local repository. This can be achieved by setting Git's .Pa remote.origin.fetch configuration variable to the value .Dq +refs/heads/*:refs/remotes/origin/* with the .Cm git config command: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*' .Pp Additionally, the .Dq mirror option must be disabled: .Pp .Dl $ cd /var/git/repo .Dl $ git config remote.origin.mirror false .Pp Alternatively, the following .Xr git-fetch 1 configuration item can be added manually to the Git repository's .Pa config file: .Pp .Dl [remote \&"origin\&"] .Dl url = ... .Dl fetch = +refs/heads/*:refs/remotes/origin/* .Dl mirror = false .Pp This configuration leaves the local repository's .Dq refs/heads namespace free for use by local branches checked out with .Cm got checkout and, if needed, created with .Cm got branch . Branches in the .Dq refs/remotes/origin namespace can now be updated with incoming changes from the remote repository with .Cm got fetch or .Xr git-fetch 1 without extra command line arguments. Newly fetched changes can be examined with .Cm got log . .Pp Display changes on the remote repository's version of the .Dq master branch, as of the last time .Cm got fetch was run: .Pp .Dl $ got log -c origin/master | less .Pp As shown here, most commands accept abbreviated reference names such as .Dq origin/master instead of .Dq refs/remotes/origin/master . The latter is only needed in case of ambiguity. .Pp .Cm got rebase can be used to merge changes which are visible on the .Dq origin/master branch into the .Dq master branch. This will also merge local changes, if any, with the incoming changes: .Pp .Dl $ got update -b origin/master .Dl $ got rebase master .Pp In order to make changes committed to the .Dq unified-buffer-cache visible on the .Dq master branch, the .Dq unified-buffer-cache branch can be rebased onto the .Dq master branch: .Pp .Dl $ got update -b master .Dl $ got rebase unified-buffer-cache .Pp Changes on the .Dq unified-buffer-cache branch can now be made visible on the .Dq master branch with .Cm got integrate . Because the rebase operation switched the work tree to the .Dq unified-buffer-cache branch, the work tree must be switched back to the .Dq master branch first: .Pp .Dl $ got update -b master .Dl $ got integrate unified-buffer-cache .Pp On the .Dq master branch, log messages for local changes can now be amended with .Dq OK by other developers and any other important new information: .Pp .Dl $ got update -c origin/master .Dl $ got histedit -m .Pp If the remote repository offers write access, local changes on the .Dq master branch can be sent to the remote repository with .Cm got send . Usually, .Cm got send can be run without further arguments. The arguments shown here match defaults, provided the work tree's current branch is the .Dq master branch: .Pp .Dl $ got send -b master origin .Pp If the remote repository requires the HTTPS protocol, the .Xr git-push 1 command must be used instead: .Pp .Dl $ cd /var/git/src.git .Dl $ git push origin master .Pp When making contributions to projects which use the .Dq pull request workflow, SSH protocol repository access needs to be set up first. Once an account has been created on a Git hosting site it should be possible to upload a public SSH key for repository access authentication. .Pp The .Dq pull request workflow will usually involve two remote repositories. In the real-life example below, the .Dq origin repository was forked from the .Dq upstream repository by using the Git hosting site's web interface. The .Xr got.conf 5 file in the local repository describes both remote repositories: .Bd -literal -offset indent # Jelmers's repository, which accepts pull requests remote "upstream" { server git@github.com protocol ssh repository "/jelmer/dulwich" branch { "master" } } # Stefan's fork, used as the default remote repository remote "origin" { server git@github.com protocol ssh repository "/stspdotname/dulwich" branch { "master" } } .Ed .Pp With this configuration, Stefan can create commits on .Dq refs/heads/master and send them to the .Dq origin repository by running: .Pp .Dl $ got send -b master origin .Pp The changes can now be proposed to Jelmer by opening a pull request via the Git hosting site's web interface. If Jelmer requests further changes to be made, additional commits can be created on the .Dq master branch and be added to the pull request by running .Cd got send again. .Pp If Jelmer prefers additional commits to be .Dq squashed then the following commands can be used to achieve this: .Pp .Dl $ got update -b master .Dl $ got update -c origin/master .Dl $ got histedit -f .Dl $ got send -f -b master origin .Pp In addition to reviewing the pull request in the web user interface, Jelmer can fetch the pull request's branch into his local repository and create a local branch which contains the proposed changes: .Pp .Dl $ got fetch -R refs/pull/1046/head origin .Dl $ got branch -c refs/remotes/origin/pull/1046/head pr1046 .Pp Once Jelmer has accepted the pull request, Stefan can fetch the merged changes, and possibly several other new changes, by running: .Pp .Dl $ got fetch upstream .Pp The merged changes will now be visible under the reference .Dq refs/remotes/upstream/master . The local .Dq master branch can now be rebased on top of the latest changes from upstream: .Pp .Dl $ got update -b upstream/master .Dl $ got rebase master .Pp As an alternative to .Cm got rebase , branches can be merged with .Cm got merge : .Pp .Dl $ got update -b master .Dl $ got merge upstream/master .Pp The question of whether to rebase or merge branches is philosophical. When in doubt, refer to the software project's policies set by project maintainers. .Pp As a final step, the forked repository's copy of the master branch needs to be kept in sync by sending the new changes there: .Pp .Dl $ got send -f -b master origin .Pp If multiple pull requests need to be managed in parallel, a separate branch must be created for each pull request with .Cm got branch . Each such branch can then be used as above, in place of .Dq refs/heads/master . Changes for any accepted pull requests will still appear under .Dq refs/remotes/upstream/master, regardless of which branch was used in the forked repository to create a pull request. .Sh SEE ALSO .Xr gotadmin 1 , .Xr tog 1 , .Xr git-repository 5 , .Xr got-worktree 5 , .Xr got.conf 5 , .Xr gotwebd 8 .Sh AUTHORS .An Anthony J. Bentley Aq Mt bentley@openbsd.org .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Hiltjo Posthuma Aq Mt hiltjo@codemadness.org .An Josh Rickmar Aq Mt jrick@zettaport.com .An Joshua Stein Aq Mt jcs@openbsd.org .An Klemens Nanni Aq Mt kn@openbsd.org .An Martin Pieuchot Aq Mt mpi@openbsd.org .An Neels Hofmeyr Aq Mt neels@hofmeyr.de .An Omar Polo Aq Mt op@openbsd.org .An Ori Bernstein Aq Mt ori@openbsd.org .An Sebastien Marie Aq Mt semarie@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Steven McDonald Aq Mt steven@steven-mcdonald.id.au .An Theo Buehler Aq Mt tb@openbsd.org .An Thomas Adam Aq Mt thomas@xteddy.org .An Tracey Emery Aq Mt tracey@traceyemery.net .An Yang Zhong Aq Mt yzhong@freebsdfoundation.org .Pp Parts of .Nm , .Xr tog 1 , and .Xr gotwebd 8 were derived from code under copyright by: .Pp .An Caldera International .An Daniel Hartmeier .An Esben Norby .An Henning Brauer .An Håkan Olsson .An Ingo Schwarze .An Jean-Francois Brousseau .An Joris Vink .An Jyri J. Virkki .An Larry Wall .An Markus Friedl .An Niall O'Higgins .An Niklas Hallqvist .An Ray Lai .An Ryan McBride .An Theo de Raadt .An Todd C. Miller .An Xavier Santolaria .Pp .Nm contains code contributed to the public domain by .An Austin Appleby . .Sh CAVEATS .Nm is a work-in-progress and some features remain to be implemented. .Pp At present, the user has to fall back on .Xr git 1 to perform some tasks. In particular: .Bl -bullet .It Reading from remote repositories over HTTP or HTTPS protocols requires .Xr git-clone 1 and .Xr git-fetch 1 . .It Writing to remote repositories over HTTP or HTTPS protocols requires .Xr git-push 1 . .It The creation of merge commits with more than two parent commits requires .Xr git-merge 1 . .It In situations where files or directories were moved around .Cm got will not automatically merge changes to new locations and .Xr git 1 will usually produce better results. .El got-portable-0.119/cvg/cvg.c0000664000175000017500000067336015066536113011335 /* * Copyright (c) 2017 Martin Pieuchot * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Ori Bernstein * Copyright (C) 2023 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_worktree_cvg.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_fetch.h" #include "got_send.h" #include "got_blame.h" #include "got_privsep.h" #include "got_opentemp.h" #include "got_gotconfig.h" #include "got_dial.h" #include "got_patch.h" #include "got_sigs.h" #include "got_date.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #ifndef GOT_DEFAULT_EDITOR #define GOT_DEFAULT_EDITOR "/usr/bin/vi" #endif static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigpipe_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigpipe(int signo) { sigpipe_received = 1; } struct got_cmd { const char *cmd_name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); const char *cmd_alias; }; __dead static void usage(int, int); __dead static void usage_import(void); __dead static void usage_clone(void); __dead static void usage_checkout(void); __dead static void usage_update(void); __dead static void usage_log(void); __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_status(void); __dead static void usage_tag(void); __dead static void usage_add(void); __dead static void usage_remove(void); __dead static void usage_patch(void); __dead static void usage_revert(void); __dead static void usage_commit(void); __dead static void usage_cherrypick(void); __dead static void usage_backout(void); __dead static void usage_cat(void); __dead static void usage_info(void); static const struct got_error* cmd_import(int, char *[]); static const struct got_error* cmd_clone(int, char *[]); static const struct got_error* cmd_checkout(int, char *[]); static const struct got_error* cmd_update(int, char *[]); static const struct got_error* cmd_log(int, char *[]); static const struct got_error* cmd_diff(int, char *[]); static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_status(int, char *[]); static const struct got_error* cmd_tag(int, char *[]); static const struct got_error* cmd_add(int, char *[]); static const struct got_error* cmd_remove(int, char *[]); static const struct got_error* cmd_patch(int, char *[]); static const struct got_error* cmd_revert(int, char *[]); static const struct got_error* cmd_commit(int, char *[]); static const struct got_error* cmd_cherrypick(int, char *[]); static const struct got_error* cmd_backout(int, char *[]); static const struct got_error* cmd_cat(int, char *[]); static const struct got_error* cmd_info(int, char *[]); static const struct got_cmd got_commands[] = { { "import", cmd_import, usage_import, "im" }, { "clone", cmd_clone, usage_clone, "cl" }, { "checkout", cmd_checkout, usage_checkout, "co" }, { "update", cmd_update, usage_update, "up" }, { "log", cmd_log, usage_log, "" }, { "diff", cmd_diff, usage_diff, "di" }, { "blame", cmd_blame, usage_blame, "bl" }, { "tree", cmd_tree, usage_tree, "tr" }, { "status", cmd_status, usage_status, "st" }, { "tag", cmd_tag, usage_tag, "" }, { "add", cmd_add, usage_add, "" }, { "remove", cmd_remove, usage_remove, "rm" }, { "patch", cmd_patch, usage_patch, "pa" }, { "revert", cmd_revert, usage_revert, "rv" }, { "commit", cmd_commit, usage_commit, "ci" }, { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" }, { "backout", cmd_backout, usage_backout, "bo" }, { "cat", cmd_cat, usage_cat, "" }, { "info", cmd_info, usage_info, "" }, }; static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(got_commands); i++) { const struct got_cmd *cmd = &got_commands[i]; fprintf(fp, " %s", cmd->cmd_name); } fputc('\n', fp); } __dead static void option_conflict(char a, char b) { errx(1, "-%c and -%c options are mutually exclusive", a, b); } int main(int argc, char *argv[]) { const struct got_cmd *cmd; size_t i; int ch; int hflag = 0, Vflag = 0; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; setlocale(LC_CTYPE, ""); while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc <= 0) usage(hflag, hflag ? 0 : 1); signal(SIGINT, catch_sigint); signal(SIGPIPE, catch_sigpipe); for (i = 0; i < nitems(got_commands); i++) { const struct got_error *error; cmd = &got_commands[i]; if (strcmp(cmd->cmd_name, argv[0]) != 0 && strcmp(cmd->cmd_alias, argv[0]) != 0) continue; if (hflag) cmd->cmd_usage(); error = cmd->cmd_main(argc, argv); if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_PRIVSEP_EXIT && !(sigpipe_received && error->code == GOT_ERR_ERRNO && errno == EPIPE) && !(sigint_received && error->code == GOT_ERR_ERRNO && errno == EINTR)) { fflush(stdout); fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]); list_commands(stderr); return 1; } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) list_commands(fp); exit(status); } static const struct got_error * get_editor(char **abspath) { const struct got_error *err = NULL; const char *editor; *abspath = NULL; editor = getenv("VISUAL"); if (editor == NULL) editor = getenv("EDITOR"); if (editor) { err = got_path_find_prog(abspath, editor); if (err) return err; } if (*abspath == NULL) { *abspath = strdup(GOT_DEFAULT_EDITOR); if (*abspath == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * apply_unveil(const char *repo_path, int repo_read_only, const char *worktree_path) { const struct got_error *err; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0) return got_error_from_errno2("unveil", repo_path); if (worktree_path && unveil(worktree_path, "rwc") != 0) return got_error_from_errno2("unveil", worktree_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); err = got_privsep_unveil_exec_helpers(); if (err != NULL) return err; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } __dead static void usage_import(void) { fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] " "[-r repository-path] directory\n", getprogname()); exit(1); } static int spawn_editor(const char *editor, const char *file) { pid_t pid; sig_t sighup, sigint, sigquit; int st = -1; sighup = signal(SIGHUP, SIG_IGN); sigint = signal(SIGINT, SIG_IGN); sigquit = signal(SIGQUIT, SIG_IGN); switch (pid = fork()) { case -1: goto doneediting; case 0: execl(editor, editor, file, (char *)NULL); _exit(127); } while (waitpid(pid, &st, 0) == -1) if (errno != EINTR) break; doneediting: (void)signal(SIGHUP, sighup); (void)signal(SIGINT, sigint); (void)signal(SIGQUIT, sigquit); if (!WIFEXITED(st)) { errno = EINTR; return -1; } return WEXITSTATUS(st); } static const struct got_error * read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; *logmsg = NULL; *len = 0; if (fseeko(fp, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); *logmsg = malloc(filesize + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); (*logmsg)[0] = '\0'; while (getline(&line, &linesize, fp) != -1) { if (line[0] == '#' || (*len == 0 && line[0] == '\n')) continue; /* remove comments and leading empty lines */ *len = strlcat(*logmsg, line, filesize + 1); if (*len >= filesize + 1) { err = got_error(GOT_ERR_NO_SPACE); goto done; } } if (ferror(fp)) { err = got_ferror(fp, GOT_ERR_IO); goto done; } while (*len > 0 && (*logmsg)[*len - 1] == '\n') { (*logmsg)[*len - 1] = '\0'; (*len)--; } done: free(line); if (err) { free(*logmsg); *logmsg = NULL; *len = 0; } return err; } static const struct got_error * edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path, const char *initial_content, size_t initial_content_len, int require_modification) { const struct got_error *err = NULL; struct stat st, st2; FILE *fp = NULL; size_t logmsg_len; *logmsg = NULL; if (stat(logmsg_path, &st) == -1) return got_error_from_errno2("stat", logmsg_path); if (spawn_editor(editor, logmsg_path) == -1) return got_error_from_errno("failed spawning editor"); if (require_modification) { struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 1; nanosleep(&timeout, NULL); } if (stat(logmsg_path, &st2) == -1) return got_error_from_errno2("stat", logmsg_path); if (require_modification && st.st_size == st2.st_size && timespeccmp(&st.st_mtim, &st2.st_mtim, ==)) return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "no changes made to commit message, aborting"); fp = fopen(logmsg_path, "re"); if (fp == NULL) { err = got_error_from_errno("fopen"); goto done; } /* strip comments and leading/trailing newlines */ err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size); if (err) goto done; if (logmsg_len == 0) { err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY, "commit message cannot be empty, aborting"); goto done; } done: if (fp && fclose(fp) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_import_msg(char **logmsg, char **logmsg_path, const char *editor, const char *path_dir, const char *branch_name) { char *initial_content = NULL; const struct got_error *err = NULL; int initial_content_len; int fd = -1; initial_content_len = asprintf(&initial_content, "\n# %s to be imported to branch %s\n", path_dir, branch_name); if (initial_content_len == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(logmsg_path, &fd, GOT_TMPDIR_STR "/got-importmsg", ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *logmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content, initial_content_len, 1); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *logmsg_path); free(initial_content); if (err) { free(*logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * import_progress(void *arg, const char *path) { printf("A %s\n", path); return NULL; } static const struct got_error * valid_author(const char *author) { const char *email = author; /* * Git' expects the author (or committer) to be in the form * "name ", which are mostly free form (see the * "committer" description in git-fast-import(1)). We're only * doing this to avoid git's object parser breaking on commits * we create. */ while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (author != email && *author == '<' && *(author - 1) != ' ') return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space " "between author name and email required", email); if (*author++ != '<') return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); while (*author && *author != '\n' && *author != '<' && *author != '>') author++; if (strcmp(author, ">") != 0) return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email); return NULL; } static const struct got_error * get_author(char **author, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; const char *got_author = NULL, *name, *email; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *author = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file * 3) repository's git config file * 4) environment variables * 5) global git config files (in user's home directory or /etc) */ if (worktree_conf) got_author = got_gotconfig_get_author(worktree_conf); if (got_author == NULL) got_author = got_gotconfig_get_author(repo_conf); if (got_author == NULL) { name = got_repo_get_gitconfig_author_name(repo); email = got_repo_get_gitconfig_author_email(repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } got_author = getenv("GOT_AUTHOR"); if (got_author == NULL) { name = got_repo_get_global_gitconfig_author_name(repo); email = got_repo_get_global_gitconfig_author_email( repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } /* TODO: Look up user in password database? */ return got_error(GOT_ERR_COMMIT_NO_AUTHOR); } } *author = strdup(got_author); if (*author == NULL) return got_error_from_errno("strdup"); err = valid_author(*author); if (err) { free(*author); *author = NULL; } return err; } static const struct got_error * get_allowed_signers(char **allowed_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_allowed_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *allowed_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_allowed_signers = got_gotconfig_get_allowed_signers_file( worktree_conf); if (got_allowed_signers == NULL) got_allowed_signers = got_gotconfig_get_allowed_signers_file( repo_conf); if (got_allowed_signers) { *allowed_signers = strdup(got_allowed_signers); if (*allowed_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * get_revoked_signers(char **revoked_signers, struct got_repository *repo, struct got_worktree *worktree) { const char *got_revoked_signers = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *revoked_signers = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_revoked_signers = got_gotconfig_get_revoked_signers_file( worktree_conf); if (got_revoked_signers == NULL) got_revoked_signers = got_gotconfig_get_revoked_signers_file( repo_conf); if (got_revoked_signers) { *revoked_signers = strdup(got_revoked_signers); if (*revoked_signers == NULL) return got_error_from_errno("strdup"); } return NULL; } static const char * get_signer_id(struct got_repository *repo, struct got_worktree *worktree) { const char *got_signer_id = NULL; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file */ if (worktree_conf) got_signer_id = got_gotconfig_get_signer_id(worktree_conf); if (got_signer_id == NULL) got_signer_id = got_gotconfig_get_signer_id(repo_conf); return got_signer_id; } static const struct got_error * get_gitconfig_path(char **gitconfig_path) { const char *homedir = getenv("HOME"); *gitconfig_path = NULL; if (homedir) { if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1) return got_error_from_errno("asprintf"); } return NULL; } static const struct got_error * cmd_import(int argc, char *argv[]) { const struct got_error *error = NULL; char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL; char *gitconfig_path = NULL, *editor = NULL, *author = NULL; const char *branch_name = NULL; char *id_str = NULL, *logmsg_path = NULL; char refname[PATH_MAX] = "refs/heads/"; struct got_repository *repo = NULL; struct got_reference *branch_ref = NULL, *head_ref = NULL; struct got_object_id *new_commit_id = NULL; int ch, n = 0; struct got_pathlist_head ignores; struct got_pathlist_entry *pe; int preserve_logmsg = 0; int *pack_fds = NULL; RB_INIT(&ignores); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'I': if (optarg[0] == '\0') break; error = got_pathlist_insert(&pe, &ignores, optarg, NULL); if (error) goto done; break; case 'm': logmsg = strdup(optarg); if (logmsg == NULL) { error = got_error_from_errno("strdup"); goto done; } break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } break; default: usage_import(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_import(); if (repo_path == NULL) { repo_path = getcwd(NULL, 0); if (repo_path == NULL) { error = got_error_from_errno("getcwd"); goto done; } } got_path_strip_trailing_slashes(repo_path); error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds); if (error) goto done; error = get_author(&author, repo, NULL); if (error) goto done; /* * Don't let the user create a branch name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (branch_name && branch_name[0] == '-') { error = got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS); goto done; } error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error && error->code != GOT_ERR_NOT_REF) goto done; if (branch_name) n = strlcat(refname, branch_name, sizeof(refname)); else if (head_ref && got_ref_is_symbolic(head_ref)) n = strlcpy(refname, got_ref_get_symref_target(head_ref), sizeof(refname)); else n = strlcat(refname, "main", sizeof(refname)); if (n >= sizeof(refname)) { error = got_error(GOT_ERR_NO_SPACE); goto done; } error = got_ref_open(&branch_ref, repo, refname, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; } else { error = got_error_msg(GOT_ERR_BRANCH_EXISTS, "import target branch already exists"); goto done; } path_dir = realpath(argv[0], NULL); if (path_dir == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } got_path_strip_trailing_slashes(path_dir); /* * unveil(2) traverses exec(2); if an editor is used we have * to apply unveil after the log message has been written. */ if (logmsg == NULL || *logmsg == '\0') { error = get_editor(&editor); if (error) goto done; free(logmsg); error = collect_import_msg(&logmsg, &logmsg_path, editor, path_dir, refname); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && logmsg_path != NULL) preserve_logmsg = 1; goto done; } } if (unveil(path_dir, "r") != 0) { error = got_error_from_errno2("unveil", path_dir); if (logmsg_path) preserve_logmsg = 1; goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_repo_import(&new_commit_id, path_dir, logmsg, author, &ignores, repo, import_progress, NULL); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc(&branch_ref, refname, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(branch_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, new_commit_id); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0); if (error) { if (error->code != GOT_ERR_NOT_REF) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD, branch_ref); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } error = got_ref_write(head_ref, repo); if (error) { if (logmsg_path) preserve_logmsg = 1; goto done; } } printf("Created branch %s with commit %s\n", got_ref_get_name(branch_ref), id_str); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), logmsg_path); } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", logmsg_path); got_pathlist_free(&ignores, GOT_PATHLIST_FREE_NONE); free(logmsg); free(logmsg_path); free(path_dir); free(repo_path); free(editor); free(new_commit_id); free(id_str); free(author); free(gitconfig_path); if (branch_ref) got_ref_close(branch_ref); if (head_ref) got_ref_close(head_ref); return error; } __dead static void usage_clone(void) { fprintf(stderr, "usage: %s clone [-almqv] [-b branch] " "[-i identity-file] [-J jumphost] [-R reference] " "repository-URL [directory]\n", getprogname()); exit(1); } struct got_fetch_progress_arg { char last_scaled_size[FMT_SCALED_STRSIZE]; int last_p_indexed; int last_p_resolved; int verbosity; struct got_repository *repo; int create_configs; int configs_created; struct { struct got_pathlist_head *symrefs; struct got_pathlist_head *wanted_branches; struct got_pathlist_head *wanted_refs; const char *proto; const char *host; const char *port; const char *remote_repo_path; const char *git_url; int fetch_all_branches; int mirror_references; } config_info; }; /* XXX forward declaration */ static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo); static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { const struct got_error *err = NULL; struct got_fetch_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_indexed, p_resolved; int print_size = 0, print_indexed = 0, print_resolved = 0; /* * In order to allow a failed clone to be resumed with 'got fetch' * we try to create configuration files as soon as possible. * Once the server has sent information about its default branch * we have all required information. */ if (a->create_configs && !a->configs_created && !RB_EMPTY(a->config_info.symrefs)) { err = create_config_files(a->config_info.proto, a->config_info.host, a->config_info.port, a->config_info.remote_repo_path, a->config_info.git_url, a->config_info.fetch_all_branches, a->config_info.mirror_references, a->config_info.symrefs, a->config_info.wanted_branches, a->config_info.wanted_refs, a->repo); if (err) return err; a->configs_created = 1; } if (a->verbosity < 0) return NULL; if (message && message[0] != '\0') { printf("\rserver: %s", message); fflush(stdout); return NULL; } if (packfile_size > 0 || nobj_indexed > 0) { if (fmt_scaled(packfile_size, scaled_size) == 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { print_size = 1; if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_indexed > 0) { p_indexed = (nobj_indexed * 100) / nobj_total; if (p_indexed != a->last_p_indexed) { a->last_p_indexed = p_indexed; print_indexed = 1; print_size = 1; } } if (nobj_resolved > 0) { p_resolved = (nobj_resolved * 100) / (nobj_total - nobj_loose); if (p_resolved != a->last_p_resolved) { a->last_p_resolved = p_resolved; print_resolved = 1; print_indexed = 1; print_size = 1; } } } if (print_size || print_indexed || print_resolved) printf("\r"); if (print_size) printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size); if (print_indexed) printf("; indexing %d%%", p_indexed); if (print_resolved) printf("; resolving deltas %d%%", p_resolved); if (print_size || print_indexed || print_resolved) fflush(stdout); return NULL; } static const struct got_error * create_symref(const char *refname, struct got_reference *target_ref, int verbosity, struct got_repository *repo) { const struct got_error *err; struct got_reference *head_symref; err = got_ref_alloc_symref(&head_symref, refname, target_ref); if (err) return err; err = got_ref_write(head_symref, repo); if (err == NULL && verbosity > 0) { printf("Created reference %s: %s\n", GOT_REF_HEAD, got_ref_get_name(target_ref)); } got_ref_close(head_symref); return err; } static const struct got_error * list_remote_refs(struct got_pathlist_head *symrefs, struct got_pathlist_head *refs) { const struct got_error *err; struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *refname = pe->path; const char *targetref = pe->data; printf("%s: %s\n", refname, targetref); } RB_FOREACH(pe, got_pathlist_head, refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; printf("%s: %s\n", refname, id_str); free(id_str); } return NULL; } static const struct got_error * create_ref(const char *refname, struct got_object_id *id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); got_ref_close(ref); if (err == NULL && verbosity >= 0) printf("Created reference %s: %s\n", refname, id_str); done: free(id_str); return err; } static int match_wanted_ref(const char *refname, const char *wanted_ref) { if (strncmp(refname, "refs/", 5) != 0) return 0; refname += 5; /* * Prevent fetching of references that won't make any * sense outside of the remote repository's context. */ if (strncmp(refname, "got/", 4) == 0) return 0; if (strncmp(refname, "remotes/", 8) == 0) return 0; if (strncmp(wanted_ref, "refs/", 5) == 0) wanted_ref += 5; /* Allow prefix match. */ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) return 1; /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); } static int is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { if (match_wanted_ref(refname, pe->path)) return 1; } return 0; } static const struct got_error * create_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err; char *remote_refname; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = create_ref(remote_refname, id, verbosity, repo); free(remote_refname); return err; } static const struct got_error * create_gotconfig(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path = NULL; char *gotconfig = NULL; FILE *gotconfig_file = NULL; const char *branchname = NULL; char *branches = NULL, *refs = NULL; ssize_t n; if (!fetch_all_branches && !RB_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_branches) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&s, "%s\"%s\" ", branches ? branches : "", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else if (!fetch_all_branches && default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (asprintf(&branches, "\"%s\" ", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!RB_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) branchname += 5; if (asprintf(&s, "%s\"%s\" ", refs ? refs : "", refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } /* Create got.conf(5). */ gotconfig_path = got_repo_get_path_gotconfig(repo); if (gotconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gotconfig"); goto done; } gotconfig_file = fopen(gotconfig_path, "ae"); if (gotconfig_file == NULL) { err = got_error_from_errno2("fopen", gotconfig_path); goto done; } if (asprintf(&gotconfig, "remote \"%s\" {\n" "\tserver %s\n" "\tprotocol %s\n" "%s%s%s" "\trepository \"%s\"\n" "%s%s%s" "%s%s%s" "%s" "%s" "}\n", GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto, port ? "\tport " : "", port ? port : "", port ? "\n" : "", remote_repo_path, branches ? "\tbranch { " : "", branches ? branches : "", branches ? "}\n" : "", refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "", mirror_references ? "\tmirror_references yes\n" : "", fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file); if (n != strlen(gotconfig)) { err = got_ferror(gotconfig_file, GOT_ERR_IO); goto done; } done: if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gotconfig_path); free(gotconfig_path); free(branches); return err; } static const struct got_error * create_gitconfig(const char *git_url, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int mirror_references, struct got_repository *repo) { const struct got_error *err = NULL; char *gitconfig_path = NULL; char *gitconfig = NULL; FILE *gitconfig_file = NULL; char *branches = NULL, *refs = NULL; const char *branchname; ssize_t n; /* Create a config file Git can understand. */ gitconfig_path = got_repo_get_path_gitconfig(repo); if (gitconfig_path == NULL) { err = got_error_from_errno("got_repo_get_path_gitconfig"); goto done; } gitconfig_file = fopen(gitconfig_path, "ae"); if (gitconfig_file == NULL) { err = got_error_from_errno2("fopen", gitconfig_path); goto done; } if (fetch_all_branches) { if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/*:refs/heads/*\n") == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/*:refs/remotes/%s/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (!RB_EMPTY(wanted_branches)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_branches) { char *s; branchname = pe->path; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/heads/%s\n", branches ? branches : "", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branches ? branches : "", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(branches); branches = s; } } else { /* * If the server specified a default branch, use just that one. * Otherwise fall back to fetching all branches on next fetch. */ if (default_branch) { branchname = default_branch; if (strncmp(branchname, "refs/heads/", 11) == 0) branchname += 11; } else branchname = "*"; /* fall back to all branches */ if (mirror_references) { if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/heads/%s\n", branchname, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&branches, "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n", branchname, GOT_FETCH_DEFAULT_REMOTE_NAME, branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (!RB_EMPTY(wanted_refs)) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, wanted_refs) { char *s; const char *refname = pe->path; if (strncmp(refname, "refs/", 5) == 0) refname += 5; if (mirror_references) { if (asprintf(&s, "%s\tfetch = refs/%s:refs/%s\n", refs ? refs : "", refname, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } } else if (asprintf(&s, "%s\tfetch = refs/%s:refs/remotes/%s/%s\n", refs ? refs : "", refname, GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { err = got_error_from_errno("asprintf"); goto done; } free(refs); refs = s; } } if (asprintf(&gitconfig, "[remote \"%s\"]\n" "\turl = %s\n" "%s" "%s" "\tfetch = refs/tags/*:refs/tags/*\n", GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "", refs ? refs : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file); if (n != strlen(gitconfig)) { err = got_ferror(gitconfig_file, GOT_ERR_IO); goto done; } done: if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL) err = got_error_from_errno2("fclose", gitconfig_path); free(gitconfig_path); free(branches); return err; } static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, struct got_repository *repo) { const struct got_error *err = NULL; const char *default_branch = NULL; struct got_pathlist_entry *pe; /* * If we asked for a set of wanted branches then use the first * one of those. */ if (!RB_EMPTY(wanted_branches)) { pe = RB_MIN(got_pathlist_head, wanted_branches); default_branch = pe->path; } else { /* First HEAD ref listed by server is the default branch. */ RB_FOREACH(pe, got_pathlist_head, symrefs) { const char *refname = pe->path; const char *target = pe->data; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; default_branch = target; break; } } /* Create got.conf(5). */ err = create_gotconfig(proto, host, port, remote_repo_path, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); if (err) return err; /* Create a config file Git can understand. */ return create_gitconfig(git_url, default_branch, fetch_all_branches, wanted_branches, wanted_refs, mirror_references, repo); } static const struct got_error * cmd_clone(int argc, char *argv[]) { const struct got_error *error = NULL; const char *uri, *dirname; char *proto, *host, *port, *repo_name, *server_path; char *default_destdir = NULL, *id_str = NULL; const char *repo_path; struct got_repository *repo = NULL; struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_object_id *pack_hash = NULL; int ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; char *git_url = NULL; int verbosity = 0, fetch_all_branches = 0, mirror_references = 0; int bflag = 0, list_refs_only = 0; int *pack_fds = NULL; const char *identity_file = NULL; const char *jumphost = NULL; RB_INIT(&refs); RB_INIT(&symrefs); RB_INIT(&wanted_branches); RB_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "ab:i:J:lmqR:v")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; break; case 'b': error = got_pathlist_insert(NULL, &wanted_branches, optarg, NULL); if (error) return error; bflag = 1; break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 'l': list_refs_only = 1; break; case 'm': mirror_references = 1; break; case 'q': verbosity = -1; break; case 'R': error = got_pathlist_insert(NULL, &wanted_refs, optarg, NULL); if (error) return error; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_clone(); break; } } argc -= optind; argv += optind; if (fetch_all_branches && !RB_EMPTY(&wanted_branches)) option_conflict('a', 'b'); if (list_refs_only) { if (!RB_EMPTY(&wanted_branches)) option_conflict('l', 'b'); if (fetch_all_branches) option_conflict('l', 'a'); if (mirror_references) option_conflict('l', 'm'); if (!RB_EMPTY(&wanted_refs)) option_conflict('l', 'R'); } uri = argv[0]; if (argc == 1) dirname = NULL; else if (argc == 2) dirname = argv[1]; else usage_clone(); error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, uri); if (error) goto done; if (asprintf(&git_url, "%s://%s%s%s%s%s", proto, host, port ? ":" : "", port ? port : "", server_path[0] != '/' ? "/" : "", server_path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } if (dirname == NULL) { if (asprintf(&default_destdir, "%s.git", repo_name) == -1) { error = got_error_from_errno("asprintf"); goto done; } repo_path = default_destdir; } else repo_path = dirname; if (!list_refs_only) { error = got_path_mkdir(repo_path); if (error && (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))) goto done; if (!got_path_dir_is_empty(repo_path)) { error = got_error_path(repo_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(repo_path, 0, NULL); if (error) goto done; if (verbosity >= 0) printf("Connecting to %s\n", git_url); error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, jumphost, identity_file, verbosity); if (error) goto done; if (!list_refs_only) { error = got_repo_init(repo_path, NULL, GOT_HASH_SHA1); if (error) goto done; error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; } fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.create_configs = 1; fpa.configs_created = 0; fpa.repo = repo; fpa.config_info.symrefs = &symrefs; fpa.config_info.wanted_branches = &wanted_branches; fpa.config_info.wanted_refs = &wanted_refs; fpa.config_info.proto = proto; fpa.config_info.host = host; fpa.config_info.port = port; fpa.config_info.remote_repo_path = server_path; fpa.config_info.git_url = git_url; fpa.config_info.fetch_all_branches = fetch_all_branches; fpa.config_info.mirror_references = mirror_references; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag, fetch_progress, &fpa); if (error) goto done; if (list_refs_only) { error = list_remote_refs(&symrefs, &refs); goto done; } if (pack_hash == NULL) { error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s", "server sent an empty pack file"); goto done; } error = got_object_id_str(&id_str, pack_hash); if (error) goto done; if (verbosity >= 0) printf("\nFetched %s.pack\n", id_str); free(id_str); /* Set up references provided with the pack file. */ RB_FOREACH(pe, got_pathlist_head, &refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *remote_refname; if (is_wanted_ref(&wanted_refs, refname) && !mirror_references) { error = create_wanted_ref(refname, id, GOT_FETCH_DEFAULT_REMOTE_NAME, verbosity - 1, repo); if (error) goto done; continue; } error = create_ref(refname, id, verbosity - 1, repo); if (error) goto done; if (mirror_references) continue; if (strncmp("refs/heads/", refname, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname + 11) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = create_ref(remote_refname, id, verbosity - 1, repo); free(remote_refname); if (error) goto done; } /* Set the HEAD reference if the server provided one. */ RB_FOREACH(pe, got_pathlist_head, &symrefs) { struct got_reference *target_ref; const char *refname = pe->path; const char *target = pe->data; char *remote_refname = NULL, *remote_target = NULL; if (strcmp(refname, GOT_REF_HEAD) != 0) continue; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(refname, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; if (mirror_references) continue; if (strncmp("refs/heads/", target, 11) != 0) continue; if (asprintf(&remote_refname, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, refname) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (asprintf(&remote_target, "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME, target + 11) == -1) { error = got_error_from_errno("asprintf"); free(remote_refname); goto done; } error = got_ref_open(&target_ref, repo, remote_target, 0); if (error) { free(remote_refname); free(remote_target); if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(remote_refname, target_ref, verbosity - 1, repo); free(remote_refname); free(remote_target); got_ref_close(target_ref); if (error) goto done; } if (pe == NULL) { /* * We failed to set the HEAD reference. If we asked for * a set of wanted branches use the first of one of those * which could be fetched instead. */ RB_FOREACH(pe, got_pathlist_head, &wanted_branches) { const char *target = pe->path; struct got_reference *target_ref; error = got_ref_open(&target_ref, repo, target, 0); if (error) { if (error->code == GOT_ERR_NOT_REF) { error = NULL; continue; } goto done; } error = create_symref(GOT_REF_HEAD, target_ref, verbosity, repo); got_ref_close(target_ref); if (error) goto done; break; } if (!fpa.configs_created && pe != NULL) { error = create_config_files(fpa.config_info.proto, fpa.config_info.host, fpa.config_info.port, fpa.config_info.remote_repo_path, fpa.config_info.git_url, fpa.config_info.fetch_all_branches, fpa.config_info.mirror_references, fpa.config_info.symrefs, fpa.config_info.wanted_branches, fpa.config_info.wanted_refs, fpa.repo); if (error) goto done; } } if (verbosity >= 0) printf("Created %s repository '%s'\n", mirror_references ? "mirrored" : "cloned", repo_path); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); free(default_destdir); free(git_url); return error; } static const struct got_error * update_ref(struct got_reference *ref, struct got_object_id *new_id, int replace_tags, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; char *new_id_str = NULL; struct got_object_id *old_id = NULL; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; if (!replace_tags && strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; if (verbosity >= 0) { printf("Rejecting update of existing tag %s: %s\n", got_ref_get_name(ref), new_id_str); } goto done; } if (got_ref_is_symbolic(ref)) { if (verbosity >= 0) { printf("Replacing reference %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } err = got_ref_change_symref_to_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } else { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; err = got_ref_change_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(ref), new_id_str); done: free(old_id); free(new_id_str); return err; } static const struct got_error * update_wanted_ref(const char *refname, struct got_object_id *id, const char *remote_repo_name, int verbosity, struct got_repository *repo) { const struct got_error *err, *unlock_err; char *remote_refname; struct got_reference *ref; if (strncmp("refs/", refname, 5) == 0) refname += 5; if (asprintf(&remote_refname, "refs/remotes/%s/%s", remote_repo_name, refname) == -1) return got_error_from_errno("asprintf"); err = got_ref_open(&ref, repo, remote_refname, 1); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = create_ref(remote_refname, id, verbosity, repo); } else { err = update_ref(ref, id, 0, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; got_ref_close(ref); } done: free(remote_refname); return err; } __dead static void usage_checkout(void) { fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] " "[-p path-prefix] repository-path [work-tree-path]\n", getprogname()); exit(1); } static void show_worktree_base_ref_warning(void) { fprintf(stderr, "%s: warning: could not create a reference " "to the work tree's base commit; the commit could be " "garbage-collected by Git or 'gotadmin cleanup'; making the " "repository writable and running 'got update' will prevent this\n", getprogname()); } struct got_checkout_progress_arg { const char *worktree_path; int had_base_commit_ref_error; int verbosity; }; static const struct got_error * checkout_progress(void *arg, unsigned char status, const char *path) { struct got_checkout_progress_arg *a = arg; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_BASE_REF_ERR) { a->had_base_commit_ref_error = 1; return NULL; } while (path[0] == '/') path++; if (a->verbosity >= 0) printf("%c %s/%s\n", status, a->worktree_path, path); return NULL; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigpipe_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * check_linear_ancestry(struct got_object_id *commit_id, struct got_object_id *base_commit_id, int allow_forwards_in_time_only, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *yca_id; err = got_commit_graph_find_youngest_common_ancestor(&yca_id, commit_id, base_commit_id, 1, 0, repo, check_cancelled, NULL); if (err) return err; if (yca_id == NULL) return got_error(GOT_ERR_ANCESTRY); /* * Require a straight line of history between the target commit * and the work tree's base commit. * * Non-linear situations such as this require a rebase: * * (commit) D F (base_commit) * \ / * C E * \ / * B (yca) * | * A * * 'got update' only handles linear cases: * Update forwards in time: A (base/yca) - B - C - D (commit) * Update backwards in time: D (base) - C - B - A (commit/yca) */ if (allow_forwards_in_time_only) { if (got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); } else if (got_object_id_cmp(commit_id, yca_id) != 0 && got_object_id_cmp(base_commit_id, yca_id) != 0) return got_error(GOT_ERR_ANCESTRY); free(yca_id); return NULL; } static const struct got_error * check_same_branch(struct got_object_id *commit_id, struct got_reference *head_ref, struct got_repository *repo) { const struct got_error *err = NULL; struct got_commit_graph *graph = NULL; struct got_object_id *head_commit_id = NULL; err = got_ref_resolve(&head_commit_id, repo, head_ref); if (err) goto done; if (got_object_id_cmp(head_commit_id, commit_id) == 0) goto done; err = got_commit_graph_open(&graph, "/", 1); if (err) goto done; err = got_commit_graph_bfsort(graph, head_commit_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = got_error(GOT_ERR_ANCESTRY); break; } if (got_object_id_cmp(&id, commit_id) == 0) break; } done: if (graph) got_commit_graph_close(graph); free(head_commit_id); return err; } static const struct got_error * checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str) { static char msg[512]; const char *branch_name; if (got_ref_is_symbolic(ref)) branch_name = got_ref_get_symref_target(ref); else branch_name = got_ref_get_name(ref); if (strncmp("refs/heads/", branch_name, 11) == 0) branch_name += 11; snprintf(msg, sizeof(msg), "target commit is not contained in branch '%s'; " "the branch to use must be specified with -b; " "if necessary a new branch can be created for " "this commit with 'got branch -c %s BRANCH_NAME'", branch_name, commit_id_str); return got_error_msg(GOT_ERR_ANCESTRY, msg); } static const struct got_error * cmd_checkout(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_reference *head_ref = NULL, *ref = NULL; struct got_worktree *worktree = NULL; char *repo_path = NULL; char *worktree_path = NULL; const char *path_prefix = ""; const char *branch_name = GOT_REF_HEAD, *refname = NULL; char *commit_id_str = NULL; struct got_object_id *commit_id = NULL; char *cwd = NULL; int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0; struct got_pathlist_head paths; struct got_checkout_progress_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) { switch (ch) { case 'b': branch_name = optarg; break; case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 'E': allow_nonempty = 1; break; case 'p': path_prefix = optarg; break; case 'q': verbosity = -1; break; default: usage_checkout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) { char *base, *dotgit; const char *path; repo_path = realpath(argv[0], NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", argv[0]); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } if (path_prefix[0]) path = path_prefix; else path = repo_path; error = got_path_basename(&base, path); if (error) goto done; dotgit = strstr(base, ".git"); if (dotgit) *dotgit = '\0'; if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) { error = got_error_from_errno("asprintf"); free(base); goto done; } free(base); } else if (argc == 2) { repo_path = realpath(argv[0], NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", argv[0]); goto done; } worktree_path = realpath(argv[1], NULL); if (worktree_path == NULL) { if (errno != ENOENT) { error = got_error_from_errno2("realpath", argv[1]); goto done; } worktree_path = strdup(argv[1]); if (worktree_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else usage_checkout(); got_path_strip_trailing_slashes(repo_path); got_path_strip_trailing_slashes(worktree_path); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; /* Pre-create work tree path for unveil(2) */ error = got_path_mkdir(worktree_path); if (error) { if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; if (!allow_nonempty && !got_path_dir_is_empty(worktree_path)) { error = got_error_path(worktree_path, GOT_ERR_DIR_NOT_EMPTY); goto done; } } error = apply_unveil(got_repo_get_path(repo), 0, worktree_path); if (error) goto done; error = got_ref_open(&head_ref, repo, branch_name, 0); if (error != NULL) goto done; error = got_worktree_init(worktree_path, head_ref, path_prefix, GOT_WORKTREE_CVG_DIR, repo); if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR); if (error != NULL) goto done; error = got_worktree_match_path_prefix(&same_path_prefix, worktree, path_prefix); if (error != NULL) goto done; if (!same_path_prefix) { error = got_error(GOT_ERR_PATH_PREFIX); goto done; } if (commit_id_str) { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) { if (error->code == GOT_ERR_ANCESTRY) { error = checkout_ancestry_error( head_ref, commit_id_str); } goto done; } error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; /* Expand potentially abbreviated commit ID string. */ free(commit_id_str); error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } else { commit_id = got_object_id_dup( got_worktree_get_base_commit_id(worktree)); if (commit_id == NULL) { error = got_error_from_errno("got_object_id_dup"); goto done; } error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } error = got_pathlist_insert(NULL, &paths, "", NULL); if (error) goto done; cpa.worktree_path = worktree_path; cpa.had_base_commit_ref_error = 0; cpa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, checkout_progress, &cpa, check_cancelled, NULL); if (error != NULL) goto done; if (got_ref_is_symbolic(head_ref)) { error = got_ref_resolve_symbolic(&ref, repo, head_ref); if (error) goto done; refname = got_ref_get_name(ref); } else refname = got_ref_get_name(head_ref); printf("Checked out %s: %s\n", refname, commit_id_str); printf("Now shut up and hack\n"); if (cpa.had_base_commit_ref_error) show_worktree_base_ref_warning(); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (head_ref) got_ref_close(head_ref); if (ref) got_ref_close(ref); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); free(commit_id_str); free(commit_id); free(repo_path); free(worktree_path); free(cwd); return error; } struct got_update_progress_arg { int did_something; int conflicts; int obstructed; int not_updated; int missing; int not_deleted; int unversioned; int verbosity; }; static void print_update_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->not_updated > 0) printf("Files not updated because of existing merge " "conflicts: %d\n", upa->not_updated); } /* * The meaning of some status codes differs between merge-style operations and * update operations. For example, the ! status code means "file was missing" * if changes were merged into the work tree, and "missing file was restored" * if the work tree was updated. This function should be used by any operation * which merges changes into the work tree without updating the work tree. */ static void print_merge_progress_stats(struct got_update_progress_arg *upa) { if (!upa->did_something) return; if (upa->conflicts > 0) printf("Files with new merge conflicts: %d\n", upa->conflicts); if (upa->obstructed > 0) printf("File paths obstructed by a non-regular file: %d\n", upa->obstructed); if (upa->missing > 0) printf("Files which had incoming changes but could not be " "found in the work tree: %d\n", upa->missing); if (upa->not_deleted > 0) printf("Files not deleted due to differences in deleted " "content: %d\n", upa->not_deleted); if (upa->unversioned > 0) printf("Files not merged because an unversioned file was " "found in the work tree: %d\n", upa->unversioned); } __dead static void usage_update(void) { fprintf(stderr, "usage: %s update [-qtvX] [-c commit] " "[-i identity-file] [-J jumphost] [-r remote] [path ...]\n", getprogname()); exit(1); } static const struct got_error * update_progress(void *arg, unsigned char status, const char *path) { struct got_update_progress_arg *upa = arg; if (status == GOT_STATUS_EXISTS || status == GOT_STATUS_BASE_REF_ERR) return NULL; upa->did_something = 1; /* Base commit bump happens silently. */ if (status == GOT_STATUS_BUMP_BASE) return NULL; if (status == GOT_STATUS_CONFLICT) upa->conflicts++; if (status == GOT_STATUS_OBSTRUCTED) upa->obstructed++; if (status == GOT_STATUS_CANNOT_UPDATE) upa->not_updated++; if (status == GOT_STATUS_MISSING) upa->missing++; if (status == GOT_STATUS_CANNOT_DELETE) upa->not_deleted++; if (status == GOT_STATUS_UNVERSIONED) upa->unversioned++; while (path[0] == '/') path++; if (upa->verbosity >= 0) printf("%c %s\n", status, path); return NULL; } static const struct got_error * check_rebase_or_histedit_in_progress(struct got_worktree *worktree) { const struct got_error *err; int in_progress; err = got_worktree_rebase_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_REBASING); err = got_worktree_histedit_in_progress(&in_progress, worktree); if (err) return err; if (in_progress) return got_error(GOT_ERR_HISTEDIT_BUSY); return NULL; } static const struct got_error * check_merge_in_progress(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; int in_progress; err = got_worktree_merge_in_progress(&in_progress, worktree, repo); if (err) return err; if (in_progress) return got_error(GOT_ERR_MERGE_BUSY); return NULL; } static const struct got_error * get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc, char *argv[], struct got_worktree *worktree) { const struct got_error *err = NULL; char *path; struct got_pathlist_entry *new; int i; if (argc == 0) { path = strdup(""); if (path == NULL) return got_error_from_errno("strdup"); return got_pathlist_insert(NULL, paths, path, NULL); } for (i = 0; i < argc; i++) { err = got_worktree_resolve_path(&path, worktree, argv[i]); if (err) break; err = got_pathlist_insert(&new, paths, path, NULL); if (err || new == NULL /* duplicate */) { free(path); if (err) break; } } return err; } static const struct got_error * wrap_not_worktree_error(const struct got_error *orig_err, const char *cmdname, const char *path) { const struct got_error *err; struct got_repository *repo; static char msg[512]; int *pack_fds = NULL; err = got_repo_pack_fds_open(&pack_fds); if (err) return err; err = got_repo_open(&repo, path, NULL, pack_fds); if (err) return orig_err; snprintf(msg, sizeof(msg), "'got %s' needs a work tree in addition to a git repository\n" "Work trees can be checked out from this Git repository with " "'got checkout'.\n" "The got(1) manual page contains more information.", cmdname); err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (err == NULL) err = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (err == NULL) err = pack_err; } return err; } static const struct got_error * cmd_update(int argc, char *argv[]) { const struct got_error *error = NULL, *unlock_err; char *worktree_path = NULL; const char *repo_path = NULL; const char *remote_name = NULL; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const struct got_remote_repo *remotes, *remote = NULL; int nremotes; char *id_str = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; struct got_pathlist_head paths, refs, symrefs; struct got_pathlist_head wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_reflist_head remote_refs; struct got_reflist_entry *re; struct got_object_id *pack_hash = NULL; int i, ch, fetchfd = -1, fetchstatus; pid_t fetchpid = -1; struct got_fetch_progress_arg fpa; struct got_update_progress_arg upa; int verbosity = 0; int delete_remote = 0; int replace_tags = 0; int *pack_fds = NULL; const char *remote_head = NULL, *worktree_branch = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; const char *refname; struct got_reference *head_ref = NULL; const char *identity_file = NULL; const char *jumphost = NULL; RB_INIT(&paths); RB_INIT(&refs); RB_INIT(&symrefs); TAILQ_INIT(&remote_refs); RB_INIT(&wanted_branches); RB_INIT(&wanted_refs); while ((ch = getopt(argc, argv, "c:i:J:qr:vX")) != -1) { switch (ch) { case 'c': commit_id_str = strdup(optarg); if (commit_id_str == NULL) return got_error_from_errno("strdup"); break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 't': replace_tags = 1; break; case 'q': verbosity = -1; break; case 'r': remote_name = optarg; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; case 'X': delete_remote = 1; break; default: usage_update(); break; } } argc -= optind; argv += optind; if (delete_remote) { if (replace_tags) option_conflict('X', 't'); if (remote_name == NULL) errx(1, "-X option requires a remote name"); } if (remote_name == NULL) remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME; worktree_path = getcwd(NULL, 0); if (worktree_path == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, worktree_path, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "update", worktree_path); goto done; } repo_path = got_worktree_get_repo_path(worktree); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = check_rebase_or_histedit_in_progress(worktree); if (error) goto done; error = check_merge_in_progress(worktree, repo); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->fetch_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); } error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port, server_path, jumphost, identity_file, verbosity); if (error) goto done; /* * If set, get this remote's HEAD ref target so * if it has changed on the server we can fetch it. */ error = got_ref_list(&remote_refs, repo, "refs/remotes", got_ref_cmp_by_name, repo); if (error) goto done; TAILQ_FOREACH(re, &remote_refs, entry) { const char *remote_refname, *remote_target; size_t remote_name_len; if (!got_ref_is_symbolic(re->ref)) continue; remote_name_len = strlen(remote->name); remote_refname = got_ref_get_name(re->ref); /* we only want refs/remotes/$remote->name/HEAD */ if (strncmp(remote_refname + 13, remote->name, remote_name_len) != 0) continue; if (strcmp(remote_refname + remote_name_len + 14, GOT_REF_HEAD) != 0) continue; /* * Take the name itself because we already * only match with refs/heads/ in fetch_pack(). */ remote_target = got_ref_get_symref_target(re->ref); remote_head = remote_target + remote_name_len + 14; break; } refname = got_worktree_get_head_ref_name(worktree); if (strncmp(refname, "refs/heads/", 11) == 0) worktree_branch = refname; fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; fpa.verbosity = verbosity; fpa.repo = repo; fpa.create_configs = 0; fpa.configs_created = 0; memset(&fpa.config_info, 0, sizeof(fpa.config_info)); error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, 0, &wanted_branches, &wanted_refs, 0, verbosity, fetchfd, repo, worktree_branch, remote_head, 0, fetch_progress, &fpa); if (error) goto done; if (pack_hash != NULL && verbosity >= 0) { error = got_object_id_str(&id_str, pack_hash); if (error) goto done; printf("\nFetched %s.pack\n", id_str); free(id_str); id_str = NULL; } /* Update references provided with the pack file. */ RB_FOREACH(pe, got_pathlist_head, &refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; struct got_reference *ref; if (is_wanted_ref(&wanted_refs, refname)) { error = update_wanted_ref(refname, id, remote->name, verbosity, repo); if (error) goto done; continue; } error = got_ref_open(&ref, repo, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(refname, id, verbosity, repo); if (error) goto done; } else { error = update_ref(ref, id, replace_tags, verbosity-1, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); if (error) goto done; } } /* Update worktree */ error = got_ref_open(&head_ref, repo, got_worktree_get_head_ref_name(worktree), 0); if (error != NULL) goto done; if (commit_id_str == NULL) { error = got_ref_resolve(&commit_id, repo, head_ref); if (error != NULL) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); free(commit_id_str); commit_id_str = NULL; if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; } error = check_linear_ancestry(commit_id, got_worktree_get_base_commit_id(worktree), 0, repo); if (error != NULL) { if (error->code == GOT_ERR_ANCESTRY) error = got_error(GOT_ERR_BRANCH_MOVED); goto done; } error = check_same_branch(commit_id, head_ref, repo); if (error) goto done; if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree), commit_id) != 0) { error = got_worktree_set_base_commit_id(worktree, repo, commit_id); if (error) goto done; } memset(&upa, 0, sizeof(upa)); upa.verbosity = verbosity; error = got_worktree_checkout_files(worktree, &paths, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { printf("Updated to %s: %s\n", got_worktree_get_head_ref_name(worktree), commit_id_str); } else printf("Already up-to-date\n"); print_update_progress_stats(&upa); done: if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) error = got_error_from_errno("kill"); if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL) error = got_error_from_errno("waitpid"); } if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL); got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&remote_refs); free(id_str); free(worktree_path); free(pack_hash); free(proto); free(host); free(port); free(server_path); free(repo_name); free(commit_id); free(commit_id_str); return error; } static const struct got_error * diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL, *blob2 = NULL; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (blob_id1) { err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192, fd1); if (err) goto done; } err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } while (path[0] == '/') path++; err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, dsa, outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob2) got_object_blob_close(blob2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2, const char *path, int diff_context, int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_diff_blob_output_unidiff_arg arg; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } arg.diff_context = diff_context; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = dsa; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.outfile = outfile; arg.lines = NULL; arg.nlines = 0; while (path[0] == '/') path++; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, path, path, repo, got_diff_blob_output_unidiff, &arg, 1); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static const struct got_error * get_changed_paths(struct got_pathlist_head *paths, struct got_commit_object *commit, struct got_repository *repo, struct got_diffstat_cb_arg *dsa) { const struct got_error *err = NULL; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_object_qid *qid; got_diff_blob_cb cb = got_diff_tree_collect_changed_paths; FILE *f1 = NULL, *f2 = NULL; int fd1 = -1, fd2 = -1; if (dsa) { cb = got_diff_tree_compute_diffstat; f1 = got_opentemp(); if (f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } } qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { struct got_commit_object *pcommit; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; tree_id1 = got_object_id_dup( got_object_commit_get_tree_id(pcommit)); if (tree_id1 == NULL) { got_object_commit_close(pcommit); return got_error_from_errno("got_object_id_dup"); } got_object_commit_close(pcommit); } if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; } tree_id2 = got_object_commit_get_tree_id(commit); err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(tree_id1); return err; } static const struct got_error * print_patch(struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile) { const struct got_error *err = NULL; struct got_commit_object *pcommit = NULL; char *id_str1 = NULL, *id_str2 = NULL; struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL; struct got_object_qid *qid; qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; err = got_object_id_str(&id_str1, &qid->id); if (err) goto done; } err = got_object_id_str(&id_str2, id); if (err) goto done; if (path && path[0] != '\0') { int obj_type; err = got_object_id_by_path(&obj_id2, repo, commit, path); if (err) goto done; if (pcommit) { err = got_object_id_by_path(&obj_id1, repo, pcommit, path); if (err) { if (err->code != GOT_ERR_NO_TREE_ENTRY) { free(obj_id2); goto done; } } } err = got_object_get_type(&obj_type, repo, obj_id2); if (err) { free(obj_id2); goto done; } fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = diff_blobs(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; case GOT_OBJ_TYPE_TREE: err = diff_trees(obj_id1, obj_id2, path, diff_context, 0, 0, dsa, repo, outfile); break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } free(obj_id1); free(obj_id2); } else { obj_id2 = got_object_commit_get_tree_id(commit); if (pcommit) obj_id1 = got_object_commit_get_tree_id(pcommit); fprintf(outfile, "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); fprintf(outfile, "commit - %s\n", id_str1 ? id_str1 : "/dev/null"); fprintf(outfile, "commit + %s\n", id_str2); err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0, dsa, repo, outfile); } done: free(id_str1); free(id_str2); if (pcommit) got_object_commit_close(pcommit); return err; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = gmtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * match_commit(int *have_match, struct got_object_id *id, struct got_commit_object *commit, regex_t *regex) { const struct got_error *err = NULL; regmatch_t regmatch; char *id_str = NULL, *logmsg = NULL; *have_match = 0; err = got_object_id_str(&id_str, id); if (err) return err; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; if (regexec(regex, got_object_commit_get_author(commit), 1, ®match, 0) == 0 || regexec(regex, got_object_commit_get_committer(commit), 1, ®match, 0) == 0 || regexec(regex, id_str, 1, ®match, 0) == 0 || regexec(regex, logmsg, 1, ®match, 0) == 0) *have_match = 1; done: free(id_str); free(logmsg); return err; } static void match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths, regex_t *regex) { regmatch_t regmatch; struct got_pathlist_entry *pe; *have_match = 0; RB_FOREACH(pe, got_pathlist_head, changed_paths) { if (regexec(regex, pe->path, 1, ®match, 0) == 0) { *have_match = 1; break; } } } static const struct got_error * match_patch(int *have_match, struct got_commit_object *commit, struct got_object_id *id, const char *path, int diff_context, struct got_repository *repo, regex_t *regex, FILE *f) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; regmatch_t regmatch; *have_match = 0; err = got_opentemp_truncate(f); if (err) return err; err = print_patch(commit, id, path, diff_context, NULL, repo, f); if (err) goto done; if (fseeko(f, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (getline(&line, &linesize, f) != -1) { if (regexec(regex, line, 1, ®match, 0) == 0) { *have_match = 1; break; } } done: free(line); return err; } #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n" static const struct got_error* build_refs_str(char **refs_str, struct got_reflist_head *refs, struct got_object_id *id, struct got_repository *repo, int local_only) { static const struct got_error *err = NULL; struct got_reflist_entry *re; char *s; const char *name; *refs_str = NULL; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; name = got_ref_get_name(re->ref); if (strcmp(name, GOT_REF_HEAD) == 0) continue; if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { if (local_only) continue; name += 8; s = strstr(name, "/" GOT_REF_HEAD); if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0) continue; } err = got_ref_resolve(&ref_id, repo, re->ref); if (err) break; if (strncmp(name, "tags/", 5) == 0) { err = got_object_open_as_tag(&tag, repo, ref_id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(ref_id); break; } /* Ref points at something other than a tag. */ err = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = *refs_str; if (asprintf(refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { err = got_error_from_errno("asprintf"); free(s); *refs_str = NULL; break; } free(s); } return err; } static const struct got_error * print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, struct got_reflist_object_id_map *refs_idmap) { const struct got_error *err = NULL; char *ref_str = NULL, *id_str = NULL, *logmsg0 = NULL; char *comma, *s, *nl; struct got_reflist_head *refs; char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */ struct tm tm; time_t committer_time; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&ref_str, refs, id, repo, 1); if (err) return err; /* Display the first matching ref only. */ if (ref_str && (comma = strchr(ref_str, ',')) != NULL) *comma = '\0'; } if (ref_str == NULL) { err = got_object_id_str(&id_str, id); if (err) return err; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) { err = got_error_from_errno("gmtime_r"); goto done; } if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; s = logmsg0; while (isspace((unsigned char)s[0])) s++; nl = strchr(s, '\n'); if (nl) { *nl = '\0'; } if (ref_str) printf("%s%-7s %s\n", datebuf, ref_str, s); else printf("%s%.7s %s\n", datebuf, id_str, s); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: free(id_str); free(ref_str); free(logmsg0); return err; } static const struct got_error * print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header) { struct got_pathlist_entry *pe; if (header != NULL) printf("%s\n", header); RB_FOREACH(pe, got_pathlist_head, dsa->paths) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; printf(" %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); } printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); if (fflush(stdout) != 0) return got_error_from_errno("fflush"); return NULL; } static const struct got_error * printfile(FILE *f) { char buf[8192]; size_t r; if (fseeko(f, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); for (;;) { r = fread(buf, 1, sizeof(buf), f); if (r == 0) { if (ferror(f)) return got_error_from_errno("fread"); if (feof(f)) break; } if (fwrite(buf, 1, r, stdout) != r) return got_ferror(stdout, GOT_ERR_IO); } return NULL; } static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, const char *path, struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context, struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str, const char *prefix) { const struct got_error *err = NULL; FILE *f = NULL; char *id_str, *datestr, *logmsg0, *logmsg, *line; char datebuf[26]; time_t committer_time; const char *author, *committer; char *refs_str = NULL; err = got_object_id_str(&id_str, id); if (err) return err; if (custom_refs_str == NULL) { struct got_reflist_head *refs; refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (refs) { err = build_refs_str(&refs_str, refs, id, repo, 0); if (err) goto done; } } printf(GOT_COMMIT_SEP_STR); if (custom_refs_str) printf("%s %s (%s)\n", prefix ? prefix : "commit", id_str, custom_refs_str); else printf("%s %s%s%s%s\n", prefix ? prefix : "commit", id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : ""); free(id_str); id_str = NULL; free(refs_str); refs_str = NULL; printf("from: %s\n", got_object_commit_get_author(commit)); author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) printf("via: %s\n", committer); committer_time = got_object_commit_get_committer_time(commit); datestr = get_datestr(&committer_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int n = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; printf("parent %d: %s\n", n++, id_str); free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; do { line = strsep(&logmsg, "\n"); if (line) printf(" %s\n", line); } while (line); free(logmsg0); if (changed_paths && diffstat == NULL) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, changed_paths) { struct got_diff_changed_path *cp = pe->data; printf(" %c %s\n", cp->status, pe->path); } printf("\n"); } if (show_patch) { if (diffstat) { f = got_opentemp(); if (f == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } } err = print_patch(commit, id, path, diff_context, diffstat, repo, diffstat == NULL ? stdout : f); if (err) goto done; } if (diffstat) { err = print_diffstat(diffstat, NULL); if (err) goto done; if (show_patch) { err = printfile(f); if (err) goto done; } } if (show_patch) printf("\n"); if (fflush(stdout) != 0 && err == NULL) err = got_error_from_errno("fflush"); done: if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(id_str); free(refs_str); return err; } static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, const char *path, int show_changed_paths, int show_diffstat, int show_patch, const char *search_pattern, int diff_context, int limit, int log_branches, int reverse_display_order, struct got_reflist_object_id_map *refs_idmap, int one_line, FILE *tmpfile) { const struct got_error *err; struct got_commit_graph *graph; regex_t regex; int have_match; struct got_object_id_queue reversed_commits; struct got_object_qid *qid; struct got_commit_object *commit; struct got_pathlist_head changed_paths; STAILQ_INIT(&reversed_commits); RB_INIT(&changed_paths); if (search_pattern && regcomp(®ex, search_pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE)) return got_error_msg(GOT_ERR_REGEX, search_pattern); err = got_commit_graph_open(&graph, path, !log_branches); if (err) return err; err = got_commit_graph_bfsort(graph, root_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; if (sigint_received || sigpipe_received) break; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if ((show_changed_paths || (show_diffstat && !show_patch)) && !reverse_display_order) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (search_pattern) { err = match_commit(&have_match, &id, commit, ®ex); if (err) { got_object_commit_close(commit); break; } if (have_match == 0 && show_changed_paths) match_changed_paths(&have_match, &changed_paths, ®ex); if (have_match == 0 && show_patch) { err = match_patch(&have_match, commit, &id, path, diff_context, repo, ®ex, tmpfile); if (err) break; } if (have_match == 0) { got_object_commit_close(commit); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); continue; } } if (reverse_display_order) { err = got_object_qid_alloc(&qid, &id); if (err) break; STAILQ_INSERT_HEAD(&reversed_commits, qid, entry); got_object_commit_close(commit); } else { if (one_line) err = print_commit_oneline(commit, &id, repo, refs_idmap); else err = print_commit(commit, &id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; } if ((limit && --limit == 0) || (end_id && got_object_id_cmp(&id, end_id) == 0)) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } if (reverse_display_order) { STAILQ_FOREACH(qid, &reversed_commits, entry) { struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; if (show_changed_paths || (show_diffstat && !show_patch)) { err = get_changed_paths(&changed_paths, commit, repo, show_diffstat ? &dsa : NULL); if (err) break; } if (one_line) err = print_commit_oneline(commit, &qid->id, repo, refs_idmap); else err = print_commit(commit, &qid->id, repo, path, (show_changed_paths || show_diffstat) ? &changed_paths : NULL, show_diffstat ? &dsa : NULL, show_patch, diff_context, refs_idmap, NULL, NULL); got_object_commit_close(commit); if (err) break; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } } done: got_object_id_queue_free(&reversed_commits); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (search_pattern) regfree(®ex); got_commit_graph_close(graph); return err; } __dead static void usage_log(void) { fprintf(stderr, "usage: %s log [-bdPpRs] [-C number] [-c commit] " "[-l N] [-r repository-path] [-S search-pattern] [-x commit] " "[path]\n", getprogname()); exit(1); } static int get_default_log_limit(void) { const char *got_default_log_limit; long long n; const char *errstr; got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT"); if (got_default_log_limit == NULL) return 0; n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr); if (errstr != NULL) return 0; return n; } static const struct got_error * cmd_log(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *start_id = NULL, *end_id = NULL; char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL; const char *start_commit = NULL, *end_commit = NULL; const char *search_pattern = NULL; int diff_context = -1, ch; int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0; int show_diffstat = 0, reverse_display_order = 0, one_line = 0; const char *errstr; struct got_reflist_head refs; struct got_reflist_object_id_map *refs_idmap = NULL; FILE *tmpfile = NULL; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif limit = get_default_log_limit(); while ((ch = getopt(argc, argv, "bC:c:dl:PpRr:S:sx:")) != -1) { switch (ch) { case 'b': log_branches = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': start_commit = optarg; break; case 'd': show_diffstat = 1; break; case 'l': limit = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "number of commits is %s: %s", errstr, optarg); break; case 'P': show_changed_paths = 1; break; case 'p': show_patch = 1; break; case 'R': reverse_display_order = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'S': search_pattern = optarg; break; case 's': one_line = 1; break; case 'x': end_commit = optarg; break; default: usage_log(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (diff_context == -1) diff_context = 3; else if (!show_patch) errx(1, "-C requires -p"); if (one_line && (show_patch || show_changed_paths || show_diffstat)) errx(1, "cannot use -s with -d, -p or -P"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; error = NULL; } if (argc == 1) { if (worktree) { error = got_worktree_resolve_path(&path, worktree, argv[0]); if (error) goto done; } else { path = strdup(argv[0]); if (path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } else if (argc != 0) usage_log(); if (repo_path == NULL) { repo_path = worktree ? strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd); } if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (error) goto done; if (start_commit == NULL) { struct got_reference *head_ref; struct got_commit_object *commit = NULL; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&start_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; error = got_object_open_as_commit(&commit, repo, start_id); if (error != NULL) goto done; got_object_commit_close(commit); } else { error = got_repo_match_object_id(&start_id, NULL, start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (end_commit != NULL) { error = got_repo_match_object_id(&end_id, NULL, end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error != NULL) goto done; } if (worktree) { /* * If a path was specified on the command line it was resolved * to a path in the work tree above. Prepend the work tree's * path prefix to obtain the corresponding in-repository path. */ if (path) { const char *prefix; prefix = got_worktree_get_path_prefix(worktree); if (asprintf(&in_repo_path, "%s%s%s", prefix, (path[0] != '\0') ? "/" : "", path) == -1) { error = got_error_from_errno("asprintf"); goto done; } } } else error = got_repo_map_path(&in_repo_path, repo, path ? path : ""); if (error != NULL) goto done; if (in_repo_path) { free(path); path = in_repo_path; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } if (search_pattern && show_patch) { tmpfile = got_opentemp(); if (tmpfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } } error = print_commits(start_id, end_id, repo, path ? path : "", show_changed_paths, show_diffstat, show_patch, search_pattern, diff_context, limit, log_branches, reverse_display_order, refs_idmap, one_line, tmpfile); done: free(path); free(repo_path); free(cwd); free(start_id); free(end_id); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (tmpfile && fclose(tmpfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); got_ref_list_free(&refs); return error; } __dead static void usage_diff(void) { fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] " "[-r repository-path] [object1 object2 | path ...]\n", getprogname()); exit(1); } struct print_diff_arg { struct got_repository *repo; struct got_worktree *worktree; struct got_diffstat_cb_arg *diffstat; int diff_context; const char *id_str; int header_shown; int diff_staged; enum got_diff_algorithm diff_algo; int ignore_whitespace; int force_text_diff; FILE *f1; FILE *f2; FILE *outfile; }; /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * print_diff(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct print_diff_arg *a = arg; const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL; int fd = -1, fd1 = -1, fd2 = -1; FILE *f2 = NULL; char *abspath = NULL, *label1 = NULL; struct stat sb; off_t size1 = 0; int f2_exists = 0; memset(&sb, 0, sizeof(sb)); if (a->diff_staged) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (staged_status == GOT_STATUS_DELETE) return NULL; if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(a->f1); if (err) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(a->f2); if (err) return got_error_from_errno("got_opentemp_truncate"); if (!a->header_shown) { if (fprintf(a->outfile, "diff %s%s\n", a->diff_staged ? "-s " : "", got_worktree_get_root_path(a->worktree)) < 0) { err = got_error_from_errno("fprintf"); goto done; } if (fprintf(a->outfile, "commit - %s\n", a->id_str) < 0) { err = got_error_from_errno("fprintf"); goto done; } if (fprintf(a->outfile, "path + %s%s\n", got_worktree_get_root_path(a->worktree), a->diff_staged ? " (staged changes)" : "") < 0) { err = got_error_from_errno("fprintf"); goto done; } a->header_shown = 1; } if (a->diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (staged_status) { case GOT_STATUS_MODIFY: label1 = path; label2 = path; break; case GOT_STATUS_ADD: label2 = path; break; case GOT_STATUS_DELETE: label1 = path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2, fd1, fd2, blob_id, staged_blob_id, label1, label2, a->diff_algo, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->repo, a->outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { char *id_str; err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id, 8192, fd1); if (err) goto done; err = got_object_id_str(&id_str, staged_blob_id); if (err) goto done; if (asprintf(&label1, "%s (staged)", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } else if (status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192, fd1); if (err) goto done; } if (status != GOT_STATUS_DELETE) { if (asprintf(&abspath, "%s/%s", got_worktree_get_root_path(a->worktree), path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err) goto done; } } if (fstatat(fd, abspath, &sb, AT_SYMLINK_NOFOLLOW) == -1) { err = got_error_from_errno2("fstatat", abspath); goto done; } f2 = fdopen(fd, "r"); if (f2 == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; f2_exists = 1; } if (blob1) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, a->f1, blob1); if (err) goto done; } err = got_diff_blob_file(NULL, NULL, blob1, a->f1, size1, label1, f2 ? f2 : a->f2, f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1) got_object_blob_close(blob1); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(abspath); return err; } static const struct got_error * cmd_diff(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; const char *commit_args[2] = { NULL, NULL }; int ncommit_args = 0; struct got_object_id *ids[2] = { NULL, NULL }; char *labels[2] = { NULL, NULL }; int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY; int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i; int force_text_diff = 0, force_path = 0, rflag = 0, show_diffstat = 0; const char *errstr; struct got_reflist_head refs; struct got_pathlist_head diffstat_paths, paths; FILE *f1 = NULL, *f2 = NULL, *outfile = NULL; int fd1 = -1, fd2 = -1; int *pack_fds = NULL; struct got_diffstat_cb_arg dsa; memset(&dsa, 0, sizeof(dsa)); TAILQ_INIT(&refs); RB_INIT(&paths); RB_INIT(&diffstat_paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aC:c:dPr:sw")) != -1) { switch (ch) { case 'a': force_text_diff = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, optarg); break; case 'c': if (ncommit_args >= 2) errx(1, "too many -c options used"); commit_args[ncommit_args++] = optarg; break; case 'd': show_diffstat = 1; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); rflag = 1; break; case 's': diff_staged = 1; break; case 'w': ignore_whitespace = 1; break; default: usage_diff(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; if (show_diffstat) { dsa.paths = &diffstat_paths; dsa.force_text = force_text_diff; dsa.ignore_ws = ignore_whitespace; dsa.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; } if (rflag || worktree == NULL || ncommit_args > 0) { if (force_path) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-P option can only be used when diffing " "a work tree"); goto done; } if (diff_staged) { error = got_error_msg(GOT_ERR_NOT_IMPL, "-s option can only be used when diffing " "a work tree"); goto done; } } error = apply_unveil(got_repo_get_path(repo), 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if ((!force_path && argc == 2) || ncommit_args > 0) { int obj_type = (ncommit_args > 0 ? GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) { const char *arg; if (ncommit_args > 0) arg = commit_args[i]; else arg = argv[i]; error = got_repo_match_object_id(&ids[i], &labels[i], arg, obj_type, &refs, repo); if (error) { if (error->code != GOT_ERR_NOT_REF && error->code != GOT_ERR_NO_OBJ) goto done; if (ncommit_args > 0) goto done; error = NULL; break; } } } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } outfile = got_opentemp(); if (outfile == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) { struct print_diff_arg arg; char *id_str; if (worktree == NULL) { if (argc == 2 && ids[0] == NULL) { error = got_error_path(argv[0], GOT_ERR_NO_OBJ); goto done; } else if (argc == 2 && ids[1] == NULL) { error = got_error_path(argv[1], GOT_ERR_NO_OBJ); goto done; } else if (argc > 0) { error = got_error_fmt(GOT_ERR_NOT_WORKTREE, "%s", "specified paths cannot be resolved"); goto done; } else { error = got_error(GOT_ERR_NOT_WORKTREE); goto done; } } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; arg.repo = repo; arg.worktree = worktree; arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; arg.diff_context = diff_context; arg.id_str = id_str; arg.header_shown = 0; arg.diff_staged = diff_staged; arg.ignore_whitespace = ignore_whitespace; arg.force_text_diff = force_text_diff; arg.diffstat = show_diffstat ? &dsa : NULL; arg.f1 = f1; arg.f2 = f2; arg.outfile = outfile; error = got_worktree_status(worktree, &paths, repo, 0, print_diff, &arg, check_cancelled, NULL); free(id_str); if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header; if (asprintf(&header, "diffstat %s%s", diff_staged ? "-s " : "", got_worktree_get_root_path(worktree)) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); goto done; } if (ncommit_args == 1) { struct got_commit_object *commit; error = got_object_open_as_commit(&commit, repo, ids[0]); if (error) goto done; labels[1] = labels[0]; ids[1] = ids[0]; if (got_object_commit_get_nparents(commit) > 0) { const struct got_object_id_queue *pids; struct got_object_qid *pid; pids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(pids); ids[0] = got_object_id_dup(&pid->id); if (ids[0] == NULL) { error = got_error_from_errno( "got_object_id_dup"); got_object_commit_close(commit); goto done; } error = got_object_id_str(&labels[0], ids[0]); if (error) { got_object_commit_close(commit); goto done; } } else { ids[0] = NULL; labels[0] = strdup("/dev/null"); if (labels[0] == NULL) { error = got_error_from_errno("strdup"); got_object_commit_close(commit); goto done; } } got_object_commit_close(commit); } if (ncommit_args == 0 && argc > 2) { error = got_error_msg(GOT_ERR_BAD_PATH, "path arguments cannot be used when diffing two objects"); goto done; } if (ids[0]) { error = got_object_get_type(&type1, repo, ids[0]); if (error) goto done; } error = got_object_get_type(&type2, repo, ids[1]); if (error) goto done; if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) { error = got_error_msg(GOT_ERR_OBJ_TYPE, "path arguments cannot be used when diffing blobs"); goto done; } for (i = 0; ncommit_args > 0 && i < argc; i++) { char *in_repo_path; struct got_pathlist_entry *new; if (worktree) { const char *prefix; char *p; error = got_worktree_resolve_path(&p, worktree, argv[i]); if (error) goto done; prefix = got_worktree_get_path_prefix(worktree); while (prefix[0] == '/') prefix++; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && prefix[0] != '\0') ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); } else { char *mapped_path, *s; error = got_repo_map_path(&mapped_path, repo, argv[i]); if (error) goto done; s = mapped_path; while (s[0] == '/') s++; in_repo_path = strdup(s); if (in_repo_path == NULL) { error = got_error_from_errno("asprintf"); free(mapped_path); goto done; } free(mapped_path); } error = got_pathlist_insert(&new, &paths, in_repo_path, NULL); if (error || new == NULL /* duplicate */) free(in_repo_path); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } fd1 = got_opentempfd(); if (fd1 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, "", "", GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "diff %s %s\n", labels[0], labels[1]); error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd1, fd2, ids[0], ids[1], &paths, GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace, force_text_diff, show_diffstat ? &dsa : NULL, repo, outfile); break; default: error = got_error(GOT_ERR_OBJ_TYPE); } if (error) goto done; if (show_diffstat && dsa.nfiles > 0) { char *header = NULL; if (asprintf(&header, "diffstat %s %s", labels[0], labels[1]) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = print_diffstat(&dsa, header); free(header); if (error) goto done; } error = printfile(outfile); done: free(labels[0]); free(labels[1]); free(ids[0]); free(ids[1]); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); got_pathlist_free(&diffstat_paths, GOT_PATHLIST_FREE_ALL); got_ref_list_free(&refs); if (outfile && fclose(outfile) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } __dead static void usage_blame(void) { fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n", getprogname()); exit(1); } struct blame_line { int annotated; char *id_str; char *committer; char datebuf[11]; /* YYYY-MM-DD + NUL */ }; struct blame_cb_args { struct blame_line *lines; int nlines; int nlines_prec; int lineno_cur; off_t *line_offsets; FILE *f; struct got_repository *repo; }; static const struct got_error * blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct blame_cb_args *a = arg; struct blame_line *bline; char *line = NULL; size_t linesize = 0; off_t offset; struct tm tm; time_t committer_time; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); if (sigint_received) return got_error(GOT_ERR_ITER_COMPLETED); if (lineno == -1) return NULL; /* no change in this commit */ /* Annotate this line. */ bline = &a->lines[lineno - 1]; if (bline->annotated) return NULL; err = got_object_id_str(&bline->id_str, id); if (err) return err; bline->committer = strdup(got_object_commit_get_committer(commit)); if (bline->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(bline->datebuf, sizeof(bline->datebuf), "%F", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } bline->annotated = 1; /* Print lines annotated so far. */ bline = &a->lines[a->lineno_cur - 1]; if (!bline->annotated) goto done; offset = a->line_offsets[a->lineno_cur - 1]; if (fseeko(a->f, offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (a->lineno_cur <= a->nlines && bline->annotated) { char *smallerthan, *at, *nl, *committer; size_t len; if (getline(&line, &linesize, a->f) == -1) { if (ferror(a->f)) err = got_error_from_errno("getline"); break; } committer = bline->committer; smallerthan = strchr(committer, '<'); if (smallerthan && smallerthan[1] != '\0') committer = smallerthan + 1; at = strchr(committer, '@'); if (at) *at = '\0'; len = strlen(committer); if (len >= 9) committer[8] = '\0'; nl = strchr(line, '\n'); if (nl) *nl = '\0'; printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur, bline->id_str, bline->datebuf, committer, line); a->lineno_cur++; bline = &a->lines[a->lineno_cur - 1]; } done: free(line); return err; } static const struct got_error * cmd_blame(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *link_target = NULL; struct got_object_id *obj_id = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL; char *commit_id_str = NULL; struct blame_cb_args bca; int ch, obj_type, i, fd1 = -1, fd2 = -1, fd3 = -1; off_t filesize; int *pack_fds = NULL; FILE *f1 = NULL, *f2 = NULL; fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); memset(&bca, 0, sizeof(bca)); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_blame(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else usage_blame(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); if (error) goto done; } } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_repo_map_path(&in_repo_path, repo, path); } if (error) goto done; if (commit_id_str == NULL) { struct got_reference *head_ref; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_resolve_symlinks(&link_target, in_repo_path, commit, repo); if (error) goto done; error = got_object_id_by_path(&obj_id, repo, commit, link_target ? link_target : in_repo_path); if (error) goto done; error = got_object_get_type(&obj_type, repo, obj_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error_path(link_target ? link_target : in_repo_path, GOT_ERR_OBJ_TYPE); goto done; } error = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1); if (error) goto done; bca.f = got_opentemp(); if (bca.f == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_object_blob_dump_to_file(&filesize, &bca.nlines, &bca.line_offsets, bca.f, blob); if (error || bca.nlines == 0) goto done; /* Don't include \n at EOF in the blame line count. */ if (bca.line_offsets[bca.nlines - 1] == filesize) bca.nlines--; bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); if (bca.lines == NULL) { error = got_error_from_errno("calloc"); goto done; } bca.lineno_cur = 1; bca.nlines_prec = 0; i = bca.nlines; while (i > 0) { i /= 10; bca.nlines_prec++; } bca.repo = repo; fd2 = got_opentempfd(); if (fd2 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } fd3 = got_opentempfd(); if (fd3 == -1) { error = got_error_from_errno("got_opentempfd"); goto done; } f1 = got_opentemp(); if (f1 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { error = got_error_from_errno("got_opentemp"); goto done; } error = got_blame(link_target ? link_target : in_repo_path, commit_id, repo, GOT_DIFF_ALGORITHM_PATIENCE, blame_cb, &bca, check_cancelled, NULL, fd2, fd3, f1, f2); done: free(in_repo_path); free(link_target); free(repo_path); free(cwd); free(commit_id); free(obj_id); if (commit) got_object_commit_close(commit); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd3 != -1 && close(fd3) == -1 && error == NULL) error = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (blob) got_object_blob_close(blob); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (bca.lines) { for (i = 0; i < bca.nlines; i++) { struct blame_line *bline = &bca.lines[i]; free(bline->id_str); free(bline->committer); } free(bca.lines); } free(bca.line_offsets); if (bca.f && fclose(bca.f) == EOF && error == NULL) error = got_error_from_errno("fclose"); return error; } __dead static void usage_tree(void) { fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] " "[path]\n", getprogname()); exit(1); } static const struct got_error * print_entry(struct got_tree_entry *te, const char *id, const char *path, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; int is_root_path = (strcmp(path, root_path) == 0); const char *modestr = ""; mode_t mode = got_tree_entry_get_mode(te); char *link_target = NULL; path += strlen(root_path); while (path[0] == '/') path++; if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) { int i; err = got_tree_entry_get_symlink_target(&link_target, te, repo); if (err) return err; for (i = 0; link_target[i] != '\0'; i++) { if (!isprint((unsigned char)link_target[i])) link_target[i] = '?'; } modestr = "@"; } else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; printf("%s%s%s%s%s%s%s\n", id ? id : "", path, is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr, link_target ? " -> ": "", link_target ? link_target : ""); free(link_target); return NULL; } static const struct got_error * print_tree(const char *path, struct got_commit_object *commit, int show_ids, int recurse, const char *root_path, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *tree_id = NULL; struct got_tree_object *tree = NULL; int nentries, i; err = got_object_id_by_path(&tree_id, repo, commit, path); if (err) goto done; err = got_object_open_as_tree(&tree, repo, tree_id); if (err) goto done; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id = NULL; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); if (show_ids) { char *id_str; err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) goto done; if (asprintf(&id, "%s ", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } err = print_entry(te, id, path, root_path, repo); free(id); if (err) goto done; if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) { char *child_path; if (asprintf(&child_path, "%s%s%s", path, path[0] == '/' && path[1] == '\0' ? "" : "/", got_tree_entry_get_name(te)) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = print_tree(child_path, commit, show_ids, 1, root_path, repo); free(child_path); if (err) goto done; } } done: if (tree) got_object_tree_close(tree); free(tree_id); return err; } static const struct got_error * cmd_tree(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; const char *path, *refname = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; char *commit_id_str = NULL; int show_ids = 0, recurse = 0; int ch; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:iRr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'i': show_ids = 1; break; case 'R': recurse = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_tree(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 1) path = argv[0]; else if (argc > 1) usage_tree(); else path = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; if (path == NULL || got_path_is_root_dir(path)) path = ""; error = got_worktree_resolve_path(&p, worktree, path); if (error) goto done; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; } else { error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; if (path == NULL) path = "/"; error = got_repo_map_path(&in_repo_path, repo, path); if (error != NULL) goto done; } if (commit_id_str == NULL) { struct got_reference *head_ref; if (worktree) refname = got_worktree_get_head_ref_name(worktree); else refname = GOT_REF_HEAD; error = got_ref_open(&head_ref, repo, refname, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error != NULL) goto done; } else { struct got_reflist_head refs; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); got_ref_list_free(&refs); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = print_tree(in_repo_path, commit, show_ids, recurse, in_repo_path, repo); done: free(in_repo_path); free(repo_path); free(cwd); free(commit_id); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_status(void) { fprintf(stderr, "usage: %s status [-I] [-S status-codes] " "[-s status-codes] [path ...]\n", getprogname()); exit(1); } struct got_status_arg { char *status_codes; int suppress; }; static const struct got_error * print_status(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct got_status_arg *st = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (st != NULL && st->status_codes) { size_t ncodes = strlen(st->status_codes); int i, j = 0; for (i = 0; i < ncodes ; i++) { if (st->suppress) { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) { j++; continue; } } else { if (status == st->status_codes[i] || staged_status == st->status_codes[i]) break; } } if (st->suppress && j == 0) goto print; if (i == ncodes) return NULL; } print: printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * cmd_status(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_status_arg st; char *cwd = NULL; struct got_pathlist_head paths; int ch, i, no_ignores = 0; int *pack_fds = NULL; RB_INIT(&paths); memset(&st, 0, sizeof(st)); st.status_codes = NULL; st.suppress = 0; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IS:s:")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'S': if (st.status_codes != NULL && st.suppress == 0) option_conflict('S', 's'); st.suppress = 1; /* fallthrough */ case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_CONFLICT: case GOT_STATUS_MISSING: case GOT_STATUS_OBSTRUCTED: case GOT_STATUS_UNVERSIONED: case GOT_STATUS_MODE_CHANGE: case GOT_STATUS_NONEXISTENT: break; default: errx(1, "invalid status code '%c'", optarg[i]); } } if (ch == 's' && st.suppress) option_conflict('s', 'S'); st.status_codes = optarg; break; default: usage_status(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "status", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; error = got_worktree_status(worktree, &paths, repo, no_ignores, print_status, &st, check_cancelled, NULL); done: if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_tag(void) { fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] " "[-r repository-path] [-s signer-id] name\n", getprogname()); exit(1); } #if 0 static const struct got_error * sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags) { const struct got_error *err = NULL; struct got_reflist_entry *re, *se, *new; struct got_object_id *re_id, *se_id; struct got_tag_object *re_tag, *se_tag; time_t re_time, se_time; STAILQ_FOREACH(re, tags, entry) { se = STAILQ_FIRST(sorted); if (se == NULL) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_HEAD(sorted, new, entry); continue; } else { err = got_ref_resolve(&re_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&re_tag, repo, re_id); free(re_id); if (err) break; re_time = got_object_tag_get_tagger_time(re_tag); got_object_tag_close(re_tag); } while (se) { err = got_ref_resolve(&se_id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&se_tag, repo, se_id); free(se_id); if (err) break; se_time = got_object_tag_get_tagger_time(se_tag); got_object_tag_close(se_tag); if (se_time > re_time) { err = got_reflist_entry_dup(&new, re); if (err) return err; STAILQ_INSERT_AFTER(sorted, se, new, entry); break; } se = STAILQ_NEXT(se, entry); continue; } } done: return err; } #endif static const struct got_error * get_tag_refname(char **refname, const char *tag_name) { const struct got_error *err; if (strncmp("refs/tags/", tag_name, 10) == 0) { *refname = strdup(tag_name); if (*refname == NULL) return got_error_from_errno("strdup"); } else if (asprintf(refname, "refs/tags/%s", tag_name) == -1) { err = got_error_from_errno("asprintf"); *refname = NULL; return err; } return NULL; } static const struct got_error * list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, const char *allowed_signers, const char *revoked_signers, int verbosity) { static const struct got_error *err = NULL; struct got_reflist_head refs; struct got_reflist_entry *re; char *wanted_refname = NULL; int bad_sigs = 0; TAILQ_INIT(&refs); err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo); if (err) return err; if (tag_name) { struct got_reference *ref; err = get_tag_refname(&wanted_refname, tag_name); if (err) goto done; /* Wanted tag reference should exist. */ err = got_ref_open(&ref, repo, wanted_refname, 0); if (err) goto done; got_ref_close(ref); } TAILQ_FOREACH(re, &refs, entry) { const char *refname; char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr; char datebuf[26]; const char *tagger, *ssh_sig = NULL; char *sig_msg = NULL; time_t tagger_time; struct got_object_id *id; struct got_tag_object *tag; struct got_commit_object *commit = NULL; refname = got_ref_get_name(re->ref); if (strncmp(refname, "refs/tags/", 10) != 0 || (wanted_refname && strcmp(refname, wanted_refname) != 0)) continue; refname += 10; refstr = got_ref_to_str(re->ref); if (refstr == NULL) { err = got_error_from_errno("got_ref_to_str"); break; } err = got_ref_resolve(&id, repo, re->ref); if (err) break; err = got_object_open_as_tag(&tag, repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(id); break; } /* "lightweight" tag */ err = got_object_open_as_commit(&commit, repo, id); if (err) { free(id); break; } tagger = got_object_commit_get_committer(commit); tagger_time = got_object_commit_get_committer_time(commit); err = got_object_id_str(&id_str, id); free(id); if (err) break; } else { free(id); tagger = got_object_tag_get_tagger(tag); tagger_time = got_object_tag_get_tagger_time(tag); err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) break; } if (tag && verify_tags) { ssh_sig = got_sigs_get_tagmsg_ssh_signature( got_object_tag_get_message(tag)); if (ssh_sig && allowed_signers == NULL) { err = got_error_msg( GOT_ERR_VERIFY_TAG_SIGNATURE, "SSH signature verification requires " "setting allowed_signers in " "got.conf(5)"); break; } } printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); free(refstr); printf("from: %s\n", tagger); datestr = get_datestr(&tagger_time, datebuf); if (datestr) printf("date: %s UTC\n", datestr); if (commit) printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); else { switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); break; case GOT_OBJ_TYPE_TREE: printf("object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); break; case GOT_OBJ_TYPE_COMMIT: printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); break; case GOT_OBJ_TYPE_TAG: printf("object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); break; default: break; } } free(id_str); if (ssh_sig) { err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, allowed_signers, revoked_signers, verbosity); if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE) bad_sigs = 1; else if (err) break; printf("signature: %s", sig_msg); free(sig_msg); sig_msg = NULL; } if (commit) { err = got_object_commit_get_logmsg(&tagmsg0, commit); if (err) break; got_object_commit_close(commit); } else { tagmsg0 = strdup(got_object_tag_get_message(tag)); got_object_tag_close(tag); if (tagmsg0 == NULL) { err = got_error_from_errno("strdup"); break; } } tagmsg = tagmsg0; do { line = strsep(&tagmsg, "\n"); if (line) printf(" %s\n", line); } while (line); free(tagmsg0); } done: got_ref_list_free(&refs); free(wanted_refname); if (err == NULL && bad_sigs) err = got_error(GOT_ERR_BAD_TAG_SIGNATURE); return err; } static const struct got_error * get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str, const char *tag_name, const char *repo_path) { const struct got_error *err = NULL; char *template = NULL, *initial_content = NULL; char *editor = NULL; int initial_content_len; int fd = -1; if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) { err = got_error_from_errno("asprintf"); goto done; } initial_content_len = asprintf(&initial_content, "\n# tagging commit %s as %s\n", commit_id_str, tag_name); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(tagmsg_path, &fd, template, ""); if (err) goto done; if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", *tagmsg_path); goto done; } if (close(fd) == -1) { err = got_error_from_errno2("close", *tagmsg_path); goto done; } fd = -1; err = get_editor(&editor); if (err) goto done; err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content, initial_content_len, 1); done: free(initial_content); free(template); free(editor); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", *tagmsg_path); if (err) { free(*tagmsg); *tagmsg = NULL; } return err; } static const struct got_error * add_tag(struct got_repository *repo, const char *tagger, const char *tag_name, const char *commit_arg, const char *tagmsg_arg, const char *signer_id, int verbosity) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL, *tag_id = NULL; char *label = NULL, *commit_id_str = NULL; struct got_reference *ref = NULL; char *refname = NULL, *tagmsg = NULL; char *tagmsg_path = NULL, *tag_id_str = NULL; int preserve_tagmsg = 0; struct got_reflist_head refs; TAILQ_INIT(&refs); /* * Don't let the user create a tag name with a leading '-'. * While technically a valid reference name, this case is usually * an unintended typo. */ if (tag_name[0] == '-') return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; err = got_repo_match_object_id(&commit_id, &label, commit_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (err) goto done; err = got_object_id_str(&commit_id_str, commit_id); if (err) goto done; err = get_tag_refname(&refname, tag_name); if (err) goto done; if (strncmp("refs/tags/", tag_name, 10) == 0) tag_name += 10; err = got_ref_open(&ref, repo, refname, 0); if (err == NULL) { err = got_error(GOT_ERR_TAG_EXISTS); goto done; } else if (err->code != GOT_ERR_NOT_REF) goto done; if (tagmsg_arg == NULL) { err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str, tag_name, got_repo_get_path(repo)); if (err) { if (err->code != GOT_ERR_COMMIT_MSG_EMPTY && tagmsg_path != NULL) preserve_tagmsg = 1; goto done; } /* Editor is done; we can now apply unveil(2) */ err = got_sigs_apply_unveil(); if (err) goto done; err = apply_unveil(got_repo_get_path(repo), 0, NULL); if (err) goto done; } err = got_object_tag_create(&tag_id, tag_name, commit_id, tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, signer_id, repo, verbosity); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_alloc(&ref, refname, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_ref_write(ref, repo); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } err = got_object_id_str(&tag_id_str, tag_id); if (err) { if (tagmsg_path) preserve_tagmsg = 1; goto done; } printf("Created tag %s\n", tag_id_str); done: if (preserve_tagmsg) { fprintf(stderr, "%s: tag message preserved in %s\n", getprogname(), tagmsg_path); } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL) err = got_error_from_errno2("unlink", tagmsg_path); free(tag_id_str); if (ref) got_ref_close(ref); free(commit_id); free(commit_id_str); free(refname); free(tagmsg); free(tagmsg_path); got_ref_list_free(&refs); return err; } static const struct got_error * cmd_tag(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL; char *gitconfig_path = NULL, *tagger = NULL; char *allowed_signers = NULL, *revoked_signers = NULL; const char *signer_id = NULL; const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; int ch, do_list = 0, verify_tags = 0, verbosity = 0; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:lm:r:s:Vv")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'l': do_list = 1; break; case 'm': tagmsg = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) { error = got_error_from_errno2("realpath", optarg); goto done; } got_path_strip_trailing_slashes(repo_path); break; case 's': signer_id = optarg; break; case 'V': verify_tags = 1; break; case 'v': if (verbosity < 0) verbosity = 0; else if (verbosity < 3) verbosity++; break; default: usage_tag(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (do_list || verify_tags) { if (commit_id_arg != NULL) errx(1, "-c option can only be used when creating a tag"); if (tagmsg) { if (do_list) option_conflict('l', 'm'); else option_conflict('V', 'm'); } if (signer_id) { if (do_list) option_conflict('l', 's'); else option_conflict('V', 's'); } if (argc > 1) usage_tag(); } else if (argc != 1) usage_tag(); if (argc == 1) tag_name = argv[0]; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; else error = NULL; if (worktree) { repo_path = strdup(got_worktree_get_repo_path(worktree)); if (repo_path == NULL) error = got_error_from_errno("strdup"); if (error) goto done; } else { repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } } if (do_list || verify_tags) { error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_allowed_signers(&allowed_signers, repo, worktree); if (error) goto done; error = get_revoked_signers(&revoked_signers, repo, worktree); if (error) goto done; if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } /* * Remove "cpath" promise unless needed for signature tmpfile * creation. */ if (verify_tags) got_sigs_apply_unveil(); else { #ifndef PROFILE if (pledge("stdio rpath wpath flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif } error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = list_tags(repo, tag_name, verify_tags, allowed_signers, revoked_signers, verbosity); } else { error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds); if (error != NULL) goto done; error = get_author(&tagger, repo, worktree); if (error) goto done; if (signer_id == NULL) signer_id = get_signer_id(repo, worktree); if (tagmsg) { if (signer_id) { error = got_sigs_apply_unveil(); if (error) goto done; } error = apply_unveil(got_repo_get_path(repo), 0, NULL); if (error) goto done; } if (commit_id_arg == NULL) { struct got_reference *head_ref; struct got_object_id *commit_id; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); free(commit_id); if (error) goto done; } if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = add_tag(repo, tagger, tag_name, commit_id_str ? commit_id_str : commit_id_arg, tagmsg, signer_id, verbosity); } done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); free(repo_path); free(gitconfig_path); free(commit_id_str); free(tagger); free(allowed_signers); free(revoked_signers); return error; } __dead static void usage_add(void) { fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname()); exit(1); } static const struct got_error * add_progress(void *arg, unsigned char status, const char *path) { while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } static const struct got_error * cmd_add(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, no_ignores = 0; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "IR")) != -1) { switch (ch) { case 'I': no_ignores = 1; break; case 'R': can_recurse = 1; break; default: usage_add(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_add(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "add", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "adding directories requires -R option"); goto done; } } } error = got_worktree_schedule_add(worktree, &paths, add_progress, NULL, repo, no_ignores); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_remove(void) { fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n", getprogname()); exit(1); } static const struct got_error * print_remove_status(void *arg, unsigned char status, unsigned char staged_status, const char *path) { while (path[0] == '/') path++; if (status == GOT_STATUS_NONEXISTENT) return NULL; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; printf("%c%c %s\n", status, staged_status, path); return NULL; } static const struct got_error * cmd_remove(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; const char *status_codes = NULL; char *cwd = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i; int ignore_missing_paths = 0; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "fkRs:")) != -1) { switch (ch) { case 'f': delete_local_mods = 1; ignore_missing_paths = 1; break; case 'k': keep_on_disk = 1; break; case 'R': can_recurse = 1; break; case 's': for (i = 0; optarg[i] != '\0'; i++) { switch (optarg[i]) { case GOT_STATUS_MODIFY: delete_local_mods = 1; break; case GOT_STATUS_MISSING: ignore_missing_paths = 1; break; default: errx(1, "invalid status code '%c'", optarg[i]); } } status_codes = optarg; break; default: usage_remove(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_remove(); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "remove", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "removing directories requires -R option"); goto done; } } } error = got_worktree_schedule_delete(worktree, &paths, delete_local_mods, status_codes, print_remove_status, NULL, repo, keep_on_disk, ignore_missing_paths); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); return error; } __dead static void usage_patch(void) { fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] " "[patchfile]\n", getprogname()); exit(1); } static const struct got_error * patch_from_stdin(int *patchfd) { const struct got_error *err = NULL; ssize_t r; char buf[BUFSIZ]; sig_t sighup, sigint, sigquit; *patchfd = got_opentempfd(); if (*patchfd == -1) return got_error_from_errno("got_opentempfd"); sighup = signal(SIGHUP, SIG_DFL); sigint = signal(SIGINT, SIG_DFL); sigquit = signal(SIGQUIT, SIG_DFL); for (;;) { r = read(0, buf, sizeof(buf)); if (r == -1) { err = got_error_from_errno("read"); break; } if (r == 0) break; if (write(*patchfd, buf, r) == -1) { err = got_error_from_errno("write"); break; } } signal(SIGHUP, sighup); signal(SIGINT, sigint); signal(SIGQUIT, sigquit); if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1) err = got_error_from_errno("lseek"); if (err != NULL) { close(*patchfd); *patchfd = -1; } return err; } struct got_patch_progress_arg { int did_something; int conflicts; int rejects; }; static const struct got_error * patch_progress(void *arg, const char *old, const char *new, unsigned char status, const struct got_error *error, int old_from, int old_lines, int new_from, int new_lines, int offset, int ws_mangled, const struct got_error *hunk_err) { const char *path = new == NULL ? old : new; struct got_patch_progress_arg *a = arg; while (*path == '/') path++; if (status != GOT_STATUS_NO_CHANGE && status != 0 /* per-hunk progress */) { printf("%c %s\n", status, path); a->did_something = 1; } if (hunk_err == NULL) { if (status == GOT_STATUS_CANNOT_UPDATE) a->rejects++; else if (status == GOT_STATUS_CONFLICT) a->conflicts++; } if (error != NULL) fprintf(stderr, "%s: %s\n", getprogname(), error->msg); if (offset != 0 || hunk_err != NULL || ws_mangled) { printf("@@ -%d,%d +%d,%d @@ ", old_from, old_lines, new_from, new_lines); if (hunk_err != NULL) printf("%s\n", hunk_err->msg); else if (offset != 0) printf("applied with offset %d\n", offset); else printf("hunk contains mangled whitespace\n"); } return NULL; } static void print_patch_progress_stats(struct got_patch_progress_arg *ppa) { if (!ppa->did_something) return; if (ppa->conflicts > 0) printf("Files with merge conflicts: %d\n", ppa->conflicts); if (ppa->rejects > 0) { printf("Files where patch failed to apply: %d\n", ppa->rejects); } } static const struct got_error * cmd_patch(int argc, char *argv[]) { const struct got_error *error = NULL, *close_error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; struct got_reflist_head refs; struct got_object_id *commit_id = NULL; const char *commit_id_str = NULL; struct stat sb; const char *errstr; char *cwd = NULL; int ch, nop = 0, strip = -1, reverse = 0; int patchfd; int *pack_fds = NULL; struct got_patch_progress_arg ppa; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:np:R")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'n': nop = 1; break; case 'p': strip = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "pathname strip count is %s: %s", errstr, optarg); break; case 'R': reverse = 1; break; default: usage_patch(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc == 0) { error = patch_from_stdin(&patchfd); if (error) return error; } else if (argc == 1) { patchfd = open(argv[0], O_RDONLY); if (patchfd == -1) return got_error_from_errno2("open", argv[0]); if (fstat(patchfd, &sb) == -1) { error = got_error_from_errno2("fstat", argv[0]); goto done; } if (!S_ISREG(sb.st_mode)) { error = got_error_path(argv[0], GOT_ERR_BAD_FILETYPE); goto done; } } else usage_patch(); if ((cwd = getcwd(NULL, 0)) == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error != NULL) goto done; const char *repo_path = got_worktree_get_repo_path(worktree); error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error != NULL) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str != NULL) { error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; } memset(&ppa, 0, sizeof(ppa)); error = got_patch(patchfd, worktree, repo, nop, strip, reverse, commit_id, patch_progress, &ppa, check_cancelled, NULL); print_patch_progress_stats(&ppa); done: got_ref_list_free(&refs); free(commit_id); if (repo) { close_error = got_repo_close(repo); if (error == NULL) error = close_error; } if (worktree != NULL) { close_error = got_worktree_close(worktree); if (error == NULL) error = close_error; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(cwd); return error; } __dead static void usage_revert(void) { fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n", getprogname()); exit(1); } static const struct got_error * revert_progress(void *arg, unsigned char status, const char *path) { if (status == GOT_STATUS_UNVERSIONED) return NULL; while (path[0] == '/') path++; printf("%c %s\n", status, path); return NULL; } struct choose_patch_arg { FILE *patch_script_file; const char *action; }; static const struct got_error * show_change(unsigned char status, const char *path, FILE *patch_file, int n, int nchanges, const char *action) { const struct got_error *err; char *line = NULL; size_t linesize = 0; ssize_t linelen; switch (status) { case GOT_STATUS_ADD: printf("A %s\n%s this addition? [y/n] ", path, action); break; case GOT_STATUS_DELETE: printf("D %s\n%s this deletion? [y/n] ", path, action); break; case GOT_STATUS_MODIFY: if (fseek(patch_file, 0L, SEEK_SET) == -1) return got_error_from_errno("fseek"); printf(GOT_COMMIT_SEP_STR); while ((linelen = getline(&line, &linesize, patch_file)) != -1) printf("%s", line); if (linelen == -1 && ferror(patch_file)) { err = got_error_from_errno("getline"); free(line); return err; } free(line); printf(GOT_COMMIT_SEP_STR); printf("M %s (change %d of %d)\n%s this change? [y/n/q] ", path, n, nchanges, action); break; default: return got_error_path(path, GOT_ERR_FILE_STATUS); } fflush(stdout); return NULL; } static const struct got_error * choose_patch(int *choice, void *arg, unsigned char status, const char *path, FILE *patch_file, int n, int nchanges) { const struct got_error *err = NULL; char *line = NULL; size_t linesize = 0; ssize_t linelen; int resp = ' '; struct choose_patch_arg *a = arg; *choice = GOT_PATCH_CHOICE_NONE; if (a->patch_script_file) { char *nl; err = show_change(status, path, patch_file, n, nchanges, a->action); if (err) return err; linelen = getline(&line, &linesize, a->patch_script_file); if (linelen == -1) { if (ferror(a->patch_script_file)) return got_error_from_errno("getline"); return NULL; } nl = strchr(line, '\n'); if (nl) *nl = '\0'; if (strcmp(line, "y") == 0) { *choice = GOT_PATCH_CHOICE_YES; printf("y\n"); } else if (strcmp(line, "n") == 0) { *choice = GOT_PATCH_CHOICE_NO; printf("n\n"); } else if (strcmp(line, "q") == 0 && status == GOT_STATUS_MODIFY) { *choice = GOT_PATCH_CHOICE_QUIT; printf("q\n"); } else printf("invalid response '%s'\n", line); free(line); return NULL; } while (resp != 'y' && resp != 'n' && resp != 'q') { err = show_change(status, path, patch_file, n, nchanges, a->action); if (err) return err; resp = getchar(); if (resp == '\n') resp = getchar(); if (status == GOT_STATUS_MODIFY) { if (resp != 'y' && resp != 'n' && resp != 'q') { printf("invalid response '%c'\n", resp); resp = ' '; } } else if (resp != 'y' && resp != 'n') { printf("invalid response '%c'\n", resp); resp = ' '; } } if (resp == 'y') *choice = GOT_PATCH_CHOICE_YES; else if (resp == 'n') *choice = GOT_PATCH_CHOICE_NO; else if (resp == 'q' && status == GOT_STATUS_MODIFY) *choice = GOT_PATCH_CHOICE_QUIT; return NULL; } struct wt_commitable_path_arg { struct got_pathlist_head *commit_paths; int *has_changes; }; /* * Shortcut work tree status callback to determine if the set of paths scanned * has at least one versioned path that is being modified and, if not NULL, is * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as * soon as a path is passed with a status that satisfies this criteria. */ static const struct got_error * worktree_has_commitable_path(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { struct wt_commitable_path_arg *a = arg; if (status == staged_status && (status == GOT_STATUS_DELETE)) status = GOT_STATUS_NO_CHANGE; if (!(status == GOT_STATUS_NO_CHANGE || status == GOT_STATUS_UNVERSIONED) || staged_status != GOT_STATUS_NO_CHANGE) { if (a->commit_paths != NULL) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, a->commit_paths) { if (strncmp(path, pe->path, pe->path_len) == 0) { *a->has_changes = 1; break; } } } else *a->has_changes = 1; if (*a->has_changes) return got_error(GOT_ERR_FILE_MODIFIED); } return NULL; } /* * Check that the changeset of the commit identified by id is * comprised of at least one modified path that is being committed. */ static const struct got_error * commit_path_changed_in_worktree(struct wt_commitable_path_arg *wcpa, struct got_object_id *id, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_commit_object *commit = NULL, *pcommit = NULL; struct got_tree_object *tree = NULL, *ptree = NULL; struct got_object_qid *pid; RB_INIT(&paths); err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; err = got_object_open_as_tree(&tree, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid != NULL) { err = got_object_open_as_commit(&pcommit, repo, &pid->id); if (err) goto done; err = got_object_open_as_tree(&ptree, repo, got_object_commit_get_tree_id(pcommit)); if (err) goto done; } err = got_diff_tree(ptree, tree, NULL, NULL, -1, -1, "", "", repo, got_diff_tree_collect_changed_paths, &paths, 0); if (err) goto done; err = got_worktree_status(worktree, &paths, repo, 0, worktree_has_commitable_path, wcpa, check_cancelled, NULL); if (err && err->code == GOT_ERR_FILE_MODIFIED) { /* * At least one changed path in the referenced commit is * modified in the work tree, that's all we need to know! */ err = NULL; } done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (commit) got_object_commit_close(commit); if (pcommit) got_object_commit_close(pcommit); if (tree) got_object_tree_close(tree); if (ptree) got_object_tree_close(ptree); return err; } /* * Remove any "logmsg" reference comprised entirely of paths that have * been reverted in this work tree. If any path in the logmsg ref changeset * remains in a changed state in the worktree, do not remove the reference. */ static const struct got_error * rm_logmsg_ref(struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct wt_commitable_path_arg wcpa; char *uuidstr = NULL; TAILQ_INIT(&refs); err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname; int has_changes = 0; refname = got_ref_get_name(re->ref); if (!strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN)) refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; else if (!strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN)) refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&commit_id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; wcpa.commit_paths = NULL; wcpa.has_changes = &has_changes; err = commit_path_changed_in_worktree(&wcpa, commit_id, worktree, repo); if (err) goto done; if (!has_changes) { err = got_ref_delete(re->ref, repo); if (err) goto done; } got_object_commit_close(commit); commit = NULL; free(commit_id); commit_id = NULL; } done: free(uuidstr); free(commit_id); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); return err; } static const struct got_error * cmd_revert(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *path = NULL; struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, can_recurse = 0, pflag = 0; FILE *patch_script_file = NULL; const char *patch_script_path = NULL; struct choose_patch_arg cpa; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "F:pR")) != -1) { switch (ch) { case 'F': patch_script_path = optarg; break; case 'p': pflag = 1; break; case 'R': can_recurse = 1; break; default: usage_revert(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) usage_revert(); if (patch_script_path && !pflag) errx(1, "-F option can only be used together with -p option"); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "revert", cwd); goto done; } error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error != NULL) goto done; if (patch_script_path) { patch_script_file = fopen(patch_script_path, "re"); if (patch_script_file == NULL) { error = got_error_from_errno2("fopen", patch_script_path); goto done; } } /* * XXX "c" perm needed on repo dir to delete merge references. */ error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); if (error) goto done; error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; if (!can_recurse) { char *ondisk_path; struct stat sb; RB_FOREACH(pe, got_pathlist_head, &paths) { if (asprintf(&ondisk_path, "%s/%s", got_worktree_get_root_path(worktree), pe->path) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (lstat(ondisk_path, &sb) == -1) { if (errno == ENOENT) { free(ondisk_path); continue; } error = got_error_from_errno2("lstat", ondisk_path); free(ondisk_path); goto done; } free(ondisk_path); if (S_ISDIR(sb.st_mode)) { error = got_error_msg(GOT_ERR_BAD_PATH, "reverting directories requires -R option"); goto done; } } } cpa.patch_script_file = patch_script_file; cpa.action = "revert"; error = got_worktree_revert(worktree, &paths, revert_progress, NULL, pflag ? choose_patch : NULL, &cpa, repo); error = rm_logmsg_ref(worktree, repo); done: if (patch_script_file && fclose(patch_script_file) == EOF && error == NULL) error = got_error_from_errno2("fclose", patch_script_path); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(path); free(cwd); return error; } __dead static void usage_commit(void) { fprintf(stderr, "usage: %s commit [-CNnS] [-A author] " "[-i identity-file] [-J jumphost] [-F path] [-m message] " "[path ...]\n", getprogname()); exit(1); } struct collect_commit_logmsg_arg { const char *cmdline_log; const char *prepared_log; const char *merged_log; int non_interactive; const char *editor; const char *worktree_path; const char *repo_path; const char *dial_proto; char *logmsg_path; }; static const struct got_error * read_prepared_logmsg(char **logmsg, const char *path) { const struct got_error *err = NULL; FILE *f = NULL; struct stat sb; size_t r; *logmsg = NULL; memset(&sb, 0, sizeof(sb)); f = fopen(path, "re"); if (f == NULL) return got_error_from_errno2("fopen", path); if (fstat(fileno(f), &sb) == -1) { err = got_error_from_errno2("fstat", path); goto done; } if (sb.st_size == 0) { err = got_error(GOT_ERR_COMMIT_MSG_EMPTY); goto done; } *logmsg = malloc(sb.st_size + 1); if (*logmsg == NULL) { err = got_error_from_errno("malloc"); goto done; } r = fread(*logmsg, 1, sb.st_size, f); if (r != sb.st_size) { if (ferror(f)) err = got_error_from_errno2("fread", path); else err = got_error(GOT_ERR_IO); goto done; } (*logmsg)[sb.st_size] = '\0'; done: if (fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * collect_commit_logmsg(struct got_pathlist_head *commitable_paths, const char *diff_path, char **logmsg, void *arg) { char *initial_content = NULL; struct got_pathlist_entry *pe; const struct got_error *err = NULL; char *template = NULL; char *prepared_msg = NULL, *merged_msg = NULL; struct collect_commit_logmsg_arg *a = arg; int initial_content_len; int fd = -1; size_t len; /* if a message was specified on the command line, just use it */ if (a->cmdline_log != NULL && *a->cmdline_log != '\0') { len = strlen(a->cmdline_log) + 1; *logmsg = malloc(len + 1); if (*logmsg == NULL) return got_error_from_errno("malloc"); strlcpy(*logmsg, a->cmdline_log, len); return NULL; } else if (a->prepared_log != NULL && a->non_interactive) return read_prepared_logmsg(logmsg, a->prepared_log); if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1) return got_error_from_errno("asprintf"); err = got_opentemp_named_fd(&a->logmsg_path, &fd, template, ""); if (err) goto done; if (a->prepared_log) { err = read_prepared_logmsg(&prepared_msg, a->prepared_log); if (err) goto done; } else if (a->merged_log) { err = read_prepared_logmsg(&merged_msg, a->merged_log); if (err) goto done; } initial_content_len = asprintf(&initial_content, "%s%s\n# changes to be committed:\n", prepared_msg ? prepared_msg : "", merged_msg ? merged_msg : ""); if (initial_content_len == -1) { err = got_error_from_errno("asprintf"); goto done; } if (write(fd, initial_content, initial_content_len) == -1) { err = got_error_from_errno2("write", a->logmsg_path); goto done; } RB_FOREACH(pe, got_pathlist_head, commitable_paths) { struct got_commitable *ct = pe->data; dprintf(fd, "# %c %s\n", got_commitable_get_status(ct), got_commitable_get_path(ct)); } if (diff_path) { dprintf(fd, "# detailed changes can be viewed in %s\n", diff_path); } if (close(fd) == -1) { err = got_error_from_errno2("close", a->logmsg_path); goto done; } fd = -1; err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content, initial_content_len, a->prepared_log ? 0 : 1); done: free(initial_content); free(template); free(prepared_msg); free(merged_msg); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno2("close", a->logmsg_path); /* Editor is done; we can now apply unveil(2) */ if (err == NULL) err = got_dial_apply_unveil(a->dial_proto); if (err == NULL) err = apply_unveil(a->repo_path, 0, a->worktree_path); if (err) { free(*logmsg); *logmsg = NULL; } return err; } static const struct got_error * cat_logmsg(FILE *f, struct got_commit_object *commit, const char *idstr, const char *type, int has_content) { const struct got_error *err = NULL; char *logmsg = NULL; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) return err; if (fprintf(f, "%s# log message of %s commit %s:%s", has_content ? "\n" : "", type, idstr, logmsg) < 0) err = got_ferror(f, GOT_ERR_IO); free(logmsg); return err; } /* * Lookup "logmsg" references of backed-out and cherrypicked commits * belonging to the current work tree. If found, and the worktree has * at least one modified file that was changed in the referenced commit, * add its log message to a new temporary file at *logmsg_path. * Add all refs found to matched_refs to be scheduled for removal on * successful commit. */ static const struct got_error * lookup_logmsg_ref(char **logmsg_path, struct got_pathlist_head *paths, struct got_reflist_head *matched_refs, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; struct got_reflist_head refs; struct got_reflist_entry *re, *re_match; FILE *f = NULL; char *uuidstr = NULL; int added_logmsg = 0; TAILQ_INIT(&refs); *logmsg_path = NULL; err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; err = got_ref_list(&refs, repo, "refs/got/worktree", got_ref_cmp_by_name, repo); if (err) goto done; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *type; struct wt_commitable_path_arg wcpa; int add_logmsg = 0; refname = got_ref_get_name(re->ref); if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1; type = "cherrypicked"; } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) { refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1; type = "backed-out"; } else continue; if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; wcpa.commit_paths = paths; wcpa.has_changes = &add_logmsg; err = commit_path_changed_in_worktree(&wcpa, id, worktree, repo); if (err) goto done; if (add_logmsg) { if (f == NULL) { err = got_opentemp_named(logmsg_path, &f, "got-commit-logmsg", ""); if (err) goto done; } err = cat_logmsg(f, commit, refname, type, added_logmsg); if (err) goto done; if (!added_logmsg) ++added_logmsg; err = got_reflist_entry_dup(&re_match, re); if (err) goto done; TAILQ_INSERT_HEAD(matched_refs, re_match, entry); } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } done: free(id); free(uuidstr); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); if (f && fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (!added_logmsg) { if (*logmsg_path && unlink(*logmsg_path) != 0 && err == NULL) err = got_error_from_errno2("unlink", *logmsg_path); *logmsg_path = NULL; } return err; } static const struct got_error * cmd_commit(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *id_str = NULL; struct got_object_id *id = NULL; const char *logmsg = NULL; char *prepared_logmsg = NULL, *merged_logmsg = NULL; struct collect_commit_logmsg_arg cl_arg; const char *author = NULL; char *gitconfig_path = NULL, *editor = NULL, *committer = NULL; int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0; int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0; int show_diff = 1, commit_conflicts = 0; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; int *pack_fds = NULL; const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; const struct got_remote_repo *remotes, *remote = NULL; int nremotes; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; const char *remote_name, *jumphost = NULL, *identity_file = NULL; int verbosity = 0; int i; TAILQ_INIT(&refs); RB_INIT(&paths); cl_arg.logmsg_path = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "A:CF:i:J:m:NnS")) != -1) { switch (ch) { case 'A': author = optarg; error = valid_author(author); if (error) return error; break; case 'C': commit_conflicts = 1; break; case 'F': if (logmsg != NULL) option_conflict('F', 'm'); prepared_logmsg = realpath(optarg, NULL); if (prepared_logmsg == NULL) return got_error_from_errno2("realpath", optarg); break; case 'i': identity_file = optarg; break; case 'J': jumphost = optarg; break; case 'm': if (prepared_logmsg) option_conflict('m', 'F'); logmsg = optarg; break; case 'N': non_interactive = 1; break; case 'n': show_diff = 0; break; case 'S': allow_bad_symlinks = 1; break; default: usage_commit(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "commit", cwd); goto done; } error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (error) goto done; if (rebase_in_progress) { error = got_error(GOT_ERR_REBASING); goto done; } error = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (error) goto done; error = get_gitconfig_path(&gitconfig_path); if (error) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), gitconfig_path, pack_fds); if (error != NULL) goto done; error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (error) goto done; if (merge_in_progress) { error = got_error(GOT_ERR_MERGE_BUSY); goto done; } error = get_author(&committer, repo, worktree); if (error) goto done; if (author == NULL) author = committer; remote_name = GOT_SEND_DEFAULT_REMOTE_NAME; worktree_conf = got_worktree_get_gotconfig(worktree); if (worktree_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, worktree_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { repo_conf = got_repo_get_gotconfig(repo); if (repo_conf) { got_gotconfig_get_remotes(&nremotes, &remotes, repo_conf); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } } if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { if (strcmp(remotes[i].name, remote_name) == 0) { remote = &remotes[i]; break; } } } if (remote == NULL) { error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); goto done; } error = got_dial_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->fetch_url); if (error) goto done; if (strcmp(proto, "git") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd dns inet unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif } else if (strcmp(proto, "http") == 0 || strcmp(proto, "git+http") == 0) { error = got_error_path(proto, GOT_ERR_NOT_IMPL); goto done; } else { error = got_error_path(proto, GOT_ERR_BAD_PROTO); goto done; } /*if (verbosity >= 0) { printf("Connecting to \"%s\" %s://%s%s%s%s%s\n", remote->name, proto, host, port ? ":" : "", port ? port : "", *server_path == '/' ? "" : "/", server_path); }*/ /* * unveil(2) traverses exec(2); if an editor is used we have * to apply unveil after the log message has been written during * the callback. */ if (logmsg == NULL || strlen(logmsg) == 0) error = get_editor(&editor); else { error = got_dial_apply_unveil(proto); if (error) goto done; error = apply_unveil(got_repo_get_path(repo), 0, got_worktree_get_root_path(worktree)); } if (error) goto done; if (prepared_logmsg == NULL) { error = lookup_logmsg_ref(&merged_logmsg, argc > 0 ? &paths : NULL, &refs, worktree, repo); if (error) goto done; } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; cl_arg.editor = editor; cl_arg.cmdline_log = logmsg; cl_arg.prepared_log = prepared_logmsg; cl_arg.merged_log = merged_logmsg; cl_arg.non_interactive = non_interactive; cl_arg.worktree_path = got_worktree_get_root_path(worktree); cl_arg.repo_path = got_repo_get_path(repo); cl_arg.dial_proto = proto; error = got_worktree_cvg_commit(&id, worktree, &paths, author, 0, committer, allow_bad_symlinks, show_diff, commit_conflicts, collect_commit_logmsg, &cl_arg, print_status, NULL, proto, host, port, server_path, jumphost, identity_file, verbosity, remote, check_cancelled, repo); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && cl_arg.logmsg_path != NULL) preserve_logmsg = 1; goto done; } error = got_object_id_str(&id_str, id); if (error) goto done; printf("Created commit %s\n", id_str); TAILQ_FOREACH(re, &refs, entry) { error = got_ref_delete(re->ref, repo); if (error) goto done; } done: if (preserve_logmsg) { fprintf(stderr, "%s: log message preserved in %s\n", getprogname(), cl_arg.logmsg_path); } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 && error == NULL) error = got_error_from_errno2("unlink", cl_arg.logmsg_path); free(cl_arg.logmsg_path); if (merged_logmsg && unlink(merged_logmsg) == -1 && error == NULL) error = got_error_from_errno2("unlink", merged_logmsg); free(merged_logmsg); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(gitconfig_path); free(editor); free(committer); free(prepared_logmsg); return error; } /* * Print and if delete is set delete all ref_prefix references. * If wanted_ref is not NULL, only print or delete this reference. */ static const struct got_error * process_logmsg_refs(const char *ref_prefix, size_t prefix_len, const char *wanted_ref, int delete, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err; struct got_pathlist_head paths; struct got_reflist_head refs; struct got_reflist_entry *re; struct got_reflist_object_id_map *refs_idmap = NULL; struct got_commit_object *commit = NULL; struct got_object_id *id = NULL; const char *header_prefix; char *uuidstr = NULL; int found = 0; TAILQ_INIT(&refs); RB_INIT(&paths); err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo); if (err) goto done; err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo); if (err) goto done; if (worktree != NULL) { err = got_worktree_get_uuid(&uuidstr, worktree); if (err) goto done; } if (wanted_ref) { if (strncmp(wanted_ref, "refs/heads/", 11) == 0) wanted_ref += 11; } if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0) header_prefix = "backout"; else header_prefix = "cherrypick"; TAILQ_FOREACH(re, &refs, entry) { const char *refname, *wt; refname = got_ref_get_name(re->ref); err = check_cancelled(NULL); if (err) goto done; if (strncmp(refname, ref_prefix, prefix_len) == 0) refname += prefix_len + 1; /* skip '-' delimiter */ else continue; wt = refname; if (worktree == NULL || strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0) refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */ else continue; err = got_repo_match_object_id(&id, NULL, refname, GOT_OBJ_TYPE_COMMIT, NULL, repo); if (err) goto done; err = got_object_open_as_commit(&commit, repo, id); if (err) goto done; if (wanted_ref) found = strncmp(wanted_ref, refname, strlen(wanted_ref)) == 0; if (wanted_ref && !found) { struct got_reflist_head *ci_refs; ci_refs = got_reflist_object_id_map_lookup(refs_idmap, id); if (ci_refs) { char *refs_str = NULL; char const *r = NULL; err = build_refs_str(&refs_str, ci_refs, id, repo, 1); if (err) goto done; r = refs_str; while (r) { if (strncmp(r, wanted_ref, strlen(wanted_ref)) == 0) { found = 1; break; } r = strchr(r, ' '); if (r) ++r; } free(refs_str); } } if (wanted_ref == NULL || found) { if (delete) { err = got_ref_delete(re->ref, repo); if (err) goto done; printf("Deleted: "); err = print_commit_oneline(commit, id, repo, refs_idmap); } else { /* * Print paths modified by commit to help * associate commits with worktree changes. */ err = get_changed_paths(&paths, commit, repo, NULL); if (err) goto done; err = print_commit(commit, id, repo, NULL, &paths, NULL, 0, 0, refs_idmap, NULL, header_prefix); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (worktree == NULL) printf("work tree: %.*s\n\n", GOT_WORKTREE_UUID_STRLEN, wt); } if (err || found) goto done; } got_object_commit_close(commit); commit = NULL; free(id); id = NULL; } if (wanted_ref != NULL && !found) err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref); done: free(id); free(uuidstr); got_ref_list_free(&refs); got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL); if (refs_idmap) got_reflist_object_id_map_free(refs_idmap); if (commit) got_object_commit_close(commit); return err; } /* * Create new temp "logmsg" ref of the backed-out or cherrypicked commit * identified by id for log messages to prepopulate the editor on commit. */ static const struct got_error * logmsg_ref(struct got_object_id *id, const char *prefix, struct got_worktree *worktree, struct got_repository *repo) { const struct got_error *err = NULL; char *idstr, *ref = NULL, *refname = NULL; int histedit_in_progress; int rebase_in_progress, merge_in_progress; /* * Silently refuse to create merge reference if any histedit, merge, * or rebase operation is in progress. */ err = got_worktree_histedit_in_progress(&histedit_in_progress, worktree); if (err) return err; if (histedit_in_progress) return NULL; err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree); if (err) return err; if (rebase_in_progress) return NULL; err = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo); if (err) return err; if (merge_in_progress) return NULL; err = got_object_id_str(&idstr, id); if (err) return err; err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix); if (err) goto done; if (asprintf(&ref, "%s-%s", refname, idstr) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = create_ref(ref, got_worktree_get_base_commit_id(worktree), -1, repo); done: free(ref); free(idstr); free(refname); return err; } __dead static void usage_cherrypick(void) { fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_cherrypick(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_cherrypick(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_cherrypick(); } else if (argc != 1) usage_cherrypick(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "cherrypick", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX, GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_repo_match_object_id(&commit_id, NULL, argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL, commit_id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo); if (error) goto done; printf("Merged commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_backout(void) { fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname()); exit(1); } static const struct got_error * cmd_backout(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_worktree *worktree = NULL; struct got_repository *repo = NULL; char *cwd = NULL, *commit_id_str = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_object_qid *pid; int ch, list_refs = 0, remove_refs = 0; struct got_update_progress_arg upa; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " "unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "lX")) != -1) { switch (ch) { case 'l': list_refs = 1; break; case 'X': remove_refs = 1; break; default: usage_backout(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs || remove_refs) { if (argc != 0 && argc != 1) usage_backout(); } else if (argc != 1) usage_backout(); if (list_refs && remove_refs) option_conflict('l', 'X'); cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (list_refs || remove_refs) { if (error->code != GOT_ERR_NOT_WORKTREE) goto done; } else { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "backout", cwd); goto done; } } error = got_repo_open(&repo, worktree ? got_worktree_get_repo_path(worktree) : cwd, NULL, pack_fds); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 0, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (list_refs || remove_refs) { error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX, GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN, argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo); goto done; } error = got_repo_match_object_id(&commit_id, NULL, argv[0], GOT_OBJ_TYPE_COMMIT, NULL, repo); if (error) goto done; error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid == NULL) { error = got_error(GOT_ERR_ROOT_COMMIT); goto done; } memset(&upa, 0, sizeof(upa)); error = got_worktree_merge_files(worktree, commit_id, &pid->id, repo, update_progress, &upa, check_cancelled, NULL); if (error != NULL) goto done; if (upa.did_something) { error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX, worktree, repo); if (error) goto done; printf("Backed out commit %s\n", commit_id_str); } print_merge_progress_stats(&upa); done: free(cwd); if (commit) got_object_commit_close(commit); free(commit_id_str); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } return error; } __dead static void usage_cat(void) { fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] " "arg ...\n", getprogname()); exit(1); } static const struct got_error * cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_blob_object *blob; int fd = -1; fd = got_opentempfd(); if (fd == -1) return got_error_from_errno("got_opentempfd"); err = got_object_open_as_blob(&blob, repo, id, 8192, fd); if (err) goto done; err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); return err; } static const struct got_error * cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tree_object *tree; int nentries, i; err = got_object_open_as_tree(&tree, repo, id); if (err) return err; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { struct got_tree_entry *te; char *id_str; if (sigint_received || sigpipe_received) break; te = got_object_tree_get_entry(tree, i); err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) break; fprintf(outfile, "%s %.7o %s\n", id_str, got_tree_entry_get_mode(te), got_tree_entry_get_name(te)); free(id_str); } got_object_tree_close(tree); return err; } static const struct got_error * cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_commit_object *commit; const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; char *id_str = NULL; const char *logmsg = NULL; char gmtoff[6]; err = got_object_open_as_commit(&commit, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str); parent_ids = got_object_commit_get_parent_ids(commit); fprintf(outfile, "numparents %d\n", got_object_commit_get_nparents(commit)); STAILQ_FOREACH(pid, parent_ids, entry) { char *pid_str; err = got_object_id_str(&pid_str, &pid->id); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str); free(pid_str); } got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_author_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR, got_object_commit_get_author(commit), (long long)got_object_commit_get_author_time(commit), gmtoff); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_commit_get_committer_gmtoff(commit)); fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER, got_object_commit_get_committer(commit), (long long)got_object_commit_get_committer_time(commit), gmtoff); logmsg = got_object_commit_get_logmsg_raw(commit); fprintf(outfile, "messagelen %zd\n", strlen(logmsg)); fprintf(outfile, "%s", logmsg); done: free(id_str); got_object_commit_close(commit); return err; } static const struct got_error * cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tag_object *tag; char *id_str = NULL; const char *tagmsg = NULL; char gmtoff[6]; err = got_object_open_as_tag(&tag, repo, id); if (err) return err; err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) goto done; fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str); switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_BLOB); break; case GOT_OBJ_TYPE_TREE: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TREE); break; case GOT_OBJ_TYPE_COMMIT: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_COMMIT); break; case GOT_OBJ_TYPE_TAG: fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE, GOT_OBJ_LABEL_TAG); break; default: break; } fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG, got_object_tag_get_name(tag)); got_date_format_gmtoff(gmtoff, sizeof(gmtoff), got_object_tag_get_tagger_gmtoff(tag)); fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER, got_object_tag_get_tagger(tag), (long long)got_object_tag_get_tagger_time(tag), gmtoff); tagmsg = got_object_tag_get_message(tag); fprintf(outfile, "messagelen %zd\n", strlen(tagmsg)); fprintf(outfile, "%s", tagmsg); done: free(id_str); got_object_tag_close(tag); return err; } static const struct got_error * cmd_cat(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *label = NULL; const char *commit_id_str = NULL; struct got_object_id *id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; int ch, obj_type, i, force_path = 0; struct got_reflist_head refs; int *pack_fds = NULL; TAILQ_INIT(&refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "c:Pr:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'P': force_path = 1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_cat(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) { repo_path = strdup( got_worktree_get_repo_path(worktree)); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } } if (repo_path == NULL) { repo_path = strdup(cwd); if (repo_path == NULL) return got_error_from_errno("strdup"); } error = got_repo_open(&repo, repo_path, NULL, pack_fds); free(repo_path); if (error != NULL) goto done; error = apply_unveil(got_repo_get_path(repo), 1, NULL); if (error) goto done; error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (commit_id_str == NULL) commit_id_str = GOT_REF_HEAD; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; for (i = 0; i < argc; i++) { if (force_path) { error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } else { error = got_repo_match_object_id(&id, &label, argv[i], GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */, repo); if (error) { if (error->code != GOT_ERR_BAD_OBJ_ID_STR && error->code != GOT_ERR_NOT_REF) break; error = got_object_id_by_path(&id, repo, commit, argv[i]); if (error) break; } } error = got_object_get_type(&obj_type, repo, id); if (error) break; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: error = cat_blob(id, repo, stdout); break; case GOT_OBJ_TYPE_TREE: error = cat_tree(id, repo, stdout); break; case GOT_OBJ_TYPE_COMMIT: error = cat_commit(id, repo, stdout); break; case GOT_OBJ_TYPE_TAG: error = cat_tag(id, repo, stdout); break; default: error = got_error(GOT_ERR_OBJ_TYPE); break; } if (error) break; free(label); label = NULL; free(id); id = NULL; } done: free(label); free(id); free(commit_id); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_ref_list_free(&refs); return error; } __dead static void usage_info(void) { fprintf(stderr, "usage: %s info [path ...]\n", getprogname()); exit(1); } static const struct got_error * print_path_info(void *arg, const char *path, mode_t mode, time_t mtime, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id) { const struct got_error *err = NULL; char *id_str = NULL; char datebuf[128]; struct tm mytm, *tm; struct got_pathlist_head *paths = arg; struct got_pathlist_entry *pe; /* * Clear error indication from any of the path arguments which * would cause this file index entry to be displayed. */ RB_FOREACH(pe, got_pathlist_head, paths) { if (got_path_cmp(path, pe->path, strlen(path), pe->path_len) == 0 || got_path_is_child(path, pe->path, pe->path_len)) pe->data = NULL; /* no error */ } printf(GOT_COMMIT_SEP_STR); if (S_ISLNK(mode)) printf("symlink: %s\n", path); else if (S_ISREG(mode)) { printf("file: %s\n", path); printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } else if (S_ISDIR(mode)) printf("directory: %s\n", path); else printf("something: %s\n", path); tm = localtime_r(&mtime, &mytm); if (tm == NULL) return NULL; if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0) return got_error(GOT_ERR_NO_SPACE); printf("timestamp: %s\n", datebuf); if (blob_id) { err = got_object_id_str(&id_str, blob_id); if (err) return err; printf("based on blob: %s\n", id_str); free(id_str); } if (staged_blob_id) { err = got_object_id_str(&id_str, staged_blob_id); if (err) return err; printf("based on staged blob: %s\n", id_str); free(id_str); } if (commit_id) { err = got_object_id_str(&id_str, commit_id); if (err) return err; printf("based on commit: %s\n", id_str); free(id_str); } return NULL; } static const struct got_error * cmd_info(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_fileindex *fileindex = NULL; char *cwd = NULL, *id_str = NULL; struct got_pathlist_head paths; char *uuidstr = NULL; int ch, show_files = 0; int *pack_fds = NULL; RB_INIT(&paths); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage_info(); /* NOTREACHED */ } } argc -= optind; argv += optind; cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, cwd, GOT_WORKTREE_CVG_DIR); if (error) { if (error->code == GOT_ERR_NOT_WORKTREE) error = wrap_not_worktree_error(error, "info", cwd); goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, got_worktree_get_repo_path(worktree), NULL, pack_fds); if (error) goto done; #ifndef PROFILE /* Remove "wpath cpath proc exec sendfd" promises. */ if (pledge("stdio rpath flock unveil", NULL) == -1) err(1, "pledge"); #endif error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree)); if (error) goto done; if (argc >= 1) { error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error) goto done; show_files = 1; } error = got_worktree_path_info_prepare(&fileindex, worktree, repo); if (error) goto done; error = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (error) goto done; error = got_worktree_get_uuid(&uuidstr, worktree); if (error) goto done; printf("work tree: %s\n", got_worktree_get_root_path(worktree)); printf("work tree base commit: %s\n", id_str); printf("work tree path prefix: %s\n", got_worktree_get_path_prefix(worktree)); printf("work tree branch reference: %s\n", got_worktree_get_head_ref_name(worktree)); printf("work tree UUID: %s\n", uuidstr); printf("work tree format version: %d\n", got_worktree_get_format_version(worktree)); printf("file index version: %u\n", got_worktree_get_fileindex_version(fileindex)); printf("repository: %s\n", got_worktree_get_repo_path(worktree)); if (show_files) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, &paths) { if (pe->path_len == 0) continue; /* * Assume this path will fail. This will be corrected * in print_path_info() in case the path does suceeed. */ pe->data = (void *)got_error(GOT_ERR_BAD_PATH); } error = got_worktree_path_info(worktree, fileindex, &paths, print_path_info, &paths, check_cancelled, NULL); if (error) goto done; RB_FOREACH(pe, got_pathlist_head, &paths) { if (pe->data != NULL) { const struct got_error *perr; perr = pe->data; error = got_error_path(pe->path, perr->code); break; } } } done: if (worktree) { const struct got_error *cerr; cerr = got_worktree_path_info_complete(fileindex, worktree); if (error == NULL) error = cerr; got_worktree_close(worktree); } if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(cwd); free(id_str); free(uuidstr); return error; } got-portable-0.119/cvg/Makefile.in0000664000175000017500000014202115066537206012444 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = cvg$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = cvg ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_cvg_OBJECTS = cvg.$(OBJEXT) $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fetch.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_privsep.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/patch.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/repository_init.$(OBJEXT) \ $(top_builddir)/lib/send.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_cvg.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) cvg_OBJECTS = $(am_cvg_OBJECTS) cvg_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fetch.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/patch.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/repository_init.Po \ $(top_builddir)/lib/$(DEPDIR)/send.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/cvg.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(cvg_SOURCES) DIST_SOURCES = $(cvg_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ cvg_SOURCES = cvg.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/send.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_cvg.c \ $(top_srcdir)/lib/worktree_open.c cvg_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = cvg.1 man1_MANS = cvg.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libbsd_LIBS) \ $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cvg/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign cvg/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && $(am__rm_f) $$files clean-sbinPROGRAMS: -$(am__rm_f) $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fetch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/patch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository_init.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/send.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_cvg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) cvg$(EXEEXT): $(cvg_OBJECTS) $(cvg_DEPENDENCIES) $(EXTRA_cvg_DEPENDENCIES) @rm -f cvg$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cvg_OBJECTS) $(cvg_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fetch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/patch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository_init.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/send.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvg.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/cvg.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/send.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_cvg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/cvg.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man1 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotadmin/0000775000175000017500000000000015066537274011507 5got-portable-0.119/gotadmin/gotadmin.c0000664000175000017500000012551615066536113013376 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_cancel.h" #include "got_repository.h" #include "got_repository_admin.h" #include "got_repository_dump.h" #include "got_repository_load.h" #include "got_gotconfig.h" #include "got_path.h" #include "got_privsep.h" #include "got_opentemp.h" #include "got_worktree.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigpipe_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigpipe(int signo) { sigpipe_received = 1; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigpipe_received) return got_error(GOT_ERR_CANCELLED); return NULL; } struct gotadmin_cmd { const char *cmd_name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); const char *cmd_alias; }; __dead static void usage(int, int); __dead static void usage_init(void); __dead static void usage_info(void); __dead static void usage_pack(void); __dead static void usage_indexpack(void); __dead static void usage_listpack(void); __dead static void usage_cleanup(void); __dead static void usage_dump(void); __dead static void usage_load(void); static const struct got_error* cmd_init(int, char *[]); static const struct got_error* cmd_info(int, char *[]); static const struct got_error* cmd_pack(int, char *[]); static const struct got_error* cmd_indexpack(int, char *[]); static const struct got_error* cmd_listpack(int, char *[]); static const struct got_error* cmd_cleanup(int, char *[]); static const struct got_error* cmd_dump(int, char *[]); static const struct got_error* cmd_load(int, char *[]); static const struct gotadmin_cmd gotadmin_commands[] = { { "init", cmd_init, usage_init, "" }, { "info", cmd_info, usage_info, "" }, { "pack", cmd_pack, usage_pack, "" }, { "indexpack", cmd_indexpack, usage_indexpack,"ix" }, { "listpack", cmd_listpack, usage_listpack, "ls" }, { "cleanup", cmd_cleanup, usage_cleanup, "cl" }, { "dump", cmd_dump, usage_dump, "" }, { "load", cmd_load, usage_load, "" }, }; static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(gotadmin_commands); i++) { const struct gotadmin_cmd *cmd = &gotadmin_commands[i]; fprintf(fp, " %s", cmd->cmd_name); } fputc('\n', fp); } int main(int argc, char *argv[]) { const struct gotadmin_cmd *cmd; size_t i; int ch; int hflag = 0, Vflag = 0; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; setlocale(LC_CTYPE, ""); while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc <= 0) usage(hflag, hflag ? 0 : 1); signal(SIGINT, catch_sigint); signal(SIGPIPE, catch_sigpipe); for (i = 0; i < nitems(gotadmin_commands); i++) { const struct got_error *error; cmd = &gotadmin_commands[i]; if (strcmp(cmd->cmd_name, argv[0]) != 0 && strcmp(cmd->cmd_alias, argv[0]) != 0) continue; if (hflag) cmd->cmd_usage(); error = cmd->cmd_main(argc, argv); if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_PRIVSEP_EXIT && !(sigpipe_received && error->code == GOT_ERR_ERRNO && errno == EPIPE) && !(sigint_received && error->code == GOT_ERR_ERRNO && errno == EINTR)) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]); list_commands(stderr); return 1; } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) list_commands(fp); exit(status); } static const struct got_error * apply_unveil(const char *repo_path, int repo_read_only) { const struct got_error *err; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0) return got_error_from_errno2("unveil", repo_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); err = got_privsep_unveil_exec_helpers(); if (err != NULL) return err; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } __dead static void usage_info(void) { fprintf(stderr, "usage: %s info [-r repository-path]\n", getprogname()); exit(1); } static const struct got_error * get_repo_path(char **repo_path) { const struct got_error *err = NULL; struct got_worktree *worktree = NULL; char *cwd; *repo_path = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); err = got_worktree_open(&worktree, cwd, NULL); if (err) { if (err->code != GOT_ERR_NOT_WORKTREE) goto done; err = NULL; } if (worktree) *repo_path = strdup(got_worktree_get_repo_path(worktree)); else *repo_path = strdup(cwd); if (*repo_path == NULL) err = got_error_from_errno("strdup"); done: if (worktree) got_worktree_close(worktree); free(cwd); return err; } __dead static void usage_init(void) { fprintf(stderr, "usage: %s init [-A hashing-algorithm] [-b branch]" " repository-path\n", getprogname()); exit(1); } static const struct got_error * cmd_init(int argc, char *argv[]) { const struct got_error *error = NULL; const char *head_name = NULL; char *repo_path = NULL; enum got_hash_algorithm algo = GOT_HASH_SHA1; int ch; #ifndef PROFILE if (pledge("stdio rpath wpath cpath unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "A:b:")) != -1) { switch (ch) { case 'A': if (!strcmp(optarg, "sha1")) algo = GOT_HASH_SHA1; else if (!strcmp(optarg, "sha256")) algo = GOT_HASH_SHA256; else return got_error_path(optarg, GOT_ERR_OBJECT_FORMAT); break; case 'b': head_name = optarg; break; default: usage_init(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_init(); repo_path = strdup(argv[0]); if (repo_path == NULL) return got_error_from_errno("strdup"); got_path_strip_trailing_slashes(repo_path); error = got_path_mkdir(repo_path); if (error && !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) goto done; error = apply_unveil(repo_path, 0); if (error) goto done; error = got_repo_init(repo_path, head_name, algo); done: free(repo_path); return error; } static const struct got_error * cmd_info(int argc, char *argv[]) { const struct got_error *error = NULL; char *repo_path = NULL; struct got_repository *repo = NULL; const struct got_gotconfig *gotconfig = NULL; int ch, npackfiles, npackedobj, nobj; off_t packsize, loose_size; char scaled[FMT_SCALED_STRSIZE]; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "r:")) != -1) { switch (ch) { case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_info(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (repo_path == NULL) { error = get_repo_path(&repo_path); if (error) goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; #ifndef PROFILE /* Remove "cpath" promise. */ if (pledge("stdio rpath wpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif error = apply_unveil(got_repo_get_path_git_dir(repo), 1); if (error) goto done; printf("repository: %s\n", got_repo_get_path_git_dir(repo)); printf("hashing algorithm: %s\n", got_repo_get_object_format(repo) == GOT_HASH_SHA1 ? "sha1" : "sha256"); gotconfig = got_repo_get_gotconfig(repo); if (gotconfig) { const struct got_remote_repo *remotes; int i, nremotes; if (got_gotconfig_get_author(gotconfig)) { printf("default author: %s\n", got_gotconfig_get_author(gotconfig)); } got_gotconfig_get_remotes(&nremotes, &remotes, gotconfig); for (i = 0; i < nremotes; i++) { const char *fetch_url = remotes[i].fetch_url; const char *send_url = remotes[i].send_url; if (strcmp(fetch_url, send_url) == 0) { printf("remote \"%s\": %s\n", remotes[i].name, remotes[i].fetch_url); } else { printf("remote \"%s\" (fetch): %s\n", remotes[i].name, remotes[i].fetch_url); printf("remote \"%s\" (send): %s\n", remotes[i].name, remotes[i].send_url); } } } error = got_repo_get_packfile_info(&npackfiles, &npackedobj, &packsize, repo); if (error) goto done; printf("pack files: %d\n", npackfiles); if (npackfiles > 0) { if (fmt_scaled(packsize, scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } printf("packed objects: %d\n", npackedobj); printf("packed total size: %s\n", scaled); } error = got_repo_get_loose_object_info(&nobj, &loose_size, repo); if (error) goto done; printf("loose objects: %d\n", nobj); if (nobj > 0) { if (fmt_scaled(loose_size, scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } printf("loose total size: %s\n", scaled); } done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(repo_path); return error; } __dead static void usage_pack(void) { fprintf(stderr, "usage: %s pack [-aDq] [-r repository-path] " "[-x reference] [reference ...]\n", getprogname()); exit(1); } struct got_pack_progress_arg { FILE *out; char last_scaled_size[FMT_SCALED_STRSIZE]; int last_ncolored; int last_nfound; int last_ntrees; int loading_done; int last_ncommits; int last_nobj_total; int last_p_deltify; int last_p_written; int last_p_indexed; int last_p_resolved; int verbosity; int printed_something; }; static void print_load_info(FILE *out, int print_colored, int print_found, int print_trees, int ncolored, int nfound, int ntrees) { if (print_colored) { fprintf(out, "%d commit%s colored", ncolored, ncolored == 1 ? "" : "s"); } if (print_found) { fprintf(out, "%s%d object%s found", ncolored > 0 ? "; " : "", nfound, nfound == 1 ? "" : "s"); } if (print_trees) { fprintf(out, "; %d tree%s scanned", ntrees, ntrees == 1 ? "" : "s"); } } static const struct got_error * pack_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, int pack_done) { struct got_pack_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_deltify, p_written; int print_colored = 0, print_found = 0, print_trees = 0; int print_searching = 0, print_total = 0; int print_deltify = 0, print_written = 0; if (a->verbosity < 0) return NULL; if (a->last_ncolored != ncolored) { print_colored = 1; a->last_ncolored = ncolored; } if (a->last_nfound != nfound) { print_colored = 1; print_found = 1; a->last_nfound = nfound; } if (a->last_ntrees != ntrees) { print_colored = 1; print_found = 1; print_trees = 1; a->last_ntrees = ntrees; } if ((print_colored || print_found || print_trees) && !a->loading_done) { fprintf(a->out, "\r"); print_load_info(a->out, print_colored, print_found, print_trees, ncolored, nfound, ntrees); a->printed_something = 1; fflush(a->out); return NULL; } else if (!a->loading_done) { fprintf(a->out, "\r"); print_load_info(a->out, 1, 1, 1, ncolored, nfound, ntrees); fprintf(a->out, "\n"); a->loading_done = 1; } if (fmt_scaled(packfile_size, scaled_size) == -1) return got_error_from_errno("fmt_scaled"); if (a->last_ncommits != ncommits) { print_searching = 1; a->last_ncommits = ncommits; } if (a->last_nobj_total != nobj_total) { print_searching = 1; print_total = 1; a->last_nobj_total = nobj_total; } if (packfile_size > 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_deltify > 0 || nobj_written > 0) { if (nobj_deltify > 0) { p_deltify = (nobj_deltify * 100) / nobj_total; if (p_deltify != a->last_p_deltify) { a->last_p_deltify = p_deltify; print_searching = 1; print_total = 1; print_deltify = 1; } } if (nobj_written > 0) { p_written = (nobj_written * 100) / nobj_total; if (p_written != a->last_p_written) { a->last_p_written = p_written; print_searching = 1; print_total = 1; print_deltify = 1; print_written = 1; } } } if (print_searching || print_total || print_deltify || print_written) fprintf(a->out, "\r"); if (print_searching) fprintf(a->out, "packing %d reference%s", ncommits, ncommits == 1 ? "" : "s"); if (print_total) fprintf(a->out, "; %d object%s", nobj_total, nobj_total == 1 ? "" : "s"); if (print_deltify) fprintf(a->out, "; deltify: %d%%", p_deltify); if (print_written) fprintf(a->out, "; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2, scaled_size, p_written); if (print_searching || print_total || print_deltify || print_written) { a->printed_something = 1; fflush(a->out); } if (pack_done) fprintf(a->out, "\n"); return NULL; } static const struct got_error * pack_index_progress(void *arg, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved, int indexing_done) { struct got_pack_progress_arg *a = arg; char scaled_size[FMT_SCALED_STRSIZE]; int p_indexed, p_resolved; int print_size = 0, print_indexed = 0, print_resolved = 0; if (a->verbosity < 0) return NULL; if (packfile_size > 0 || nobj_indexed > 0) { if (fmt_scaled(packfile_size, scaled_size) == 0 && (a->last_scaled_size[0] == '\0' || strcmp(scaled_size, a->last_scaled_size)) != 0) { print_size = 1; if (strlcpy(a->last_scaled_size, scaled_size, FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE) return got_error(GOT_ERR_NO_SPACE); } if (nobj_indexed > 0) { p_indexed = (nobj_indexed * 100) / nobj_total; if (p_indexed != a->last_p_indexed) { a->last_p_indexed = p_indexed; print_indexed = 1; print_size = 1; } } if (nobj_resolved > 0) { p_resolved = (nobj_resolved * 100) / (nobj_total - nobj_loose); if (p_resolved != a->last_p_resolved) { a->last_p_resolved = p_resolved; print_resolved = 1; print_indexed = 1; print_size = 1; } } } if (print_size || print_indexed || print_resolved) printf("\r"); if (print_size) printf("%*s packed", FMT_SCALED_STRSIZE - 2, scaled_size); if (print_indexed) printf("; indexing %d%%", p_indexed); if (print_resolved) printf("; resolving deltas %d%%", p_resolved); if (indexing_done) printf("\n"); if (print_size || print_indexed || print_resolved || indexing_done) fflush(stdout); return NULL; } static const struct got_error * add_ref(struct got_reflist_entry **new, struct got_reflist_head *refs, const char *refname, struct got_repository *repo) { const struct got_error *err; struct got_reference *ref; *new = NULL; err = got_ref_open(&ref, repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; /* Treat argument as a reference prefix. */ err = got_ref_list(refs, repo, refname, got_ref_cmp_by_name, NULL); } else { err = got_reflist_insert(new, refs, ref, got_ref_cmp_by_name, NULL); if (err || *new == NULL /* duplicate */) got_ref_close(ref); } return err; } static const struct got_error * cmd_pack(int argc, char *argv[]) { const struct got_error *error = NULL; char *repo_path = NULL; struct got_repository *repo = NULL; int ch, i, loose_obj_only = 1, force_refdelta = 0, verbosity = 0; struct got_object_id *pack_hash = NULL; char *id_str = NULL, *idxpath = NULL; struct got_pack_progress_arg ppa; FILE *packfile = NULL; struct got_pathlist_head exclude_args; struct got_pathlist_entry *pe; struct got_reflist_head exclude_refs; struct got_reflist_head include_refs; struct got_reflist_entry *re, *new; int *pack_fds = NULL; RB_INIT(&exclude_args); TAILQ_INIT(&exclude_refs); TAILQ_INIT(&include_refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "aDqr:x:")) != -1) { switch (ch) { case 'a': loose_obj_only = 0; break; case 'D': force_refdelta = 1; break; case 'q': verbosity = -1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'x': got_path_strip_trailing_slashes(optarg); error = got_pathlist_insert(NULL, &exclude_args, optarg, NULL); if (error) return error; break; default: usage_pack(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (repo_path == NULL) { error = get_repo_path(&repo_path); if (error) goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path_git_dir(repo), 0); if (error) goto done; RB_FOREACH(pe, got_pathlist_head, &exclude_args) { const char *refname = pe->path; error = add_ref(&new, &exclude_refs, refname, repo); if (error) goto done; } if (argc == 0) { error = got_ref_list(&include_refs, repo, "", got_ref_cmp_by_name, NULL); if (error) goto done; } else { for (i = 0; i < argc; i++) { const char *refname; got_path_strip_trailing_slashes(argv[i]); refname = argv[i]; error = add_ref(&new, &include_refs, refname, repo); if (error) goto done; } } /* Ignore references in the refs/got/ namespace. */ TAILQ_FOREACH_SAFE(re, &include_refs, entry, new) { const char *refname = got_ref_get_name(re->ref); if (strncmp("refs/got/", refname, 9) != 0) continue; TAILQ_REMOVE(&include_refs, re, entry); got_ref_close(re->ref); free(re); } memset(&ppa, 0, sizeof(ppa)); ppa.out = stdout; ppa.last_scaled_size[0] = '\0'; ppa.last_p_indexed = -1; ppa.last_p_resolved = -1; ppa.verbosity = verbosity; error = got_repo_pack_objects(&packfile, &pack_hash, &include_refs, &exclude_refs, repo, loose_obj_only, force_refdelta, pack_progress, &ppa, check_cancelled, NULL); if (error) { if (ppa.printed_something) printf("\n"); goto done; } error = got_object_id_str(&id_str, pack_hash); if (error) goto done; if (verbosity >= 0) printf("\nWrote %s.pack\n", id_str); error = got_repo_index_pack(&idxpath, packfile, pack_hash, repo, pack_index_progress, &ppa, check_cancelled, NULL); if (error) goto done; if (verbosity >= 0) printf("\nIndexed %s.pack\n", id_str); done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&exclude_args, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&exclude_refs); got_ref_list_free(&include_refs); free(id_str); free(pack_hash); free(repo_path); free(idxpath); return error; } __dead static void usage_indexpack(void) { fprintf(stderr, "usage: %s indexpack packfile-path\n", getprogname()); exit(1); } static const struct got_error * cmd_indexpack(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; int ch; struct got_object_id *pack_hash = NULL; char *packfile_path = NULL, *idxpath = NULL; char *id_str = NULL; struct got_pack_progress_arg ppa; FILE *packfile = NULL; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: usage_indexpack(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_indexpack(); packfile_path = realpath(argv[0], NULL); if (packfile_path == NULL) return got_error_from_errno2("realpath", argv[0]); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, packfile_path, NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path_git_dir(repo), 0); if (error) goto done; memset(&ppa, 0, sizeof(ppa)); ppa.out = stdout; ppa.last_scaled_size[0] = '\0'; ppa.last_p_indexed = -1; ppa.last_p_resolved = -1; error = got_repo_find_pack(&packfile, &pack_hash, repo, packfile_path); if (error) goto done; error = got_object_id_str(&id_str, pack_hash); if (error) goto done; error = got_repo_index_pack(&idxpath, packfile, pack_hash, repo, pack_index_progress, &ppa, check_cancelled, NULL); if (error) goto done; printf("\nIndexed %s.pack\n", id_str); done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(id_str); free(pack_hash); free(idxpath); return error; } __dead static void usage_listpack(void) { fprintf(stderr, "usage: %s listpack [-hs] packfile-path\n", getprogname()); exit(1); } struct gotadmin_list_pack_cb_args { int nblobs; int ntrees; int ncommits; int ntags; int noffdeltas; int nrefdeltas; int human_readable; }; static const struct got_error * list_pack_cb(void *arg, struct got_object_id *id, int type, off_t offset, off_t size, off_t base_offset, struct got_object_id *base_id) { const struct got_error *err; struct gotadmin_list_pack_cb_args *a = arg; char *id_str, *delta_str = NULL, *base_id_str = NULL; const char *type_str; err = got_object_id_str(&id_str, id); if (err) return err; switch (type) { case GOT_OBJ_TYPE_BLOB: type_str = GOT_OBJ_LABEL_BLOB; a->nblobs++; break; case GOT_OBJ_TYPE_TREE: type_str = GOT_OBJ_LABEL_TREE; a->ntrees++; break; case GOT_OBJ_TYPE_COMMIT: type_str = GOT_OBJ_LABEL_COMMIT; a->ncommits++; break; case GOT_OBJ_TYPE_TAG: type_str = GOT_OBJ_LABEL_TAG; a->ntags++; break; case GOT_OBJ_TYPE_OFFSET_DELTA: type_str = "offset-delta"; if (asprintf(&delta_str, " base-offset %lld", (long long)base_offset) == -1) { err = got_error_from_errno("asprintf"); goto done; } a->noffdeltas++; break; case GOT_OBJ_TYPE_REF_DELTA: type_str = "ref-delta"; err = got_object_id_str(&base_id_str, base_id); if (err) goto done; if (asprintf(&delta_str, " base-id %s", base_id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } a->nrefdeltas++; break; default: err = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (a->human_readable) { char scaled[FMT_SCALED_STRSIZE]; char *s;; if (fmt_scaled(size, scaled) == -1) { err = got_error_from_errno("fmt_scaled"); goto done; } s = scaled; while (isspace((unsigned char)*s)) s++; printf("%s %s at %lld size %s%s\n", id_str, type_str, (long long)offset, s, delta_str ? delta_str : ""); } else { printf("%s %s at %lld size %lld%s\n", id_str, type_str, (long long)offset, (long long)size, delta_str ? delta_str : ""); } done: free(id_str); free(base_id_str); free(delta_str); return err; } static const struct got_error * cmd_listpack(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; int ch; struct got_object_id *pack_hash = NULL; char *packfile_path = NULL; char *id_str = NULL; struct gotadmin_list_pack_cb_args lpa; FILE *packfile = NULL; int show_stats = 0, human_readable = 0; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "hs")) != -1) { switch (ch) { case 'h': human_readable = 1; break; case 's': show_stats = 1; break; default: usage_listpack(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_listpack(); packfile_path = realpath(argv[0], NULL); if (packfile_path == NULL) return got_error_from_errno2("realpath", argv[0]); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, packfile_path, NULL, pack_fds); if (error) goto done; #ifndef PROFILE /* Remove "cpath" promise. */ if (pledge("stdio rpath wpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif error = apply_unveil(got_repo_get_path_git_dir(repo), 1); if (error) goto done; error = got_repo_find_pack(&packfile, &pack_hash, repo, packfile_path); if (error) goto done; error = got_object_id_str(&id_str, pack_hash); if (error) goto done; memset(&lpa, 0, sizeof(lpa)); lpa.human_readable = human_readable; error = got_repo_list_pack(packfile, pack_hash, repo, list_pack_cb, &lpa, check_cancelled, NULL); if (error) goto done; if (show_stats) { printf("objects: %d\n blobs: %d\n trees: %d\n commits: %d\n" " tags: %d\n offset-deltas: %d\n ref-deltas: %d\n", lpa.nblobs + lpa.ntrees + lpa.ncommits + lpa.ntags + lpa.noffdeltas + lpa.nrefdeltas, lpa.nblobs, lpa.ntrees, lpa.ncommits, lpa.ntags, lpa.noffdeltas, lpa.nrefdeltas); } done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(id_str); free(pack_hash); free(packfile_path); return error; } __dead static void usage_cleanup(void) { fprintf(stderr, "usage: %s cleanup [-anpq] [-r repository-path]\n", getprogname()); exit(1); } struct got_cleanup_progress_arg { int last_nloose; int last_ncommits; int last_npurged; int last_nredundant; int verbosity; int printed_something; int dry_run; }; static const struct got_error * cleanup_progress(void *arg, int ncommits, int nloose, int npurged, int nredundant) { struct got_cleanup_progress_arg *a = arg; int print_loose = 0, print_commits = 0, print_purged = 0; int print_redundant = 0; if (a->last_ncommits != ncommits) { print_commits = 1; a->last_ncommits = ncommits; } if (a->last_nloose != nloose) { print_commits = 1; print_loose = 1; a->last_nloose = nloose; } if (a->last_npurged != npurged) { print_commits = 1; print_loose = 1; print_purged = 1; a->last_npurged = npurged; } if (a->last_nredundant != nredundant) { print_commits = 1; print_loose = 1; print_purged = 1; print_redundant = 1; a->last_nredundant = nredundant; } if (a->verbosity < 0) return NULL; if (print_loose || print_commits || print_purged || print_redundant) printf("\r"); if (print_commits) printf("%d commit%s scanned", ncommits, ncommits == 1 ? "" : "s"); if (print_loose) printf("; %d loose object%s", nloose, nloose == 1 ? "" : "s"); if (print_purged || print_redundant) { if (a->dry_run) { printf("; could purge %d object%s", npurged, npurged == 1 ? "" : "s"); } else { printf("; purged %d object%s", npurged, npurged == 1 ? "" : "s"); } } if (print_redundant) { if (a->dry_run) { printf(", %d pack file%s", nredundant, nredundant == 1 ? "" : "s"); } else { printf(", %d pack file%s", nredundant, nredundant == 1 ? "" : "s"); } } if (print_loose || print_commits || print_purged || print_redundant) { a->printed_something = 1; fflush(stdout); } return NULL; } struct got_lonely_packidx_progress_arg { int verbosity; int printed_something; int dry_run; }; static const struct got_error * lonely_packidx_progress(void *arg, const char *path) { struct got_lonely_packidx_progress_arg *a = arg; if (a->verbosity < 0) return NULL; if (a->dry_run) printf("%s could be removed\n", path); else printf("%s removed\n", path); a->printed_something = 1; return NULL; } static const struct got_error * cmd_cleanup(int argc, char *argv[]) { const struct got_error *error = NULL; char *repo_path = NULL; struct got_repository *repo = NULL; int ch, dry_run = 0, verbosity = 0; int ncommits = 0, nloose = 0, npacked = 0; int remove_lonely_packidx = 0, ignore_mtime = 0; struct got_pack_progress_arg ppa; struct got_cleanup_progress_arg cpa; struct got_lonely_packidx_progress_arg lpa; off_t loose_before, loose_after; off_t pack_before, pack_after; off_t total_size; char loose_before_scaled[FMT_SCALED_STRSIZE]; char loose_after_scaled[FMT_SCALED_STRSIZE]; char pack_before_scaled[FMT_SCALED_STRSIZE]; char pack_after_scaled[FMT_SCALED_STRSIZE]; char total_size_scaled[FMT_SCALED_STRSIZE]; int *pack_fds = NULL; #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "anpqr:")) != -1) { switch (ch) { case 'a': ignore_mtime = 1; break; case 'n': dry_run = 1; break; case 'p': remove_lonely_packidx = 1; break; case 'q': verbosity = -1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_cleanup(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (repo_path == NULL) { error = get_repo_path(&repo_path); if (error) goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path_git_dir(repo), 0); if (error) goto done; if (got_repo_has_extension(repo, "preciousObjects")) { error = got_error_msg(GOT_ERR_GIT_REPO_EXT, "the preciousObjects Git extension is enabled; " "this implies that objects must not be deleted"); goto done; } if (remove_lonely_packidx) { memset(&lpa, 0, sizeof(lpa)); lpa.dry_run = dry_run; lpa.verbosity = verbosity; error = got_repo_remove_lonely_packidx(repo, dry_run, lonely_packidx_progress, &lpa, check_cancelled, NULL); goto done; } memset(&cpa, 0, sizeof(cpa)); cpa.last_nloose = -1; cpa.last_npurged = -1; cpa.last_nredundant = -1; cpa.dry_run = dry_run; cpa.verbosity = verbosity; memset(&ppa, 0, sizeof(ppa)); ppa.out = stdout; ppa.verbosity = verbosity; error = got_repo_cleanup(repo, &loose_before, &loose_after, &pack_before, &pack_after, &ncommits, &nloose, &npacked, dry_run, ignore_mtime, cleanup_progress, &cpa, pack_progress, &ppa, pack_index_progress, &ppa, check_cancelled, NULL); if (ppa.printed_something || cpa.printed_something) printf("\n"); if (error) goto done; total_size = (loose_before - loose_after) + (pack_before - pack_after); if (cpa.printed_something) { if (fmt_scaled(loose_before, loose_before_scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } if (fmt_scaled(loose_after, loose_after_scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } if (fmt_scaled(pack_before, pack_before_scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } if (fmt_scaled(pack_after, pack_after_scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } if (fmt_scaled(total_size, total_size_scaled) == -1) { error = got_error_from_errno("fmt_scaled"); goto done; } printf("loose total size before: %s\n", loose_before_scaled); printf("loose total size after: %s\n", loose_after_scaled); printf("pack files total size before: %s\n", pack_before_scaled); printf("pack files total size after: %s\n", pack_after_scaled); if (dry_run) { printf("disk space which would be freed: %s\n", total_size_scaled); } else printf("disk space freed: %s\n", total_size_scaled); printf("loose objects also found in pack files: %d\n", npacked); } done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(repo_path); return error; } __dead static void usage_dump(void) { fprintf(stderr, "usage: %s dump [-q] [-r repository-path] " "[-x reference] [reference]...\n", getprogname()); exit(1); } static const struct got_error * cmd_dump(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_pack_progress_arg ppa; struct got_repository *repo = NULL; struct got_pathlist_head exclude_args; struct got_pathlist_entry *pe; struct got_reflist_head exclude_refs; struct got_reflist_head include_refs; struct got_reflist_entry *re, *new; const char *refname; char *repo_path = NULL; int *pack_fds = NULL; int verbosity = 0; int i, ch; RB_INIT(&exclude_args); TAILQ_INIT(&exclude_refs); TAILQ_INIT(&include_refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "qr:x:")) != -1) { switch (ch) { case 'q': verbosity = -1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 'x': error = got_pathlist_insert(NULL, &exclude_args, optarg, NULL); if (error) return error; break; default: usage_dump(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (repo_path == NULL) { error = get_repo_path(&repo_path); if (error) goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path_git_dir(repo), 1); if (error) goto done; RB_FOREACH(pe, got_pathlist_head, &exclude_args) { refname = pe->path; error = add_ref(&new, &exclude_refs, refname, repo); if (error) goto done; } if (argc == 0) { error = got_ref_list(&include_refs, repo, "", got_ref_cmp_by_name, NULL); if (error) goto done; } else { for (i = 0; i < argc; i++) { got_path_strip_trailing_slashes(argv[i]); refname = argv[i]; error = add_ref(&new, &include_refs, refname, repo); if (error) goto done; } } /* Ignore references in the refs/got/ namespace. */ TAILQ_FOREACH_SAFE(re, &include_refs, entry, new) { refname = got_ref_get_name(re->ref); if (strncmp("refs/got/", refname, 9) != 0) continue; TAILQ_REMOVE(&include_refs, re, entry); got_ref_close(re->ref); free(re); } memset(&ppa, 0, sizeof(ppa)); ppa.out = stderr; ppa.verbosity = verbosity; error = got_repo_dump(stdout, &include_refs, &exclude_refs, repo, pack_progress, &ppa, check_cancelled, NULL); if (ppa.printed_something) fprintf(stderr, "\n"); done: if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err; pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&exclude_args, GOT_PATHLIST_FREE_NONE); got_ref_list_free(&exclude_refs); got_ref_list_free(&include_refs); free(repo_path); return error; } __dead static void usage_load(void) { fprintf(stderr, "usage: %s load [-nq] [-l bundle-file] " "[-r repository-path] [reference ...]\n", getprogname()); exit(1); } static const struct got_error * load_progress(void *arg, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { return pack_index_progress(arg, packfile_size, nobj_total, nobj_indexed, nobj_loose, nobj_resolved, 0); } static int is_wanted_ref(struct got_pathlist_head *wanted, const char *ref) { struct got_pathlist_entry *pe; if (RB_EMPTY(wanted)) return 1; RB_FOREACH(pe, got_pathlist_head, wanted) { if (strcmp(pe->path, ref) == 0) return 1; } return 0; } static const struct got_error * create_ref(const char *refname, struct got_object_id *id, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; struct got_reference *ref; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = got_ref_alloc(&ref, refname, id); if (err) goto done; err = got_ref_write(ref, repo); got_ref_close(ref); if (err == NULL && verbosity >= 0) printf("Created reference %s: %s\n", refname, id_str); done: free(id_str); return err; } static const struct got_error * update_ref(struct got_reference *ref, struct got_object_id *new_id, int replace_tags, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL; char *new_id_str = NULL; struct got_object_id *old_id = NULL; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; if (!replace_tags && strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; if (verbosity >= 0) { printf("Rejecting update of existing tag %s: %s\n", got_ref_get_name(ref), new_id_str); } goto done; } if (got_ref_is_symbolic(ref)) { if (verbosity >= 0) { printf("Replacing reference %s: %s\n", got_ref_get_name(ref), got_ref_get_symref_target(ref)); } err = got_ref_change_symref_to_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } else { err = got_ref_resolve(&old_id, repo, ref); if (err) goto done; if (got_object_id_cmp(old_id, new_id) == 0) goto done; err = got_ref_change_ref(ref, new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; } if (verbosity >= 0) printf("Updated %s: %s\n", got_ref_get_name(ref), new_id_str); done: free(old_id); free(new_id_str); return err; } static const struct got_error * cmd_load(int argc, char *argv[]) { const struct got_error *error = NULL; struct got_repository *repo = NULL; struct got_pathlist_head include_args; struct got_pathlist_head available_refs; struct got_pathlist_entry *pe; struct got_pack_progress_arg ppa; FILE *in = stdin; int *pack_fds = NULL; char *repo_path = NULL; int list_refs_only = 0; int noop = 0; int verbosity = 0; int ch, i; RB_INIT(&include_args); RB_INIT(&available_refs); #ifndef PROFILE if (pledge("stdio rpath wpath cpath fattr flock proc exec " "sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt(argc, argv, "l:nqr:")) != -1) { switch (ch) { case 'l': list_refs_only = 1; in = fopen(optarg, "re"); if (in == NULL) return got_error_from_errno2("open", optarg); break; case 'n': noop = 1; break; case 'q': verbosity = -1; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; default: usage_load(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (list_refs_only && argc > 1) errx(1, "-l and references on the command line are exclusive"); if (list_refs_only && noop) errx(1, "-n and -l are mutually exclusive"); for (i = 0; i < argc; i++) { char *refname = argv[i]; got_path_strip_trailing_slashes(refname); if (!got_ref_name_is_valid(refname)) errx(1, "invalid reference name %s", refname); error = got_pathlist_insert(NULL, &include_args, refname, NULL); if (error) goto done; } if (repo_path == NULL) { error = get_repo_path(&repo_path); if (error) goto done; } error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; error = apply_unveil(got_repo_get_path_git_dir(repo), 0); if (error) goto done; memset(&ppa, 0, sizeof(ppa)); ppa.out = stdout; ppa.verbosity = verbosity; error = got_repo_load(in, &available_refs, repo, list_refs_only, noop, load_progress, &ppa, check_cancelled, NULL); if (verbosity >= 0 && !list_refs_only) printf("\n"); if (error) goto done; if (list_refs_only) { RB_FOREACH(pe, got_pathlist_head, &available_refs) { const char *refname = pe->path; struct got_object_id *id = pe->data; char *idstr; error = got_object_id_str(&idstr, id); if (error) goto done; printf("%s: %s\n", refname, idstr); free(idstr); } goto done; } if (noop) goto done; /* Update references */ RB_FOREACH(pe, got_pathlist_head, &available_refs) { const struct got_error *unlock_err; struct got_reference *ref; const char *refname = pe->path; struct got_object_id *id = pe->data; if (!is_wanted_ref(&include_args, pe->path)) continue; error = got_ref_open(&ref, repo, refname, 1); if (error) { if (error->code != GOT_ERR_NOT_REF) goto done; error = create_ref(refname, id, verbosity, repo); if (error) goto done; } else { /* XXX: check advances only and add -f to force? */ error = update_ref(ref, id, 1, verbosity, repo); unlock_err = got_ref_unlock(ref); if (unlock_err && error == NULL) error = unlock_err; got_ref_close(ref); if (error) goto done; } } done: if (in != stdin && fclose(in) == EOF && error == NULL) error = got_error_from_errno("fclose"); if (repo) got_repo_close(repo); if (pack_fds) { const struct got_error *pack_err; pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } got_pathlist_free(&include_args, GOT_PATHLIST_FREE_NONE); got_pathlist_free(&available_refs, GOT_PATHLIST_FREE_ALL); free(repo_path); return error; } got-portable-0.119/gotadmin/Makefile.am0000664000175000017500000000375015066536113013457 bin_PROGRAMS = gotadmin include $(top_builddir)/Makefile.common gotadmin_SOURCES = gotadmin.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dump.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/load.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_admin.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree_open.c gotadmin_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotadmin.1 man1_MANS = gotadmin.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm LDADD += $(libbsd_LIBS) $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(zlib_CFLAGS) $(libuuid_CFLAGS) \ $(libmd_CFLAGS) got-portable-0.119/gotadmin/gotadmin.10000664000175000017500000003314215066535721013311 .\" .\" Copyright (c) 2021 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTADMIN 1 .Os .Sh NAME .Nm gotadmin .Nd Game of Trees repository administration .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Sh DESCRIPTION .Nm is the repository maintenance tool for the .Xr got 1 version control system. .Pp .Xr got 1 stores the history of tracked files in a Git repository, as used by the Git version control system. .Nm provides commands for inspecting and manipulating the on-disk state of Git repositories. The repository format is described in .Xr git-repository 5 . .Pp .Nm provides global and command-specific options. Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information and exit immediately. .It Fl V , -version Display program version and exit immediately. .El .Pp The commands for .Nm are as follows: .Bl -tag -width checkout .It Cm init Oo Fl A Ar hashing-algorithm Oc Oo Fl b Ar branch Oc Ar repository-path Create a new empty repository at the specified .Ar repository-path . .Pp After .Cm gotadmin init , the new repository must be populated before .Cm got checkout can be used. The .Cm got import command can be used to populate the new repository with data from a local directory. Alternatively, on a server running .Xr gotd 8 , the new repository can be made available to .Xr got 1 or .Xr git 1 clients by adding the repository to .Xr gotd.conf 5 and restarting .Xr gotd 8 . Clients may then clone the new repository from the server, populate the cloned repository, and then populate the new repository on the server via .Cm got send or .Cm git push . .Pp The options for .Cm gotadmin init are as follows: .Bl -tag -width Ds .It Fl A Ar hashing-algorithm Configure the repository's .Ar hashing-algorithm used for the computation of Git object IDs. Possible values are .Cm sha1 .Pq the default or .Cm sha256 . .It Fl b Ar branch Make the repository's HEAD reference point to the specified .Ar branch instead of the default branch .Dq main . .El .Pp The .Cm gotadmin init command is equivalent to .Cm got init . .It Cm info Op Fl r Ar repository-path Display information about a repository. This includes some configuration settings from .Xr got.conf 5 , the object ID hashing algorithm, and the number of objects stored in the repository, in packed or loose form, as well as the current on-disk size of these objects. .Pp The options for .Cm gotadmin info are as follows: .Bl -tag -width Ds .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm pack .Op Fl aDq .Op Fl r Ar repository-path .Op Fl x Ar reference .Op Ar reference ... .Xc Generate a new pack file and a corresponding pack file index. By default, add any loose objects which are reachable via any references to the generated pack file. .Pp If one or more .Ar reference arguments is specified, only add objects which are reachable via the specified references. Each .Ar reference argument may either specify a specific reference or a reference namespace, in which case all references within this namespace will be used. .Pp .Cm gotadmin pack always ignores references in the .Pa refs/got/ namespace, effectively treating such references as if they did not refer to any objects. .Pp The options for .Cm gotadmin pack are as follows: .Bl -tag -width Ds .It Fl a Add objects to the generated pack file even if they are already packed in a different pack file. Unless this option is specified, only loose objects will be added. .It Fl D Force the use of ref-delta representation for deltified objects. If this option is not specified, offset-deltas will be used to represent deltified objects. .It Fl q Suppress progress reporting output. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .It Fl x Ar reference Exclude objects reachable via the specified .Ar reference from the pack file. The .Ar reference argument may either specify a specific reference or a reference namespace, in which case all references within this namespace will be excluded. The .Fl x option may be specified multiple times to build a list of references to exclude. .Pp Exclusion takes precedence over inclusion. If a reference appears in both the included and excluded lists, it will be excluded. .El .Tg ix .It Cm indexpack Ar packfile-path .Dl Pq alias: Cm ix Create a pack index for the pack file at .Ar packfile-path . .Pp A pack index is required for using the corresponding pack file with .Xr got 1 . Usually, a pack index will be created by commands such as .Cm gotadmin pack or .Cm got fetch as part of regular operation. The .Cm gotadmin indexpack command may be used to recover from a corrupt or missing index. A given pack file will always yield the same bit-identical index. .Pp The provided .Ar packfile-path must be located within the .Pa objects/pack/ directory of the repository and should end in .Pa .pack . The filename of the corresponding pack index is equivalent, except that it ends in .Pa .idx . .Tg ls .It Xo .Cm listpack .Op Fl hs .Ar packfile-path .Xc .Dl Pq alias: Cm ls List the contents of the pack file at .Ar packfile-path . .Pp Each object contained in the pack file will be displayed on a single line. The information shown includes the object ID, object type, object offset, and object size. .Pp If a packed object is deltified against another object, the delta base will be shown as well. For offset deltas, the delta base is identified via an offset into the pack file. For reference deltas, the delta base is identified via an object ID. .Pp The provided .Ar packfile-path must be located within the .Pa objects/pack/ directory of the repository and should end in .Pa .pack . The corresponding pack index must exist and can be created with .Cm gotadmin indexpack if it is missing. .Pp The options for .Cm gotadmin listpack are as follows: .Bl -tag -width Ds .It Fl h Show object sizes in human-readable form. .It Fl s Display statistics about the pack file after listing objects. This includes the total number of objects stored in the pack file and a break-down of the number of objects per object type. .El .Tg cl .It Xo .Cm cleanup .Op Fl anpq .Op Fl r Ar repository-path .Xc .Dl Pq alias: Cm cl Repack the repository and then purge unreferenced loose objects and redundant pack files. Display the amount of disk space which has been freed as a result. .Pp Unreferenced objects are present in the repository but cannot be reached via any reference in the entire .Pa refs/ namespace. Objects will usually become unreferenced as a result of deleting branches, tags, or other references with .Cm got branch -d , .Cm got ref -d , or .Cm got fetch -X . .Pp Loose objects are stored as individual files in subdirectories of the repository's .Pa objects/ directory. .Pp Packed objects are stored in pack files under .Pa objects/pack/ . .Pp If redundant copies of packed objects exist in loose form, such redundant copies will be purged. If all the objects of a pack file are present in a bigger pack file, the redundant smaller pack file will be purged. .Pp References in the .Pa refs/got namespace may prevent objects from being purged. This includes references in the .Pa refs/got/worktree namespace created by .Cm got checkout and .Cm got update , as well as references in the .Pa refs/got/backup namespace created by .Cm got rebase and .Cm got histedit . .Cm gotadmin cleanup will only purge corresponding objects once such references have been deleted with .Cm got rebase -X , .Cm got histedit -X , or .Cm got ref -d . .Pp The .Dq preciousObjects Git extension is intended to prevent the removal of objects from a repository. .Cm gotadmin cleanup will refuse to operate on repositories where this extension is active. .Pp For compatibility with Git, if a file with the extension .Pa .keep exists and corresponds to a pack file with the extension .Pa .pack then this pack file will not be removed. .Pp Some Git repositories contain pack index files which lack a corresponding pack file, which is an inconsistent repository state. In such cases, .Cm gotadmin cleanup -p -n will display a list of affected pack index files. Whenever possible, the missing pack files should be restored. If restoring missing pack files is not possible, then affected pack index files can be removed with .Cm gotadmin cleanup -p . .Pp The options for .Cm gotadmin cleanup are as follows: .Bl -tag -width Ds .It Fl a Delete all redundant loose and packed objects. By default, objects which are newer than an implementation-defined modification timestamp are kept on disk to prevent race conditions with other commands that add new objects to the repository while .Cm gotadmin cleanup is running. .It Fl n Display the usual progress output and summary information but do not actually remove any files from disk. .It Fl p Instead of purging unreferenced loose objects and redundant pack files, remove any pack index files which do not have a corresponding pack file. .It Fl q Suppress progress reporting and disk space summary output. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm dump .Op Fl q .Op Fl r Ar repository-path .Op Fl x Ar reference .Op Ar reference ... .Xc Dump the contents of the repository to standard output in Git bundle format. .Pp If one or more .Ar reference arguments is specified, only add objects which are reachable via the specified references. Each .Ar reference argument may either specify a specific reference or a reference namespace, in which case all references within this namespace will be used. .Pp The options for .Nm .Cm dump are as follows: .Bl -tag -width Ds .It Fl q Suppress progress reporting output. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .It Fl x Ar reference Exclude objects reachable via the specified .Ar reference from the bundle. The .Ar reference argument may either specify a specific reference or a reference namespace, in which case all references within this namespace will be excluded. The .Fl x option may be specified multiple times to build a list of references to exclude. .Pp Exclusion takes precedence over inclusion. If a reference appears in both the included and excluded lists, it will be excluded. .El .It Xo .Cm load .Op Fl nq .Op Fl l Ar bundle-path .Op Fl r Ar repository-path .Op Ar reference ... .Xc Read a Git bundle stream from standard input and load its data into a repository. .Pp If one or more .Ar reference arguments are provided then only load the specified references from the bundle. Otherwise, all references will be loaded. .Pp The options for .Cm gotadmin load are as follows: .Bl -tag -width Ds .It Fl l Ar bundle-path List references available for loading from the bundle at the specified .Ar bundle-path and exit immediately. If the .Fl l option is specified then no .Ar reference arguments are allowed. The .Fl l option is incompatible with the .Fl n option. .It Fl n Attempt to load the bundle but don't install new packfile or update any reference. Can be used to verify the integrity of the bundle. .It Fl q Suppress progress reporting output. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .El .Sh EXIT STATUS .Ex -std gotadmin .Sh SEE ALSO .Xr got 1 , .Xr tog 1 , .Xr git-repository 5 , .Xr got.conf 5 .Sh AUTHORS .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Josh Rickmar Aq Mt jrick@zettaport.com .An Klemens Nanni Aq Mt kn@openbsd.org .An Omar Polo Aq Mt op@openbsd.org .An Ori Bernstein Aq Mt ori@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Tracey Emery Aq Mt tracey@traceyemery.net .Sh CAVEATS .Nm is a work-in-progress and some features remain to be implemented. .Pp At present, the user has to fall back on .Xr git 1 to perform some tasks. In particular: .Bl -bullet .It Exporting data from repositories requires .Xr git-fast-export 1 . .It Importing data into repositories requires .Xr git-fast-import 1 . .El .Sh BUGS Disk space savings reported by .Cm gotadmin cleanup will be misleading if the repository contains object files that were hard-linked from another repository. Such hard-links will be created by certain .Xr git 1 commands. By itself, .Xr got 1 will never create hard-linked object files. got-portable-0.119/gotadmin/Makefile.in0000664000175000017500000012205615066537207013476 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = gotadmin$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotadmin ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gotadmin_OBJECTS = gotadmin.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/dump.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/load.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_privsep.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/repository_admin.$(OBJEXT) \ $(top_builddir)/lib/repository_init.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) gotadmin_OBJECTS = $(am_gotadmin_OBJECTS) gotadmin_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/dump.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/load.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/repository_admin.Po \ $(top_builddir)/lib/$(DEPDIR)/repository_init.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/gotadmin.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(gotadmin_SOURCES) DIST_SOURCES = $(gotadmin_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(zlib_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ gotadmin_SOURCES = gotadmin.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dump.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/load.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/repository_admin.c \ $(top_srcdir)/lib/repository_init.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/worktree_open.c gotadmin_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotadmin.1 man1_MANS = gotadmin.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libbsd_LIBS) \ $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotadmin/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotadmin/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: -$(am__rm_f) $(bin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dump.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/load.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository_admin.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository_init.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gotadmin$(EXEEXT): $(gotadmin_OBJECTS) $(gotadmin_DEPENDENCIES) $(EXTRA_gotadmin_DEPENDENCIES) @rm -f gotadmin$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotadmin_OBJECTS) $(gotadmin_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dump.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/load.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository_admin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository_init.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotadmin.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dump.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/load.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_admin.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/gotadmin.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dump.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/load.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_admin.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository_init.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/gotadmin.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotd/0000775000175000017500000000000015066537274010642 5got-portable-0.119/gotd/notify.h0000664000175000017500000000147215066535721012242 /* * Copyright (c) 2024 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void notify_main(const char *); got-portable-0.119/gotd/gotd.c0000664000175000017500000030337615066536113011666 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_opentemp.h" #include "got_path.h" #include "got_repository.h" #include "got_object.h" #include "got_reference.h" #include "got_diff.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_hash.h" #include "got_lib_gitproto.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "gotd.h" #include "log.h" #include "listen.h" #include "auth.h" #include "session_read.h" #include "session_write.h" #include "repo_read.h" #include "repo_write.h" #include "notify.h" #include "secrets.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif enum gotd_client_state { GOTD_CLIENT_STATE_NEW, GOTD_CLIENT_STATE_ACCESS_GRANTED, GOTD_CLIENT_STATE_NOTIFY, }; struct gotd_child_proc { pid_t pid; enum gotd_procid type; char repo_name[NAME_MAX]; char repo_path[PATH_MAX]; int pipe[2]; struct gotd_imsgev iev; struct event tmo; TAILQ_ENTRY(gotd_child_proc) entry; }; TAILQ_HEAD(gotd_procs, gotd_child_proc) procs; struct gotd_client { STAILQ_ENTRY(gotd_client) entry; enum gotd_client_state state; uint32_t id; int fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; struct gotd_child_proc *repo; struct gotd_child_proc *auth; struct gotd_child_proc *session; struct gotd_child_proc *gotsys; int gotsys_conf_fd; int required_auth; int gotsys_error_sent; struct timespec time_connected; char repo_name[NAME_MAX]; }; STAILQ_HEAD(gotd_clients, gotd_client); static struct gotd_clients gotd_clients[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY clients_hash_key; volatile int client_cnt; static struct timeval auth_timeout = { 5, 0 }; static struct gotd gotd; static int gotd_socket = -1; static int gotd_reload_conf_fd = -1; static int gotd_reload_secrets_fd = -1; static int have_reload_secrets; static char *gotd_reload_secrets_path; static int listener_halted; static uint32_t reload_client_id; void gotd_sighdlr(int sig, short event, void *arg); static void gotd_shutdown(void); static const struct got_error *start_session_child(struct gotd_client *, struct gotd_repo *, char *, const char *, int, int); static const struct got_error *start_repo_child(struct gotd_client *, enum gotd_procid, struct gotd_repo *, char *, const char *, int, int); static const struct got_error *start_auth_child(struct gotd_client *, int, struct gotd_repo *, char *, const char *, int, int); static void kill_proc(struct gotd_child_proc *, int); static void disconnect(struct gotd_client *); static pid_t start_child(enum gotd_procid, const char *, char *, const char *, const char *, int, int, int); static void kill_proc_timeout(int, short, void *); __dead static void usage(void) { fprintf(stderr, "usage: %s [-dnv] [-f config-file] [-s secrets]\n", getprogname()); exit(1); } static void drop_privs(struct passwd *pw) { /* Drop root privileges. */ if (setgid(pw->pw_gid) == -1) fatal("setgid %d failed", pw->pw_gid); if (setuid(pw->pw_uid) == -1) fatal("setuid %d failed", pw->pw_uid); } static int unix_socket_listen(const char *unix_socket_path, uid_t uid, gid_t gid) { struct sockaddr_un sun; int fd = -1; mode_t old_umask, mode; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif fd = socket(AF_UNIX, sock_flags, 0); if (fd == -1) { log_warn("socket"); return -1; } sun.sun_family = AF_UNIX; if (strlcpy(sun.sun_path, unix_socket_path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { log_warnx("%s: name too long", unix_socket_path); close(fd); return -1; } if (unlink(unix_socket_path) == -1) { if (errno != ENOENT) { log_warn("unlink %s", unix_socket_path); close(fd); return -1; } } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { log_warn("bind: %s", unix_socket_path); close(fd); umask(old_umask); return -1; } umask(old_umask); if (chmod(unix_socket_path, mode) == -1) { log_warn("chmod %o %s", mode, unix_socket_path); close(fd); unlink(unix_socket_path); return -1; } if (chown(unix_socket_path, uid, gid) == -1) { log_warn("chown %s uid=%d gid=%d", unix_socket_path, uid, gid); close(fd); unlink(unix_socket_path); return -1; } if (listen(fd, GOTD_UNIX_SOCKET_BACKLOG) == -1) { log_warn("listen"); close(fd); unlink(unix_socket_path); return -1; } return fd; } static void clients_init(void) { uint64_t slot; arc4random_buf(&clients_hash_key, sizeof(clients_hash_key)); for (slot = 0; slot < nitems(gotd_clients); slot++) STAILQ_INIT(&gotd_clients[slot]); } static uint64_t client_hash(uint32_t client_id) { return SipHash24(&clients_hash_key, &client_id, sizeof(client_id)); } static void add_client(struct gotd_client *client) { uint64_t slot = client_hash(client->id) % nitems(gotd_clients); STAILQ_INSERT_HEAD(&gotd_clients[slot], client, entry); client_cnt++; } static struct gotd_client * find_client(uint32_t client_id) { uint64_t slot; struct gotd_client *c; slot = client_hash(client_id) % nitems(gotd_clients); STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->id == client_id) return c; } return NULL; } static struct gotd_client * find_client_by_proc_fd(int fd) { uint64_t slot; for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c; STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->repo && c->repo->iev.ibuf.fd == fd) return c; if (c->auth && c->auth->iev.ibuf.fd == fd) return c; if (c->session && c->session->iev.ibuf.fd == fd) return c; if (c->gotsys && c->gotsys->pipe[0] == fd) return c; } } return NULL; } static int client_is_reading(struct gotd_client *client) { return (client->required_auth & (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == GOTD_AUTH_READ; } static int client_is_writing(struct gotd_client *client) { return (client->required_auth & (GOTD_AUTH_READ | GOTD_AUTH_WRITE)) == (GOTD_AUTH_READ | GOTD_AUTH_WRITE); } static const struct got_error * ensure_client_is_not_writing(struct gotd_client *client) { if (client_is_writing(client)) { return got_error_fmt(GOT_ERR_BAD_PACKET, "uid %d made a read-request but is writing to " "a repository", client->euid); } return NULL; } static const struct got_error * ensure_client_is_not_reading(struct gotd_client *client) { if (client_is_reading(client)) { return got_error_fmt(GOT_ERR_BAD_PACKET, "uid %d made a write-request but is reading from " "a repository", client->euid); } return NULL; } static void proc_done(struct gotd_child_proc *proc) { struct gotd_client *client; int do_disconnect = 0; TAILQ_REMOVE(&procs, proc, entry); client = find_client_by_proc_fd(proc->iev.ibuf.fd); if (client == NULL) client = find_client_by_proc_fd(proc->pipe[0]); if (client != NULL) { if (proc == client->repo) { client->repo = NULL; do_disconnect = 1; } if (proc == client->auth) { client->auth = NULL; do_disconnect = 1; } if (proc == client->session) { client->session = NULL; do_disconnect = 1; } if (proc == client->gotsys) client->gotsys = NULL; } if (proc == gotd.notify_proc) gotd.notify_proc = NULL; evtimer_del(&proc->tmo); if (proc->iev.ibuf.fd != -1) { event_del(&proc->iev.ev); imsgbuf_clear(&proc->iev.ibuf); close(proc->iev.ibuf.fd); } free(proc); if (do_disconnect) disconnect(client); } static void kill_repo_proc(struct gotd_client *client) { if (client->repo == NULL) return; kill_proc(client->repo, 0); client->repo = NULL; } static void kill_auth_proc(struct gotd_client *client) { if (client->auth == NULL) return; kill_proc(client->auth, 0); client->auth = NULL; } static void kill_session_proc(struct gotd_client *client) { if (client->session == NULL) return; kill_proc(client->session, 0); client->session = NULL; } static void kill_gotsys_proc(struct gotd_client *client) { if (client->gotsys == NULL) return; kill_proc(client->gotsys, 0); client->gotsys = NULL; } static void disconnect(struct gotd_client *client) { struct gotd_imsg_disconnect idisconnect; struct gotd_child_proc *listen_proc = gotd.listen_proc; uint64_t slot; log_debug("uid %d: disconnecting", client->euid); kill_auth_proc(client); kill_session_proc(client); kill_repo_proc(client); kill_gotsys_proc(client); idisconnect.client_id = client->id; if (gotd_imsg_compose_event(&listen_proc->iev, GOTD_IMSG_DISCONNECT, GOTD_PROC_GOTD, -1, &idisconnect, sizeof(idisconnect)) == -1) log_warn("imsg compose DISCONNECT"); slot = client_hash(client->id) % nitems(gotd_clients); STAILQ_REMOVE(&gotd_clients[slot], client, gotd_client, entry); imsgbuf_clear(&client->iev.ibuf); event_del(&client->iev.ev); evtimer_del(&client->tmo); if (client->fd != -1) close(client->fd); else if (client->iev.ibuf.fd != -1) close(client->iev.ibuf.fd); free(client->username); free(client); client_cnt--; if (listener_halted && client_cnt == 0) event_loopexit(NULL); } static void disconnect_on_error(struct gotd_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); if (client->fd != -1) { if (imsgbuf_init(&ibuf, client->fd) != -1) { gotd_imsg_send_error(&ibuf, 0, GOTD_PROC_GOTD, err); imsgbuf_clear(&ibuf); } else log_warn("%s: imsgbuf_init failed", __func__); } } disconnect(client); } static const struct got_error * send_repo_info(struct gotd_imsgev *iev, struct gotd_repo *repo) { const struct got_error *err = NULL; struct gotd_imsg_info_repo irepo; memset(&irepo, 0, sizeof(irepo)); if (strlcpy(irepo.repo_name, repo->name, sizeof(irepo.repo_name)) >= sizeof(irepo.repo_name)) return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long"); if (strlcpy(irepo.repo_path, repo->path, sizeof(irepo.repo_path)) >= sizeof(irepo.repo_path)) return got_error_msg(GOT_ERR_NO_SPACE, "repo path too long"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_REPO, GOTD_PROC_GOTD, -1, &irepo, sizeof(irepo)) == -1) { err = got_error_from_errno("imsg compose INFO_REPO"); if (err) return err; } return NULL; } static const struct got_error * send_client_info(struct gotd_imsgev *iev, struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_info_client iclient; struct gotd_child_proc *proc; memset(&iclient, 0, sizeof(iclient)); iclient.euid = client->euid; iclient.egid = client->egid; if (strlcpy(iclient.repo_name, client->repo_name, sizeof(iclient.repo_name)) >= sizeof(iclient.repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repo name too long"); } proc = client->repo; if (proc) iclient.repo_child_pid = proc->pid; if (client_is_writing(client)) iclient.is_writing = 1; if (client->session) iclient.session_child_pid = client->session->pid; iclient.time_connected = client->time_connected.tv_sec; if (gotd_imsg_compose_event(iev, GOTD_IMSG_INFO_CLIENT, GOTD_PROC_GOTD, -1, &iclient, sizeof(iclient)) == -1) { err = got_error_from_errno("imsg compose INFO_CLIENT"); if (err) return err; } return NULL; } static const struct got_error * send_info(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_info info; uint64_t slot; struct gotd_repo *repo; if (client->euid != 0) return got_error_set_errno(EPERM, "info"); info.pid = gotd.pid; info.verbosity = gotd.verbosity; info.nrepos = gotd.nrepos; info.nclients = client_cnt - 1; if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_INFO, GOTD_PROC_GOTD, -1, &info, sizeof(info)) == -1) { err = got_error_from_errno("imsg compose INFO"); if (err) return err; } TAILQ_FOREACH(repo, &gotd.repos, entry) { err = send_repo_info(&client->iev, repo); if (err) return err; } for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c; STAILQ_FOREACH(c, &gotd_clients[slot], entry) { if (c->id == client->id) continue; err = send_client_info(&client->iev, c); if (err) return err; } } return NULL; } static const struct got_error * stop_gotd(struct gotd_client *client) { if (client->euid != 0) return got_error_set_errno(EPERM, "stop"); gotd_shutdown(); /* NOTREACHED */ return NULL; } static const struct got_error * send_reload_config(struct gotd_imsgev *iev) { const struct got_error *err = NULL; int fd; fd = dup(gotd_socket); if (fd == -1) { err = got_error_from_errno("dup"); goto done; } if (imsg_compose(&iev->ibuf, GOTD_IMSG_LISTEN_SOCKET, GOTD_PROC_GOTD, gotd.pid, fd, NULL, 0) == -1) { close(fd); err = got_error_from_errno("imsg compose LISTEN_SOCKET"); goto done; } if (imsg_compose(&iev->ibuf, GOTD_IMSG_RELOAD_SECRETS, GOTD_PROC_GOTD, gotd.pid, gotd_reload_secrets_fd, gotd_reload_secrets_path ? gotd_reload_secrets_path : NULL, gotd_reload_secrets_path ? strlen(gotd_reload_secrets_path) : 0) == -1) { err = got_error_from_errno("imsg compose RELOAD_SECRETS"); goto done; } if (imsg_compose(&iev->ibuf, GOTD_IMSG_GOTD_CONF, GOTD_PROC_GOTD, gotd.pid, gotd_reload_conf_fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose GOTD_CONF"); goto done; } err = gotd_imsg_flush(&iev->ibuf); if (err) return err; done: if (gotd_reload_conf_fd != -1) { close(gotd_reload_conf_fd); gotd_reload_conf_fd = -1; } if (gotd_reload_conf_fd != -1) { close(gotd_reload_secrets_fd); gotd_reload_secrets_fd = -1; } have_reload_secrets = 0; return err; } static const struct got_error * halt_listener(struct gotd_imsgev *iev) { if (gotd_imsg_compose_event(&gotd.listen_proc->iev, GOTD_IMSG_HALT, GOTD_PROC_GOTD, -1, &reload_client_id, sizeof(reload_client_id)) == -1) return got_error_from_errno("imsg compose HALT"); listener_halted = 1; return NULL; } static void reload_reset(void) { /* Clear state such that reloading again will work. */ close(gotd_reload_conf_fd); gotd_reload_conf_fd = -1; close(gotd_reload_secrets_fd); gotd_reload_secrets_fd = -1; have_reload_secrets = 0; } static void gotd_dispatch_reload(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = gotd.reload_proc; ssize_t n; int shut = 0; struct imsg imsg; if (proc->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_RELOAD_READY: err = send_reload_config(iev); if (err) break; err = halt_listener(iev); if (err) break; shut = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (err) { log_warnx("reloading failed: %s", err->msg); kill_proc(gotd.reload_proc, 0); gotd.reload_proc = NULL; imsg_free(&imsg); reload_reset(); return; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); if (listener_halted && client_cnt == 0) event_loopexit(NULL); } } static const struct got_error * reload_gotd(struct gotd_client *client, struct imsg *imsg) { const struct got_error *err = NULL; size_t datalen; char *confpath = NULL; struct gotd_child_proc *proc = NULL; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (client->euid != 0) return got_error_set_errno(EPERM, "reload"); if (gotd.reload_proc != NULL || gotd_reload_conf_fd != -1) return got_error_set_errno(EALREADY, "reload"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen == 0) return got_error(GOT_ERR_PRIVSEP_LEN); confpath = strndup(imsg->data, datalen); if (confpath == NULL) return got_error_from_errno("strndup"); gotd_reload_conf_fd = imsg_get_fd(imsg); if (gotd_reload_conf_fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (fcntl(gotd_reload_conf_fd, F_SETFD, FD_CLOEXEC) == -1) { err = got_error_from_errno("fcntl"); goto done; } /* TODO: parse provided config for verification */ proc = calloc(1, sizeof(*proc)); if (proc == NULL) { err = got_error_from_errno("calloc"); goto done; } proc->type = GOTD_PROC_RELOAD; if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) { err = got_error_from_errno("socketpair"); free(proc); proc = NULL; goto done; } if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } proc->pid = start_child(GOTD_PROC_RELOAD, NULL, gotd.argv0, confpath, gotd_reload_secrets_path, proc->pipe[1], gotd.daemonize, gotd.verbosity); imsgbuf_allow_fdpass(&proc->iev.ibuf); proc->iev.handler = gotd_dispatch_reload; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_reload, &proc->iev); gotd_imsg_event_add(&proc->iev); evtimer_set(&proc->tmo, kill_proc_timeout, proc); TAILQ_INSERT_HEAD(&procs, proc, entry); gotd.reload_proc = proc; log_info("gotd is reloading with PID %d", proc->pid); reload_client_id = client->id; done: if (err) { if (proc) { close(proc->pipe[0]); close(proc->pipe[1]); free(proc); } } free(confpath); return err; } static const struct got_error * start_client_authentication(struct gotd_client *client, struct imsg *imsg) { const struct got_error *err; struct gotd_imsg_list_refs ireq; struct gotd_repo *repo = NULL; size_t datalen; log_debug("list-refs request from uid %d", client->euid); if (client->state != GOTD_CLIENT_STATE_NEW) return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected list-refs request received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); if (ireq.client_is_reading) { err = ensure_client_is_not_writing(client); if (err) return err; repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); if (strlcpy(client->repo_name, repo->name, sizeof(client->repo_name)) >= sizeof(client->repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } err = start_auth_child(client, GOTD_AUTH_READ, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) return err; } else { err = ensure_client_is_not_reading(client); if (err) return err; repo = gotd_find_repo_by_name(ireq.repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); if (strlcpy(client->repo_name, repo->name, sizeof(client->repo_name)) >= sizeof(client->repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } err = start_auth_child(client, GOTD_AUTH_READ | GOTD_AUTH_WRITE, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) return err; } evtimer_add(&client->tmo, &auth_timeout); /* Flow continues upon authentication success/failure or timeout. */ return NULL; } static const struct got_error * recv_reload_secrets(struct imsg *imsg) { const struct got_error *err = NULL; size_t datalen; gotd_reload_secrets_fd = imsg_get_fd(imsg); if (gotd_reload_secrets_fd == -1) return NULL; /* no secrets being used */ if (fcntl(gotd_reload_secrets_fd, F_SETFD, FD_CLOEXEC) == -1) { err = got_error_from_errno("fcntl"); goto done; } datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen == 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } gotd_reload_secrets_path = strndup(imsg->data, datalen); if (gotd_reload_secrets_path == NULL) err = got_error_from_errno("strndup"); done: if (err) { if (gotd_reload_secrets_fd != -1) { close(gotd_reload_secrets_fd); gotd_reload_secrets_fd = -1; } free(gotd_reload_secrets_path); gotd_reload_secrets_path = NULL; } return err; } static void gotd_request(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client = iev->handler_arg; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; int do_disconnect = 0; if (events & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { /* * The client has closed its socket. This can * happen when Git clients are done sending * pack file data. */ if (err->code == GOT_ERR_ERRNO && errno == EPIPE) { disconnect(client); return; } disconnect_on_error(client, err); return; } /* Disconnect gotctl(8) if all messages have been sent. */ if (!client_is_reading(client) && !client_is_writing(client) && imsgbuf_queuelen(ibuf) == 0) { disconnect(client); return; } } if (events & EV_READ) { n = imsgbuf_read(ibuf); if (n == -1) { err = got_error_from_errno("imsgbuf_read"); disconnect_on_error(client, err); return; } if (n == 0) { err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } while (err == NULL && !do_disconnect) { n = imsg_get(ibuf, &imsg); if (n == -1) { err = got_error_from_errno("imsg_get"); break; } if (n == 0) break; evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_INFO: err = send_info(client); break; case GOTD_IMSG_STOP: err = stop_gotd(client); break; case GOTD_IMSG_RELOAD_SECRETS: if (have_reload_secrets) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = recv_reload_secrets(&imsg); if (err) break; have_reload_secrets = 1; break; case GOTD_IMSG_RELOAD: err = reload_gotd(client, &imsg); if (err) break; do_disconnect = 1; break; case GOTD_IMSG_LIST_REFS: err = start_client_authentication(client, &imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { disconnect_on_error(client, err); } else if (do_disconnect) { disconnect(client); } else { gotd_imsg_event_add(&client->iev); } } static void gotd_auth_timeout(int fd, short events, void *arg) { struct gotd_client *client = arg; log_debug("disconnecting uid %d due to authentication timeout", client->euid); disconnect(client); } static const struct got_error * recv_connect(uint32_t *client_id, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_connect iconnect; size_t datalen; struct gotd_client *client = NULL; *client_id = 0; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); if (find_client(iconnect.client_id)) { err = got_error_msg(GOT_ERR_CLIENT_ID, "duplicate client ID"); goto done; } client = calloc(1, sizeof(*client)); if (client == NULL) { err = got_error_from_errno("calloc"); goto done; } *client_id = iconnect.client_id; client->state = GOTD_CLIENT_STATE_NEW; client->id = iconnect.client_id; /* The auth process will verify UID/GID for us. */ client->euid = iconnect.euid; client->egid = iconnect.egid; if (clock_gettime(CLOCK_REALTIME, &client->time_connected) == -1) { err = got_error_from_errno("clock_gettime"); goto done; } client->fd = imsg_get_fd(imsg); if (client->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } if (fcntl(client->fd, F_SETFD, FD_CLOEXEC) == -1) { err = got_error_from_errno("fcntl"); goto done; } if (imsgbuf_init(&client->iev.ibuf, client->fd) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&client->iev.ibuf); client->iev.handler = gotd_request; client->iev.events = EV_READ; client->iev.handler_arg = client; client->gotsys_conf_fd = -1; event_set(&client->iev.ev, client->fd, EV_READ, gotd_request, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_auth_timeout, client); add_client(client); log_debug("%s: new client uid %d connected on fd %d", __func__, client->euid, client->fd); done: if (err && client) { struct gotd_child_proc *listen_proc = gotd.listen_proc; struct gotd_imsg_disconnect idisconnect; idisconnect.client_id = client->id; if (gotd_imsg_compose_event(&listen_proc->iev, GOTD_IMSG_DISCONNECT, GOTD_PROC_GOTD, -1, &idisconnect, sizeof(idisconnect)) == -1) log_warn("imsg compose DISCONNECT"); if (client->fd != -1) close(client->fd); free(client); } return err; } static const char *gotd_proc_names[GOTD_PROC_MAX] = { "parent", "listen", "auth", "session_read", "session_write", "repo_read", "repo_write", "gitwrapper", "notify", "gotsys-check", "gotsys-apply", "reload", "gotctl", }; static void kill_proc(struct gotd_child_proc *proc, int fatal) { struct timeval tv = { 5, 0 }; log_debug("kill -%d %d", fatal ? SIGKILL : SIGTERM, proc->pid); if (proc->iev.ibuf.fd != -1) { event_del(&proc->iev.ev); imsgbuf_clear(&proc->iev.ibuf); close(proc->iev.ibuf.fd); proc->iev.ibuf.fd = -1; } if (!evtimer_pending(&proc->tmo, NULL) && !fatal) evtimer_add(&proc->tmo, &tv); if (fatal) { log_warnx("sending SIGKILL to PID %d", proc->pid); kill(proc->pid, SIGKILL); } else kill(proc->pid, SIGTERM); } static void kill_proc_timeout(int fd, short ev, void *d) { struct gotd_child_proc *proc = d; log_warnx("timeout waiting for PID %d to terminate;" " retrying with force", proc->pid); kill_proc(proc, 1); } static void gotd_shutdown(void) { uint64_t slot; log_debug("shutting down"); for (slot = 0; slot < nitems(gotd_clients); slot++) { struct gotd_client *c, *tmp; STAILQ_FOREACH_SAFE(c, &gotd_clients[slot], entry, tmp) disconnect(c); } kill_proc(gotd.listen_proc, 0); free(gotd.default_sender); log_info("terminating"); exit(0); } static struct gotd_child_proc * find_proc_by_pid(pid_t pid) { struct gotd_child_proc *proc = NULL; TAILQ_FOREACH(proc, &procs, entry) if (proc->pid == pid) break; return proc; } static const struct got_error * gotsys_exit(struct gotd_child_proc *proc, int status) { struct gotd_client *client; log_debug("%s (PID %d) %s", gotd_proc_names[proc->type], proc->pid, WEXITSTATUS(status) == 0 ? "succeeded" : "failed"); client = find_client_by_proc_fd(proc->pipe[0]); if (client == NULL || client->session == NULL) return NULL; if (proc->type == GOTD_PROC_GOTSYS_CHECK && WEXITSTATUS(status) != 0 && !client->gotsys_error_sent) { const struct got_error *err; err = got_error_fmt(GOT_ERR_PARSE_CONFIG, "%s failure", gotd_proc_names[proc->type]); if (gotd_imsg_send_error_event(&client->session->iev, GOTD_PROC_GOTD, client->id, err) == -1) log_warn("imsg send error"); } return NULL; } void gotd_sighdlr(int sig, short event, void *arg) { const struct got_error *err; struct gotd_child_proc *proc; pid_t pid; int status; /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("ignoring SIGHUP; run 'gotctl reload' instead"); break; case SIGUSR1: log_info("ignoring SIGUSR1"); break; case SIGTERM: case SIGINT: gotd_shutdown(); break; case SIGCHLD: for (;;) { pid = waitpid(WAIT_ANY, &status, WNOHANG); if (pid == -1) { if (errno == EINTR) continue; if (errno == ECHILD) break; fatal("waitpid"); } if (pid == 0) break; log_debug("reaped pid %d", pid); proc = find_proc_by_pid(pid); if (proc == NULL) { log_info("caught exit of unknown child %d", pid); continue; } if (WIFSIGNALED(status)) { log_warnx("child PID %d terminated with" " signal %d", pid, WTERMSIG(status)); } if (proc->type == GOTD_PROC_GOTSYS_CHECK || proc->type == GOTD_PROC_GOTSYS_APPLY) { err = gotsys_exit(proc, status); if (err) log_warn("%s", err->msg); } proc_done(proc); } break; default: fatalx("unexpected signal"); } } static const struct got_error * ensure_proc_is_reading(struct gotd_client *client, struct gotd_child_proc *proc) { if (!client_is_reading(client)) { kill_proc(proc, 1); return got_error_fmt(GOT_ERR_BAD_PACKET, "PID %d handled a read-request for uid %d but this " "user is not reading from a repository", proc->pid, client->euid); } return NULL; } static const struct got_error * ensure_proc_is_writing(struct gotd_client *client, struct gotd_child_proc *proc) { if (!client_is_writing(client)) { kill_proc(proc, 1); return got_error_fmt(GOT_ERR_BAD_PACKET, "PID %d handled a write-request for uid %d but this " "user is not writing to a repository", proc->pid, client->euid); } return NULL; } static int verify_imsg_src(struct gotd_client *client, struct gotd_child_proc *proc, struct imsg *imsg) { const struct got_error *err; int ret = 0; if (proc->type == GOTD_PROC_REPO_READ || proc->type == GOTD_PROC_REPO_WRITE) { if (client->repo == NULL) fatalx("no process found for uid %d", client->euid); if (proc->pid != client->repo->pid) { kill_proc(proc, 1); log_warnx("received message from PID %d for uid %d, " "while PID %d is the process serving this user", proc->pid, client->euid, client->repo->pid); return 0; } } if (proc->type == GOTD_PROC_SESSION_READ || proc->type == GOTD_PROC_SESSION_WRITE) { if (client->session == NULL) { log_warnx("no session found for uid %d", client->euid); return 0; } if (proc->pid != client->session->pid) { kill_proc(proc, 1); log_warnx("received message from PID %d for uid %d, " "while PID %d is the process serving this user", proc->pid, client->euid, client->session->pid); return 0; } } switch (imsg->hdr.type) { case GOTD_IMSG_ERROR: ret = 1; break; case GOTD_IMSG_CONNECT: if (proc->type != GOTD_PROC_LISTEN) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "new connection for uid %d from PID %d " "which is not the listen process", client->euid, proc->pid); } else ret = 1; break; case GOTD_IMSG_AUTH_READY: case GOTD_IMSG_ACCESS_GRANTED: if (proc->type != GOTD_PROC_AUTH) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "authentication of uid %d from PID %d " "which is not the auth process", client->euid, proc->pid); } else ret = 1; break; case GOTD_IMSG_CLIENT_SESSION_READY: if (proc->type != GOTD_PROC_SESSION_READ && proc->type != GOTD_PROC_SESSION_WRITE) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "unexpected \"ready\" signal from PID %d", proc->pid); } else ret = 1; break; case GOTD_IMSG_REPO_CHILD_READY: if (proc->type != GOTD_PROC_REPO_READ && proc->type != GOTD_PROC_REPO_WRITE) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "unexpected \"ready\" signal from PID %d", proc->pid); } else ret = 1; break; case GOTD_IMSG_PACKFILE_DONE: err = ensure_proc_is_reading(client, proc); if (err) log_warnx("uid %d: %s", client->euid, err->msg); else ret = 1; break; case GOTD_IMSG_PACKFILE_INSTALL: case GOTD_IMSG_REF_UPDATES_START: case GOTD_IMSG_REF_UPDATE: case GOTD_IMSG_REFS_UPDATED: err = ensure_proc_is_writing(client, proc); if (err) log_warnx("uid %d: %s", client->euid, err->msg); else ret = 1; break; case GOTD_IMSG_RUN_GOTSYS_CHECK: if (proc->type != GOTD_PROC_SESSION_WRITE) { err = got_error_fmt(GOT_ERR_BAD_PACKET, "unexpected \"ready\" signal from PID %d", proc->pid); break; } err = ensure_proc_is_writing(client, proc); if (err) { log_warnx("uid %d: %s", client->euid, err->msg); } ret = 1; break; default: log_debug("%s: unexpected imsg %d", __func__, imsg->hdr.type); break; } return ret; } static const struct got_error * connect_repo_child(struct gotd_client *client, struct gotd_child_proc *repo_proc) { static const struct got_error *err; struct gotd_imsgev *session_iev = &client->session->iev; struct gotd_imsg_connect_repo_child ireq; int pipe[2]; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected repo child ready signal received"); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1) fatal("socketpair"); memset(&ireq, 0, sizeof(ireq)); if (strlcpy(ireq.repo_name, repo_proc->repo_name, sizeof(ireq.repo_name)) >= sizeof(ireq.repo_name)) { err = got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); close(pipe[0]); close(pipe[1]); return err; } ireq.proc_id = repo_proc->type; /* Pass repo child pipe to session child process. */ if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_REPO_CHILD, GOTD_PROC_GOTD, pipe[0], &ireq, sizeof(ireq)) == -1) { err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD"); close(pipe[0]); close(pipe[1]); return err; } /* Pass session child pipe to repo child process. */ if (gotd_imsg_compose_event(&repo_proc->iev, GOTD_IMSG_CONNECT_REPO_CHILD, GOTD_PROC_GOTD, pipe[1], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_REPO_CHILD"); close(pipe[1]); return err; } return NULL; } static const struct got_error * setup_listener(struct gotd_imsgev *iev) { struct gotd_imsg_listen_socket isocket; size_t i; int fd; memset(&isocket, 0, sizeof(isocket)); isocket.nconnection_limits = gotd.nconnection_limits; fd = dup(gotd_socket); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LISTEN_SOCKET, GOTD_PROC_GOTD, fd, &isocket, sizeof(isocket)) == -1) { close(fd); return got_error_from_errno("imsg compose LISTEN_SOCKET"); } for (i = 0; i < gotd.nconnection_limits; i++) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_CONNECTION_LIMIT, GOTD_PROC_GOTD, -1, &gotd.connection_limits[i], sizeof(*gotd.connection_limits)) == -1) return got_error_from_errno("imsg compose " "CONNECTION_LIMIT"); } return NULL; } static void gotd_dispatch_listener(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = gotd.listen_proc; ssize_t n; int shut = 0; struct imsg imsg; if (proc->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; struct gotd_client *client = NULL; uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_LISTENER_READY: err = setup_listener(&proc->iev); break; case GOTD_IMSG_CONNECT: err = recv_connect(&client_id, &imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (client_id == 0) { if (err) log_warnx("%s", err->msg); imsg_free(&imsg); continue; } client = find_client(client_id); if (client == NULL) { log_warnx("%s: client not found", __func__); if (err) log_warnx("%s", err->msg); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * send_notification_target_email(struct gotd_imsgev *iev, const char *repo_name, struct gotd_notification_target *target) { struct gotd_imsg_notitfication_target_email itarget; struct ibuf *wbuf = NULL; memset(&itarget, 0, sizeof(itarget)); if (target->conf.email.sender) itarget.sender_len = strlen(target->conf.email.sender); else itarget.sender_len = strlen(gotd.default_sender); if (target->conf.email.recipient) itarget.recipient_len = strlen(target->conf.email.recipient); if (target->conf.email.responder) itarget.responder_len = strlen(target->conf.email.responder); if (target->conf.email.hostname) itarget.hostname_len = strlen(target->conf.email.hostname); if (target->conf.email.port) itarget.port_len = strlen(target->conf.email.port); itarget.repo_name_len = strlen(repo_name); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL, 0, 0, sizeof(itarget) + itarget.sender_len + itarget.recipient_len + itarget.responder_len + itarget.hostname_len + itarget.port_len + itarget.repo_name_len); if (wbuf == NULL) { return got_error_from_errno("imsg_create " "NOTIFICATION_TARGET_EMAIL"); } if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } if (target->conf.email.sender) { if (imsg_add(wbuf, target->conf.email.sender, itarget.sender_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } else { if (imsg_add(wbuf, gotd.default_sender, itarget.sender_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } if (target->conf.email.recipient) { if (imsg_add(wbuf, target->conf.email.recipient, itarget.recipient_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } if (target->conf.email.responder) { if (imsg_add(wbuf, target->conf.email.responder, itarget.responder_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } if (target->conf.email.hostname) { if (imsg_add(wbuf, target->conf.email.hostname, itarget.hostname_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } if (target->conf.email.port) { if (imsg_add(wbuf, target->conf.email.port, itarget.port_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } } if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_EMAIL"); } imsg_close(&iev->ibuf, wbuf); return gotd_imsg_flush(&iev->ibuf); } static const struct got_error * send_notification_target_http(struct gotd_imsgev *iev, const char *repo_name, struct gotd_notification_target *target) { struct gotd_imsg_notitfication_target_http itarget; struct ibuf *wbuf = NULL; memset(&itarget, 0, sizeof(itarget)); itarget.tls = target->conf.http.tls; itarget.hostname_len = strlen(target->conf.http.hostname); itarget.port_len = strlen(target->conf.http.port); itarget.path_len = strlen(target->conf.http.path); if (target->conf.http.auth) itarget.auth_len = strlen(target->conf.http.auth); if (target->conf.http.hmac) itarget.hmac_len = strlen(target->conf.http.hmac); itarget.repo_name_len = strlen(repo_name); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFICATION_TARGET_HTTP, 0, 0, sizeof(itarget) + itarget.hostname_len + itarget.port_len + itarget.path_len + itarget.auth_len + itarget.hmac_len + itarget.repo_name_len); if (wbuf == NULL) { return got_error_from_errno("imsg_create " "NOTIFICATION_TARGET_HTTP"); } if (imsg_add(wbuf, &itarget, sizeof(itarget)) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } if (imsg_add(wbuf, target->conf.http.hostname, itarget.hostname_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } if (imsg_add(wbuf, target->conf.http.port, itarget.port_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } if (imsg_add(wbuf, target->conf.http.path, itarget.path_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } if (target->conf.http.auth) { if (imsg_add(wbuf, target->conf.http.auth, itarget.auth_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } } if (target->conf.http.hmac) { if (imsg_add(wbuf, target->conf.http.hmac, itarget.hmac_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } } if (imsg_add(wbuf, repo_name, itarget.repo_name_len) == -1) { return got_error_from_errno("imsg_add " "NOTIFICATION_TARGET_HTTP"); } imsg_close(&iev->ibuf, wbuf); return gotd_imsg_flush(&iev->ibuf); } static const struct got_error * send_notification_target(struct gotd_imsgev *iev, const char *repo_name, struct gotd_notification_target *target) { const struct got_error *err = NULL; switch (target->type) { case GOTD_NOTIFICATION_VIA_EMAIL: err = send_notification_target_email(iev, repo_name, target); break; case GOTD_NOTIFICATION_VIA_HTTP: err = send_notification_target_http(iev, repo_name, target); break; default: log_warn("unsupported notification target type %d", target->type); break; } return err; } static const struct got_error * send_notification_targets(struct gotd_imsgev *iev, const char *repo_name, struct gotd_notification_targets *targets) { const struct got_error *err = NULL; struct gotd_notification_target *target; STAILQ_FOREACH(target, targets, entry) { err = send_notification_target(iev, repo_name, target); if (err) return err; } return NULL; } static void gotd_dispatch_notifier(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = gotd.notify_proc; ssize_t n; int shut = 0; struct imsg imsg; if (proc->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFIER_READY: { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd.repos, entry) { err = send_notification_targets(iev, repo->name, &repo->notification_targets); if (err) break; } break; } default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); /* * Do not exit all of gotd if the notification handler dies. * We can continue operating without notifications until an * operator intervenes. */ log_warnx("notify child process (pid %d) closed its imsg pipe " "unexpectedly", proc->pid); proc_done(proc); } } static const struct got_error * send_access_rule(struct gotd_imsgev *iev, struct gotd_access_rule *rule) { struct gotd_imsg_auth_access_rule irule; struct ibuf *wbuf = NULL; memset(&irule, 0, sizeof(irule)); switch (rule->access) { case GOTD_ACCESS_DENIED: case GOTD_ACCESS_PERMITTED: irule.access = rule->access; break; default: return got_error_fmt(GOT_ERR_NOT_IMPL, "unknown access %d", rule->access); } irule.authorization = rule->authorization; irule.identifier_len = strlen(rule->identifier); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_AUTH_ACCESS_RULE, 0, 0, sizeof(irule) + irule.identifier_len); if (wbuf == NULL) return got_error_from_errno("imsg_create AUTH_ACCESS_RULE"); if (imsg_add(wbuf, &irule, sizeof(irule)) == -1) return got_error_from_errno("imsg_add AUTH_ACCESS_FULE"); if (imsg_add(wbuf, rule->identifier, irule.identifier_len) == -1) return got_error_from_errno("imsg_add AUTH_ACCESS_FULE"); imsg_close(&iev->ibuf, wbuf); return gotd_imsg_flush(&iev->ibuf); } static const struct got_error * send_access_rules(struct gotd_imsgev *iev, char *repo_name) { const struct got_error *err = NULL; struct gotd_repo *repo; struct gotd_access_rule *rule; repo = gotd_find_repo_by_name(repo_name, &gotd.repos); if (repo == NULL) { return got_error_fmt(GOT_ERR_NOT_GIT_REPO, "repository %s not found in config", repo_name); } STAILQ_FOREACH(rule, &repo->rules, entry) { err = send_access_rule(iev, rule); if (err) return err; } return NULL; } static const struct got_error * send_authreq(struct gotd_imsgev *iev, struct gotd_client *client) { struct gotd_imsg_auth iauth; int fd; fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); memset(&iauth, 0, sizeof(iauth)); iauth.euid = client->euid; iauth.egid = client->egid; iauth.required_auth = client->required_auth; iauth.client_id = client->id; if (strlcpy(iauth.repo_name, client->auth->repo_name, sizeof(iauth.repo_name)) >= sizeof(iauth.repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } if (gotd_imsg_compose_event(iev, GOTD_IMSG_AUTHENTICATE, GOTD_PROC_GOTD, fd, &iauth, sizeof(iauth)) == -1) { log_warn("imsg compose AUTHENTICATE"); close(fd); /* Let the auth_timeout handler tidy up. */ } return NULL; } static void gotd_dispatch_auth_child(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client; struct gotd_repo *repo = NULL; ssize_t n; int shut = 0; struct imsg imsg; uint32_t client_id = 0; int do_disconnect = 0; size_t datalen; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (client->auth == NULL) fatalx("cannot find auth child process for fd %d", fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); goto done; } if (client->auth->iev.ibuf.fd != fd) fatalx("%s: unexpected fd %d", __func__, fd); if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ return; evtimer_del(&client->tmo); datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_AUTH_READY: if (client->state != GOTD_CLIENT_STATE_NEW) { do_disconnect = 1; err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_access_rules(iev, client->auth->repo_name); if (err) break; err = send_authreq(iev, client); break; case GOTD_IMSG_ACCESS_GRANTED: if (client->state != GOTD_CLIENT_STATE_NEW) { do_disconnect = 1; err = got_error(GOT_ERR_PRIVSEP_MSG); } break; default: do_disconnect = 1; log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, client->auth, &imsg)) { do_disconnect = 1; log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, client->auth->pid); } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); imsg_free(&imsg); return; } else if (err) log_warn("uid %d: %s", client->euid, err->msg); if (imsg.hdr.type != GOTD_IMSG_ACCESS_GRANTED) { imsg_free(&imsg); return; } client->state = GOTD_CLIENT_STATE_ACCESS_GRANTED; if (datalen > 0) client->username = strndup(imsg.data, datalen); imsg_free(&imsg); if (client->username == NULL && asprintf(&client->username, "uid %d", client->euid) == -1) { err = got_error_from_errno("asprintf"); goto done; } repo = gotd_find_repo_by_name(client->auth->repo_name, &gotd.repos); if (repo == NULL) { err = got_error(GOT_ERR_NOT_GIT_REPO); goto done; } kill_auth_proc(client); log_info("authenticated %s for repository %s", client->username, repo->name); err = start_session_child(client, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); if (err) goto done; done: if (err) log_warnx("uid %d: %s", client->euid, err->msg); /* We might have killed the auth process by now. */ if (client->auth != NULL) { if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); } } } static const struct got_error * connect_session(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsg_connect iconnect; int s; struct ibuf *wbuf; memset(&iconnect, 0, sizeof(iconnect)); s = dup(client->fd); if (s == -1) return got_error_from_errno("dup"); iconnect.client_id = client->id; iconnect.euid = client->euid; iconnect.egid = client->egid; iconnect.username_len = strlen(client->username); wbuf = imsg_create(&client->session->iev.ibuf, GOTD_IMSG_CONNECT, GOTD_PROC_GOTD, gotd.pid, sizeof(iconnect) + iconnect.username_len); if (wbuf == NULL) { err = got_error_from_errno("imsg compose CONNECT"); close(s); return err; } if (imsg_add(wbuf, &iconnect, sizeof(iconnect)) == -1) { close(s); return got_error_from_errno("imsg_add CONNECT"); } if (imsg_add(wbuf, client->username, iconnect.username_len) == -1) { close(s); return got_error_from_errno("imsg_add CONNECT"); } ibuf_fd_set(wbuf, s); imsg_close(&client->session->iev.ibuf, wbuf); gotd_imsg_event_add(&client->session->iev); /* * We are no longer interested in messages from this client. * Further client requests will be handled by the session process. */ imsgbuf_clear(&client->iev.ibuf); event_del(&client->iev.ev); client->fd = -1; /* will be closed via copy in client->iev.ibuf.fd */ return NULL; } static const struct got_error * send_gotsys_check_req(struct gotd_imsgev *iev, struct gotd_client *client) { const struct got_error *err = NULL; if (gotd_imsg_compose_event(iev, GOTD_IMSG_GOTSYS_CHECK, GOTD_PROC_GOTD, client->gotsys_conf_fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose GOTSYS_CHECK"); close(client->gotsys_conf_fd); client->gotsys_conf_fd = -1; } return err; } static void dispatch_gotsys_check(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client = NULL; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (client->gotsys == NULL) fatalx("cannot find gotsys child process for fd %d", fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { log_warn("%s", err->msg); goto done; } } for (;;) { const struct got_error *err = NULL; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); log_warnx("user %s: %s: %s", gotd_proc_names[client->gotsys->type], client->username, err->msg); if (client->session != NULL && gotd_imsg_send_error_event(&client->session->iev, GOTD_PROC_GOTD, client->id, err) == -1) log_warn("imsg send error"); else client->gotsys_error_sent = 1; break; case GOTD_IMSG_GOTSYS_READY: if (client->gotsys_conf_fd == -1) { err = got_error(GOT_ERR_PRIVSEP_MSG); do_disconnect = 1; break; } err = send_gotsys_check_req(iev, client); break; case GOTD_IMSG_GOTSYS_CFG_OK: if (client->session != NULL && gotd_imsg_compose_event(&client->session->iev, GOTD_IMSG_PACKFILE_VERIFIED, GOTD_PROC_GOTD, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose " "PACKFILE_VERIFIED"); do_disconnect = 1; } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (err) { log_warnx("user %s: %s %s", gotd_proc_names[client->gotsys->type], client->username, err->msg); } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); } } static const struct got_error * send_gotsys_apply_req(struct gotd_imsgev *iev) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_GOTSYS_APPLY, GOTD_PROC_GOTD, -1, NULL, 0) == -1) return got_error_from_errno("imsg compose GOTSYS_APPLY"); return NULL; } static void client_session_notify(struct gotd_client *client) { const struct got_error *err; if (client->session == NULL) return; /* * session_write may now proceed to send notifications * and disconnect the client. */ if (gotd_imsg_compose_event(&client->session->iev, GOTD_IMSG_NOTIFY, GOTD_PROC_GOTD, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose NOTIFY"); if (err) log_warnx("user %s: %s", client->username, err->msg); } } static void dispatch_gotsys_apply(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_client *client = NULL; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (client->gotsys == NULL) fatalx("cannot find gotsys child process for fd %d", fd); if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { log_warn("%s", err->msg); goto done; } } for (;;) { const struct got_error *err = NULL; int do_notify = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); log_warnx("user %s: %s: %s", gotd_proc_names[client->gotsys->type], client->username, err->msg); do_notify = 1; break; case GOTD_IMSG_GOTSYS_READY: err = send_gotsys_apply_req(iev); break; case GOTD_IMSG_SYSCONF_STARTED: do_notify = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (err) { log_warnx("user %s: %s %s", gotd_proc_names[client->gotsys->type], client->username, err->msg); } if (do_notify) client_session_notify(client); imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); } } static const struct got_error * run_gotsys(struct gotd_client *client, struct gotd_repo *repo, void (*handler)(int, short, void *), enum gotd_procid proc_id) { const struct got_error *err = NULL; struct gotd_child_proc *proc; pid_t pid; const char *argv[4]; int argc = 0; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) { err = got_error_from_errno("calloc"); return err; } switch (proc_id) { case GOTD_PROC_GOTSYS_CHECK: case GOTD_PROC_GOTSYS_APPLY: proc->type = proc_id; break; default: free(proc); return got_error(GOT_ERR_NOT_IMPL); } if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) { free(proc); return got_error_from_errno("socketpair"); } if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) { err = got_error_from_errno("imsgbuf_init"); close(proc->pipe[0]); close(proc->pipe[1]); free(proc); return err; } if (proc->type == GOTD_PROC_GOTSYS_CHECK) imsgbuf_allow_fdpass(&proc->iev.ibuf); proc->iev.handler = handler; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->pipe[0], EV_READ, handler, &proc->iev); event_add(&proc->iev.ev, NULL); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); switch (pid = fork()) { case -1: fatal("cannot fork"); case 0: break; default: proc->pid = pid; close(proc->pipe[1]); proc->pipe[1] = -1; client->gotsys = proc; log_debug("running %s (PID %d)", gotd_proc_names[proc->type], pid); return NULL; } if (proc->pipe[1] != GOTD_FILENO_MSG_PIPE) { if (dup2(proc->pipe[1], GOTD_FILENO_MSG_PIPE) == -1) fatal("cannot setup imsg fd"); } else if (fcntl(proc->pipe[1], F_SETFD, 0) == -1) fatal("cannot setup imsg fd"); if (proc->type == GOTD_PROC_GOTSYS_CHECK) { argv[argc++] = GOTD_PATH_PROG_GOTSYS_CHECK; } else { argv[argc++] = GOTD_PATH_PROG_GOTSYS_APPLY; argv[argc++] = "-r"; argv[argc++] = repo->path; } argv[argc++] = NULL; execvp(argv[0], (char * const *)argv); fatal("execvp"); /* NOTREACHED */ return NULL; } static const struct got_error * run_gotsys_check(struct gotd_client *client, struct gotd_repo *repo, struct imsg *imsg) { const struct got_error *err; if (client->gotsys_conf_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->gotsys_conf_fd = imsg_get_fd(imsg); if (client->gotsys_conf_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (fcntl(client->gotsys_conf_fd, F_SETFD, FD_CLOEXEC) == -1) { err = got_error_from_errno("fcntl"); goto done; } err = run_gotsys(client, repo, dispatch_gotsys_check, GOTD_PROC_GOTSYS_CHECK); done: if (err) { close(client->gotsys_conf_fd); client->gotsys_conf_fd = -1; } return err; } static const struct got_error * run_gotsys_apply(struct gotd_client *client, struct gotd_repo *repo) { return run_gotsys(client, repo, dispatch_gotsys_apply, GOTD_PROC_GOTSYS_APPLY); } static const struct got_error * send_pathlist_elem(struct gotd_imsgev *iev, const char *refname, int imsg_type) { struct gotd_imsg_pathlist_elem ielem; struct ibuf *wbuf = NULL; memset(&ielem, 0, sizeof(ielem)); ielem.path_len = strlen(refname); wbuf = imsg_create(&iev->ibuf, imsg_type, GOTD_PROC_GOTD, gotd.pid, sizeof(ielem) + ielem.path_len); if (wbuf == NULL) return got_error_from_errno_fmt("imsg_create %d", imsg_type); if (imsg_add(wbuf, &ielem, sizeof(ielem)) == -1) return got_error_from_errno_fmt("imsg_add %d", imsg_type); if (imsg_add(wbuf, refname, ielem.path_len) == -1) return got_error_from_errno_fmt("imsg_add %d", imsg_type); imsg_close(&iev->ibuf, wbuf); return gotd_imsg_flush(&iev->ibuf); } static const struct got_error * send_request_timeout(struct gotd_imsgev *iev, struct timeval *timeout) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_REQUEST_TIMEOUT, GOTD_PROC_GOTD, -1, timeout, sizeof(*timeout)) == -1) { return got_error_from_errno("imsg compose REQUEST_TIMEOUT"); } return NULL; } static const struct got_error * send_notification_config(struct gotd_imsgev *iev, char *repo_name) { const struct got_error *err = NULL; struct gotd_repo *repo; struct got_pathlist_entry *pe; struct gotd_imsg_pathlist ilist; memset(&ilist, 0, sizeof(ilist)); repo = gotd_find_repo_by_name(repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); ilist.nelem = repo->num_notification_refs; if (ilist.nelem > 0) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFICATION_REFS, GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { return got_error_from_errno("imsg compose " "NOTIFICATION_REFS"); } RB_FOREACH(pe, got_pathlist_head, &repo->notification_refs) { err = send_pathlist_elem(iev, pe->path, GOTD_IMSG_NOTIFICATION_REFS_ELEM); if (err) return err; } } ilist.nelem = repo->num_notification_ref_namespaces; if (ilist.nelem > 0) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFICATION_REF_NAMESPACES, GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { return got_error_from_errno("imsg compose " "NOTIFICATION_REF_NAMESPACES"); } RB_FOREACH(pe, got_pathlist_head, &repo->notification_ref_namespaces) { err = send_pathlist_elem(iev, pe->path, GOTD_IMSG_NOTIFICATION_REF_NAMESPACES_ELEM); if (err) return err; } } return send_notification_targets(iev, repo->name, &repo->notification_targets); } static void gotd_dispatch_client_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = NULL; struct gotd_client *client = NULL; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } proc = client->session; if (proc == NULL) fatalx("cannot find session child process for fd %d", fd); for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_start_repo_child = 0; int do_gotsys_check = 0, refs_updated = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CLIENT_SESSION_READY: if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_request_timeout(iev, &gotd.request_timeout); if (err) break; if (client_is_writing(client)) { err = send_notification_config(iev, proc->repo_name); if (err) break; } do_start_repo_child = 1; break; case GOTD_IMSG_RUN_GOTSYS_CHECK: if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } do_gotsys_check = 1; break; case GOTD_IMSG_REFS_UPDATED: if (client->state != GOTD_CLIENT_STATE_ACCESS_GRANTED) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } refs_updated = 1; break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, proc, &imsg)) { log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, proc->pid); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_start_repo_child) { struct gotd_repo *repo; const char *name = client->session->repo_name; repo = gotd_find_repo_by_name(name, &gotd.repos); if (repo != NULL) { enum gotd_procid proc_type; if (client->required_auth & GOTD_AUTH_WRITE) proc_type = GOTD_PROC_REPO_WRITE; else proc_type = GOTD_PROC_REPO_READ; err = start_repo_child(client, proc_type, repo, gotd.argv0, gotd.confpath, gotd.daemonize, gotd.verbosity); } else err = got_error(GOT_ERR_NOT_GIT_REPO); if (err) { log_warnx("uid %d: %s", client->euid, err->msg); do_disconnect = 1; } } if (do_gotsys_check) { struct gotd_repo *repo; repo = gotd_find_repo_by_name("gotsys", &gotd.repos); if (repo == NULL) repo = gotd_find_repo_by_name("gotsys.git", &gotd.repos); if (repo) { err = run_gotsys_check(client, repo, &imsg); if (err) { log_warnx("user %s: %s", client->username, err->msg); do_disconnect = 1; } } } if (refs_updated) { const char *name = client->session->repo_name; struct gotd_repo *repo; client->state = GOTD_CLIENT_STATE_NOTIFY; if (strcmp(name, "gotsys") == 0 || strcmp(name, "gotsys.git") == 0) { repo = gotd_find_repo_by_name(name, &gotd.repos); if (repo != NULL) run_gotsys_apply(client, repo); } else client_session_notify(client); } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); imsg_free(&imsg); return; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); disconnect(client); } } static const struct got_error * connect_notifier_and_session(struct gotd_client *client) { const struct got_error *err = NULL; struct gotd_imsgev *session_iev = &client->session->iev; int pipe[2]; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; if (gotd.notify_proc == NULL) return NULL; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); /* Pass notifier pipe to session . */ if (gotd_imsg_compose_event(session_iev, GOTD_IMSG_CONNECT_NOTIFIER, GOTD_PROC_GOTD, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_NOTIFIER"); close(pipe[0]); close(pipe[1]); return err; } /* Pass session pipe to notifier. */ if (gotd_imsg_compose_event(&gotd.notify_proc->iev, GOTD_IMSG_CONNECT_SESSION, GOTD_PROC_GOTD, pipe[1], NULL, 0) == -1) { err = got_error_from_errno("imsg compose CONNECT_SESSION"); close(pipe[1]); return err; } return NULL; } static const struct got_error * send_protected_refs(struct gotd_imsgev *iev, const char *repo_name) { const struct got_error *err = NULL; struct got_pathlist_entry *pe; struct gotd_imsg_pathlist ilist; struct gotd_repo *repo; memset(&ilist, 0, sizeof(ilist)); repo = gotd_find_repo_by_name(repo_name, &gotd.repos); if (repo == NULL) return got_error(GOT_ERR_NOT_GIT_REPO); ilist.nelem = repo->nprotected_tag_namespaces; if (ilist.nelem > 0) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_PROTECTED_TAG_NAMESPACES, GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { return got_error_from_errno("imsg compose " "PROTECTED_TAG_NAMESPACES"); } RB_FOREACH(pe, got_pathlist_head, &repo->protected_tag_namespaces) { err = send_pathlist_elem(iev, pe->path, GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM); if (err) return err; } } ilist.nelem = repo->nprotected_branch_namespaces; if (ilist.nelem > 0) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES, GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { return got_error_from_errno("imsg compose " "PROTECTED_BRANCH_NAMESPACES"); } RB_FOREACH(pe, got_pathlist_head, &repo->protected_branch_namespaces) { err = send_pathlist_elem(iev, pe->path, GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM); if (err) return err; } } ilist.nelem = repo->nprotected_branches; if (ilist.nelem > 0) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_PROTECTED_BRANCHES, GOTD_PROC_GOTD, -1, &ilist, sizeof(ilist)) == -1) { return got_error_from_errno("imsg compose " "PROTECTED_BRANCH_NAMESPACES"); } RB_FOREACH(pe, got_pathlist_head, &repo->protected_branches) { err = send_pathlist_elem(iev, pe->path, GOTD_IMSG_PROTECTED_BRANCHES_ELEM); if (err) return err; } } return NULL; } static void gotd_dispatch_repo_child(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_child_proc *proc = NULL; struct gotd_client *client; ssize_t n; int shut = 0; struct imsg imsg; client = find_client_by_proc_fd(fd); if (client == NULL) { /* Can happen during process teardown. */ warnx("cannot find client for fd %d", fd); shut = 1; goto done; } if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } proc = client->repo; if (proc == NULL) fatalx("cannot find child process for fd %d", fd); for (;;) { uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_REPO_CHILD_READY: if (client_is_writing(client)) { err = send_protected_refs(iev, proc->repo_name); if (err) break; } err = connect_session(client); if (err) break; if (client_is_writing(client)) { err = connect_notifier_and_session(client); if (err) break; } err = connect_repo_child(client, proc); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (!verify_imsg_src(client, proc, &imsg)) { log_debug("dropping imsg type %d from PID %d", imsg.hdr.type, proc->pid); imsg_free(&imsg); continue; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); disconnect(client); } } static pid_t start_child(enum gotd_procid proc_id, const char *repo_path, char *argv0, const char *confpath, const char *secretspath, int fd, int daemonize, int verbosity) { const char *argv[13]; int argc = 0; pid_t pid; switch (pid = fork()) { case -1: fatal("cannot fork"); case 0: break; default: close(fd); return pid; } if (fd != GOTD_FILENO_MSG_PIPE) { if (dup2(fd, GOTD_FILENO_MSG_PIPE) == -1) fatal("cannot setup imsg fd"); } else if (fcntl(fd, F_SETFD, 0) == -1) fatal("cannot setup imsg fd"); argv[argc++] = argv0; switch (proc_id) { case GOTD_PROC_LISTEN: argv[argc++] = "-TL"; break; case GOTD_PROC_AUTH: argv[argc++] = "-TA"; break; case GOTD_PROC_SESSION_READ: argv[argc++] = "-Ts"; break; case GOTD_PROC_SESSION_WRITE: argv[argc++] = "-TS"; break; case GOTD_PROC_REPO_READ: argv[argc++] = "-TR"; break; case GOTD_PROC_REPO_WRITE: argv[argc++] = "-TW"; break; case GOTD_PROC_NOTIFY: argv[argc++] = "-TN"; break; case GOTD_PROC_RELOAD: argv[argc++] = "-TG"; break; default: fatalx("invalid process id %d", proc_id); } argv[argc++] = "-f"; argv[argc++] = confpath; if (secretspath) { argv[argc++] = "-s"; argv[argc++] = secretspath; } if (repo_path) { argv[argc++] = "-P"; argv[argc++] = repo_path; } if (!daemonize) argv[argc++] = "-d"; if (verbosity > 0) argv[argc++] = "-v"; if (verbosity > 1) argv[argc++] = "-v"; argv[argc++] = NULL; execvp(argv0, (char * const *)argv); fatal("execvp"); } static void start_listener(char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) fatal("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); /* proc->tmo is initialized in main() after event_init() */ proc->type = GOTD_PROC_LISTEN; if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, NULL, argv0, confpath, NULL, proc->pipe[1], daemonize, verbosity); if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&proc->iev.ibuf); proc->iev.handler = gotd_dispatch_listener; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; gotd.listen_proc = proc; } static void start_notifier(char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; proc = calloc(1, sizeof(*proc)); if (proc == NULL) fatal("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); /* proc->tmo is initialized in main() after event_init() */ proc->type = GOTD_PROC_NOTIFY; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, NULL, argv0, confpath, NULL, proc->pipe[1], daemonize, verbosity); if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&proc->iev.ibuf); proc->iev.handler = gotd_dispatch_notifier; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_notifier, &proc->iev); gotd_imsg_event_add(&proc->iev); gotd.notify_proc = proc; } static const struct got_error * start_session_child(struct gotd_client *client, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) return got_error_from_errno("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); if (client_is_reading(client)) proc->type = GOTD_PROC_SESSION_READ; else proc->type = GOTD_PROC_SESSION_WRITE; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting client uid %d session for repository %s", client->euid, repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, NULL, proc->pipe[1], daemonize, verbosity); if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&proc->iev.ibuf); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_client_session; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_client_session, &proc->iev); gotd_imsg_event_add(&proc->iev); client->session = proc; return NULL; } static const struct got_error * start_repo_child(struct gotd_client *client, enum gotd_procid proc_type, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM|SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (proc_type != GOTD_PROC_REPO_READ && proc_type != GOTD_PROC_REPO_WRITE) return got_error_msg(GOT_ERR_NOT_IMPL, "bad process type"); proc = calloc(1, sizeof(*proc)); if (proc == NULL) return got_error_from_errno("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); proc->type = proc_type; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting %s for repository %s", proc->type == GOTD_PROC_REPO_READ ? "reader" : "writer", repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (realpath(repo->path, proc->repo_path) == NULL) fatal("%s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, NULL, proc->pipe[1], daemonize, verbosity); if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&proc->iev.ibuf); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_repo_child; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_repo_child, &proc->iev); gotd_imsg_event_add(&proc->iev); client->repo = proc; return NULL; } static const struct got_error * start_auth_child(struct gotd_client *client, int required_auth, struct gotd_repo *repo, char *argv0, const char *confpath, int daemonize, int verbosity) { struct gotd_child_proc *proc; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif proc = calloc(1, sizeof(*proc)); if (proc == NULL) return got_error_from_errno("calloc"); TAILQ_INSERT_HEAD(&procs, proc, entry); evtimer_set(&proc->tmo, kill_proc_timeout, proc); proc->type = GOTD_PROC_AUTH; if (strlcpy(proc->repo_name, repo->name, sizeof(proc->repo_name)) >= sizeof(proc->repo_name)) fatalx("repository name too long: %s", repo->name); log_debug("starting auth for uid %d repository %s", client->euid, repo->name); if (strlcpy(proc->repo_path, repo->path, sizeof(proc->repo_path)) >= sizeof(proc->repo_path)) fatalx("repository path too long: %s", repo->path); if (realpath(repo->path, proc->repo_path) == NULL) fatal("%s", repo->path); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, proc->pipe) == -1) fatal("socketpair"); proc->pid = start_child(proc->type, proc->repo_path, argv0, confpath, NULL, proc->pipe[1], daemonize, verbosity); if (imsgbuf_init(&proc->iev.ibuf, proc->pipe[0]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&proc->iev.ibuf); log_debug("proc %s %s is on fd %d", gotd_proc_names[proc->type], proc->repo_path, proc->pipe[0]); proc->iev.handler = gotd_dispatch_auth_child; proc->iev.events = EV_READ; proc->iev.handler_arg = NULL; event_set(&proc->iev.ev, proc->iev.ibuf.fd, EV_READ, gotd_dispatch_auth_child, &proc->iev); gotd_imsg_event_add(&proc->iev); client->auth = proc; client->required_auth = required_auth; return NULL; } static void apply_unveil_repo_readonly(const char *repo_path, int need_tmpdir) { if (need_tmpdir) { if (unveil(GOT_TMPDIR_STR, "rwc") == -1) fatal("unveil %s", GOT_TMPDIR_STR); } if (unveil(repo_path, "r") == -1) fatal("unveil %s", repo_path); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void apply_unveil_repo_readwrite(const char *repo_path) { if (unveil(repo_path, "rwc") == -1) fatal("unveil %s", repo_path); if (unveil(GOT_TMPDIR_STR, "rwc") == -1) fatal("unveil %s", GOT_TMPDIR_STR); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void apply_unveil_none(void) { if (unveil("/", "") == -1) fatal("unveil"); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void unveil_gotsys_and_self_exec(void) { if (unveil(GOTD_PATH_PROG_GOTSYS_CHECK, "x") == -1) fatal("unveil %s", GOTD_PATH_PROG_GOTSYS_CHECK); if (unveil(GOTD_PATH_PROG_GOTSYS_APPLY, "x") == -1) fatal("unveil %s", GOTD_PATH_PROG_GOTSYS_APPLY); if (unveil(gotd.argv0, "x") == -1) fatal("unveil %s", gotd.argv0); if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void set_max_datasize(void) { struct rlimit rl; if (getrlimit(RLIMIT_DATA, &rl) != 0) return; rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_DATA, &rl); } static void unveil_notification_helpers(void) { const char *helpers[] = { GOTD_PATH_PROG_NOTIFY_EMAIL, GOTD_PATH_PROG_NOTIFY_HTTP, }; size_t i; for (i = 0; i < nitems(helpers); i++) { if (unveil(helpers[i], "x") == 0) continue; fatal("unveil %s", helpers[i]); } if (unveil(NULL, NULL) == -1) fatal("unveil"); } static void check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) fatal("cannot stat %s", fname); if (st.st_uid != 0) fatalx("secrets file %s must be owned by root", fname); if (st.st_gid != 0) fatalx("secrets file %s must be owned by group wheel/root", fname); if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) fatalx("secrets file %s must not be group writable or world " "readable/writable", fname); } int main(int argc, char **argv) { const struct got_error *error = NULL; struct gotd_secrets *secrets = NULL; int ch, daemonize = 1, verbosity = 0, noaction = 0; const char *confpath = GOTD_CONF_PATH; char *secretspath = NULL; char *argv0 = argv[0]; char title[2048]; struct passwd *pw = NULL; uid_t uid; char *repo_path = NULL; enum gotd_procid proc_id = GOTD_PROC_GOTD; struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld; int *pack_fds = NULL, *temp_fds = NULL; struct gotd_repo *repo = NULL; char hostname[_POSIX_HOST_NAME_MAX + 1]; FILE *fp; FILE *diff_f1 = NULL, *diff_f2 = NULL, *tmp_f1 = NULL, *tmp_f2 = NULL; int diff_fd1 = -1, diff_fd2 = -1, tmp_fd = -1; const char *errstr; TAILQ_INIT(&procs); log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ while ((ch = getopt(argc, argv, "df:nP:s:T:v")) != -1) { switch (ch) { case 'd': daemonize = 0; break; case 'f': confpath = optarg; break; case 'n': noaction = 1; break; case 'P': repo_path = realpath(optarg, NULL); if (repo_path == NULL) fatal("realpath '%s'", optarg); break; case 's': secretspath = realpath(optarg, NULL); if (secretspath == NULL) fatal("realpath '%s'", optarg); break; case 'T': switch (*optarg) { case 'A': proc_id = GOTD_PROC_AUTH; break; case 'G': proc_id = GOTD_PROC_RELOAD; break; case 'L': proc_id = GOTD_PROC_LISTEN; break; case 'N': proc_id = GOTD_PROC_NOTIFY; break; case 'R': proc_id = GOTD_PROC_REPO_READ; break; case 's': proc_id = GOTD_PROC_SESSION_READ; break; case 'S': proc_id = GOTD_PROC_SESSION_WRITE; break; case 'W': proc_id = GOTD_PROC_REPO_WRITE; break; default: errx(1, "unknown proc type %s", optarg); } break; case 'v': if (verbosity < 3) verbosity++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0) usage(); if (geteuid() && proc_id == GOTD_PROC_GOTD) fatalx("need root privileges"); if (geteuid() == 0 && proc_id != GOTD_PROC_GOTD) fatalx("must not run as root"); if (proc_id == GOTD_PROC_GOTD) { const char *p = secretspath ? secretspath : GOTD_SECRETS_PATH; int conf_fd = -1; fp = fopen(p, "r"); if (fp == NULL && (secretspath != NULL || errno != ENOENT)) fatal("can't open secrets file %s", p); if (fp != NULL) { check_file_secrecy(fileno(fp), p); error = gotd_secrets_parse(p, fp, &secrets); fclose(fp); if (error) fatalx("failed to parse secrets file %s: %s", p, error->msg); } conf_fd = open(confpath, O_RDONLY | O_NOFOLLOW); if (conf_fd == -1) fatal("open %s", confpath); if (gotd_parse_config(confpath, conf_fd, proc_id, secrets, &gotd) != 0) return 1; close(conf_fd); conf_fd = -1; pw = getpwnam(gotd.user_name); if (pw == NULL) { uid = strtonum(gotd.user_name, 0, UID_MAX - 1, &errstr); if (errstr == NULL) pw = getpwuid(uid); } if (pw == NULL) fatalx("user %s not found", gotd.user_name); if (pw->pw_uid == 0) fatalx("cannot run %s as the superuser", getprogname()); /* * SHA2 repositories cannot be used with gotd until Git protov2 * support is added. Reject them at startup for now. */ TAILQ_FOREACH(repo, &gotd.repos, entry) { struct got_repository *r; error = got_repo_open(&r, repo->path, NULL, NULL); if (error) { if (error->code == GOT_ERR_ERRNO && errno == ENOENT) continue; fatalx("%s: %s", repo->path, error->msg); } if (got_repo_get_object_format(r) != GOT_HASH_SHA1) { error = got_error_msg(GOT_ERR_NOT_IMPL, "sha256 object IDs unsupported in network " "protocol"); fatalx("%s: %s", repo->path, error->msg); } got_repo_close(r); } if (noaction) { fprintf(stderr, "configuration OK\n"); return 0; } gotd_socket = unix_socket_listen(gotd.unix_socket_path, pw->pw_uid, pw->pw_gid); if (gotd_socket == -1) { fatal("cannot listen on unix socket %s", gotd.unix_socket_path); } if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); if (asprintf(&gotd.default_sender, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); } else if (proc_id == GOTD_PROC_RELOAD) { struct imsgbuf ibuf; struct imsg imsg; if (imsgbuf_init(&ibuf, GOTD_FILENO_MSG_PIPE) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); if (imsg_compose(&ibuf, GOTD_IMSG_RELOAD_READY, GOTD_PROC_RELOAD, getpid(), -1, NULL, 0) == -1) fatal("imsg compose RELOAD_READY"); error = gotd_imsg_flush(&ibuf); if (error) { gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatal("imsg flush: %s", error->msg); } while (error == NULL && (gotd_socket == -1 || gotd_reload_conf_fd == -1)) { error = gotd_imsg_poll_recv(&imsg, &ibuf, 0); if (error) break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: error = gotd_imsg_recv_error(NULL, &imsg); break; case GOTD_IMSG_LISTEN_SOCKET: if (gotd_socket != -1) { error = got_error(GOT_ERR_PRIVSEP_MSG); break; } gotd_socket = imsg_get_fd(&imsg); if (gotd_socket == -1) { error = got_error( GOT_ERR_PRIVSEP_NO_FD); break; } if (fcntl(gotd_socket, F_SETFD, FD_CLOEXEC) == -1) error = got_error_from_errno("fcntl"); break; case GOTD_IMSG_RELOAD_SECRETS: if (have_reload_secrets) { error = got_error(GOT_ERR_PRIVSEP_MSG); break; } error = recv_reload_secrets(&imsg); if (error) break; have_reload_secrets = 1; break; case GOTD_IMSG_GOTD_CONF: if (!have_reload_secrets || gotd_reload_conf_fd != -1) { error = got_error(GOT_ERR_PRIVSEP_MSG); break; } gotd_reload_conf_fd = imsg_get_fd(&imsg); if (gotd_reload_conf_fd != -1) break; if (fcntl(gotd_reload_conf_fd, F_SETFD, FD_CLOEXEC) == -1) error = got_error_from_errno("fcntl"); error = got_error(GOT_ERR_PRIVSEP_NO_FD); break; } } if (error) { gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatal("reloading: %s", error->msg); } if (gotd_reload_secrets_fd != -1) { char *p = gotd_reload_secrets_path; check_file_secrecy(gotd_reload_secrets_fd, p); fp = fdopen(gotd_reload_secrets_fd, "r"); if (fp == NULL) { error = got_error_from_errno2("fdopen", gotd_reload_secrets_path); gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatal("reloading: %s", error->msg); } error = gotd_secrets_parse(p, fp, &secrets); fclose(fp); if (error) { gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatalx("failed to parse secrets file %s: %s", p, error->msg); } } if (gotd_parse_config(confpath, gotd_reload_conf_fd, GOTD_PROC_GOTD, secrets, &gotd) != 0) return 1; pw = getpwnam(gotd.user_name); if (pw == NULL) { uid = strtonum(gotd.user_name, 0, UID_MAX - 1, &errstr); if (errstr == NULL) pw = getpwuid(uid); } if (pw == NULL) { error = got_error_fmt(GOT_ERR_UID, "user %s not found", gotd.user_name); gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatalx("%s", error->msg); } if (pw->pw_uid == 0) { error = got_error_fmt(GOT_ERR_UID, "cannot run %s as the superuser", getprogname()); gotd_imsg_send_error(&ibuf, proc_id, 0, error); fatalx("%s", error->msg); } if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); if (asprintf(&gotd.default_sender, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); imsgbuf_clear(&ibuf); close(GOTD_FILENO_MSG_PIPE); reload_reset(); } gotd.argv0 = argv0; gotd.daemonize = daemonize; gotd.verbosity = verbosity; gotd.confpath = confpath; /* Require an absolute path in argv[0] for reliable re-exec. */ if (!got_path_is_absolute(argv0)) fatalx("bad path \"%s\": must be an absolute path", argv0); log_init(daemonize ? 0 : 1, LOG_DAEMON); log_setverbose(verbosity); if (proc_id == GOTD_PROC_GOTD) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); clients_init(); if (daemonize && daemon(1, 0) == -1) fatal("daemon"); gotd.pid = getpid(); } else if (proc_id == GOTD_PROC_RELOAD) { snprintf(title, sizeof(title), "%s", gotd_proc_names[GOTD_PROC_GOTD]); clients_init(); gotd.pid = getpid(); } else if (proc_id == GOTD_PROC_LISTEN) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); } else if (proc_id == GOTD_PROC_AUTH) { snprintf(title, sizeof(title), "%s %s", gotd_proc_names[proc_id], repo_path); } else if (proc_id == GOTD_PROC_REPO_READ || proc_id == GOTD_PROC_REPO_WRITE || proc_id == GOTD_PROC_SESSION_READ || proc_id == GOTD_PROC_SESSION_WRITE) { error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) fatalx("cannot open pack tempfiles: %s", error->msg); error = got_repo_temp_fds_open(&temp_fds); if (error != NULL) fatalx("cannot open pack tempfiles: %s", error->msg); if (repo_path == NULL) fatalx("repository path not specified"); snprintf(title, sizeof(title), "%s %s", gotd_proc_names[proc_id], repo_path); } else if (proc_id == GOTD_PROC_NOTIFY) { snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]); } else fatal("invalid process id %d", proc_id); setproctitle("%s", title); log_procinit(title); event_init(); switch (proc_id) { case GOTD_PROC_GOTD: /* Drop root privileges. */ if (setgid(pw->pw_gid) == -1) fatal("setgid %d failed", pw->pw_gid); if (setuid(pw->pw_uid) == -1) fatal("setuid %d failed", pw->pw_uid); /* FALLTHROUGH */ case GOTD_PROC_RELOAD: proc_id = GOTD_PROC_GOTD; if (verbosity) { log_info("socket: %s", gotd.unix_socket_path); log_info("user: %s", pw->pw_name); } start_listener(argv0, confpath, daemonize, verbosity); start_notifier(argv0, confpath, daemonize, verbosity); #ifndef PROFILE /* "exec" promise will be limited to argv[0] via unveil(2). */ if (pledge("stdio proc exec sendfd recvfd unveil", NULL) == -1) err(1, "pledge"); #endif break; case GOTD_PROC_LISTEN: #ifndef PROFILE /* * The "recvfd" promise is only needed during setup and * will be removed in a later pledge(2) call. */ if (pledge("stdio recvfd sendfd unix unveil", NULL) == -1) err(1, "pledge"); #endif /* * Ensure that AF_UNIX bind(2) cannot be used with any other * sockets by revoking all filesystem access via unveil(2). */ apply_unveil_none(); listen_main(title); /* NOTREACHED */ break; case GOTD_PROC_AUTH: #ifndef PROFILE if (pledge("stdio getpw recvfd unix unveil", NULL) == -1) err(1, "pledge"); #endif /* * We need the "unix" pledge promise for getpeername(2) only. * Ensure that AF_UNIX bind(2) cannot be used by revoking all * filesystem access via unveil(2). Access to password database * files will still work since "getpw" bypasses unveil(2). */ apply_unveil_none(); auth_main(title); /* NOTREACHED */ break; case GOTD_PROC_SESSION_READ: #ifndef PROFILE /* * The "recvfd" promise is only needed during setup and * will be removed in a later pledge(2) call. */ if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock " "unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 1); session_read_main(title, repo_path, pack_fds, temp_fds); /* NOTREACHED */ break; case GOTD_PROC_SESSION_WRITE: tmp_fd = got_opentempfd(); if (tmp_fd == -1) fatal("got_opentempfd"); #ifndef PROFILE /* * The "recvfd" promise is only needed during setup and * will be removed in a later pledge(2) call. */ if (pledge("stdio rpath wpath cpath recvfd sendfd fattr flock " "unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readwrite(repo_path); session_write_main(title, repo_path, pack_fds, temp_fds, tmp_fd); /* NOTREACHED */ break; case GOTD_PROC_REPO_READ: set_max_datasize(); #ifndef PROFILE if (pledge("stdio rpath recvfd unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); if (enter_chroot(repo_path)) { log_info("change repo path %s", repo_path); free(repo_path); repo_path = strdup("/"); if (repo_path == NULL) fatal("strdup"); log_info("repo path is now %s", repo_path); } drop_privs(pw); repo_read_main(title, repo_path, pack_fds, temp_fds); /* NOTREACHED */ exit(0); case GOTD_PROC_REPO_WRITE: set_max_datasize(); diff_f1 = got_opentemp(); if (diff_f1 == NULL) fatal("got_opentemp"); diff_f2 = got_opentemp(); if (diff_f2 == NULL) fatal("got_opentemp"); diff_fd1 = got_opentempfd(); if (diff_fd1 == -1) fatal("got_opentempfd"); diff_fd2 = got_opentempfd(); if (diff_fd2 == -1) fatal("got_opentempfd"); tmp_f1 = got_opentemp(); if (tmp_f1 == NULL) fatal("got_opentemp"); tmp_f2 = got_opentemp(); if (tmp_f2 == NULL) fatal("got_opentemp"); #ifndef PROFILE if (pledge("stdio rpath recvfd unveil", NULL) == -1) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); repo_write_main(title, repo_path, pack_fds, temp_fds, tmp_f1, tmp_f2, diff_f1, diff_f2, diff_fd1, diff_fd2); /* NOTREACHED */ exit(0); case GOTD_PROC_NOTIFY: #ifndef PROFILE if (pledge("stdio proc exec recvfd unveil", NULL) == -1) err(1, "pledge"); #endif /* * Limit "exec" promise to notification helpers via unveil(2). */ unveil_notification_helpers(); notify_main(title); /* NOTREACHED */ exit(0); default: fatal("invalid process id %d", proc_id); } if (proc_id != GOTD_PROC_GOTD) fatal("invalid process id %d", proc_id); evtimer_set(&gotd.listen_proc->tmo, kill_proc_timeout, gotd.listen_proc); if (gotd.notify_proc) { evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout, gotd.notify_proc); } unveil_gotsys_and_self_exec(); signal_set(&evsigint, SIGINT, gotd_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, gotd_sighdlr, NULL); signal_set(&evsighup, SIGHUP, gotd_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, gotd_sighdlr, NULL); signal_set(&evsigchld, SIGCHLD, gotd_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); signal_add(&evsigchld, NULL); gotd_imsg_event_add(&gotd.listen_proc->iev); if (gotd.notify_proc) { struct imsgbuf *imsgbuf = &gotd.notify_proc->iev.ibuf; struct gotd_secret *s; size_t i, n = 0; gotd_imsg_event_add(&gotd.notify_proc->iev); if (gotd.secrets) n = gotd.secrets->len; if (imsg_compose(imsgbuf, GOTD_IMSG_SECRETS, 0, 0, -1, &n, sizeof(n)) == -1) fatal("imsg_compose GOTD_IMSG_SECRETS"); error = gotd_imsg_flush(imsgbuf); if (error) fatalx("%s", error->msg); for (i = 0; i < n; ++i) { struct iovec iov[5]; s = &gotd.secrets->secrets[i]; iov[0].iov_base = &s->type; iov[0].iov_len = sizeof(s->type); iov[1].iov_base = s->label; iov[1].iov_len = strlen(s->label) + 1; iov[2].iov_base = s->user; iov[2].iov_len = s->user ? strlen(s->user) + 1 : 0 ; iov[3].iov_base = s->pass; iov[3].iov_len = s->pass ? strlen(s->pass) + 1 : 0 ; iov[4].iov_base = s->hmac; iov[4].iov_len = s->hmac ? strlen(s->hmac) + 1 : 0 ; if (imsg_composev(imsgbuf, GOTD_IMSG_SECRET, 0, 0, -1, iov, 5) == -1) fatal("imsg_composev GOTD_IMSG_SECRET"); error = gotd_imsg_flush(imsgbuf); if (error) fatalx("%s", error->msg); } gotd_secrets_free(gotd.secrets); gotd.secrets = NULL; } event_dispatch(); free(repo_path); free(secretspath); gotd_shutdown(); return 0; } got-portable-0.119/gotd/libexec/0000775000175000017500000000000015066537274012255 5got-portable-0.119/gotd/libexec/Makefile.am0000664000175000017500000000005315066536113014216 SUBDIRS = got-notify-email got-notify-http got-portable-0.119/gotd/libexec/got-notify-email/0000775000175000017500000000000015066537274015441 5got-portable-0.119/gotd/libexec/got-notify-email/got-notify-email.c0000664000175000017500000002540415066536113020705 /* * Copyright (c) 2024 Stefan Sperling * Copyright (c) 2008, 2012 Gilles Chehade * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "got_error.h" #include "got_lib_poll.h" #define SMTP_LINE_MAX 65535 static int smtp_timeout = 60; /* in seconds */ static char smtp_buf[SMTP_LINE_MAX]; static size_t smtp_buflen; __dead static void usage(void) { fprintf(stderr, "usage: %s [-f sender] [-r responder] " "[-s subject] [-h hostname] [-p port] recipient\n", getprogname()); exit(1); } static int dial(const char *host, const char *port) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int s, error, save_errno; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) fatalx("failed to resolve %s:%s: %s", host, port, gai_strerror(error)); s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { cause = "connect"; save_errno = errno; close(s); errno = save_errno; s = -1; continue; } break; } freeaddrinfo(res0); if (s == -1) fatal("%s %s:%s", cause, host, port); return s; } static char * set_default_fromaddr(void) { struct passwd *pw = NULL; char *s; char hostname[255]; pw = getpwuid(getuid()); if (pw == NULL) { fatalx("my UID %d was not found in password database", getuid()); } if (gethostname(hostname, sizeof(hostname)) == -1) fatal("gethostname"); if (asprintf(&s, "%s@%s", pw->pw_name, hostname) == -1) fatal("asprintf"); return s; } static int read_smtp_code(int s, const char *code) { const struct got_error *error; char *endl; size_t linelen; ssize_t r; for (;;) { endl = memmem(smtp_buf, smtp_buflen, "\r\n", 2); if (endl != NULL) break; if (smtp_buflen == sizeof(smtp_buf)) fatalx("line too long"); error = got_poll_fd(s, POLLIN, smtp_timeout); if (error) fatalx("poll: %s", error->msg); r = read(s, smtp_buf + smtp_buflen, sizeof(smtp_buf) - smtp_buflen); if (r == -1) fatal("read"); if (r == 0) fatalx("unexpected EOF"); smtp_buflen += r; } linelen = endl - smtp_buf; if (linelen < 3) fatalx("invalid SMTP response"); if (strncmp(code, smtp_buf, 3) != 0) { smtp_buf[3] = '\0'; log_warnx("unexpected SMTP message code: %s", smtp_buf); return -1; } /* * Normally we would get just one reply, but the regress doesn't * use a real SMTP server and queues all the replies upfront. */ linelen += 2; memmove(smtp_buf, smtp_buf + linelen, smtp_buflen - linelen); smtp_buflen -= linelen; return 0; } static int send_smtp_msg(int s, const char *fmt, ...) { const struct got_error *error; char buf[512]; int len; va_list ap; va_start(ap, fmt); len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (len < 0) { log_warn("vsnprintf"); return -1; } if (len >= sizeof(buf)) { log_warnx("%s: buffer too small for message '%s...'", __func__, buf); return -1; } error = got_poll_write_full(s, buf, len); if (error) { log_warnx("write: %s", error->msg); return -1; } return 0; } static const struct got_error * print_date(int s, char *date, int shortfmt) { const struct got_error *error; struct tm tm; char *t, datebuf[26]; const char *errstr; time_t ts; date[strcspn(date, " \n")] = '\0'; ts = strtonum(date, INT64_MIN, INT64_MAX, &errstr); if (errstr) return got_error_set_errno(EINVAL, errstr); if (gmtime_r(&ts, &tm) == NULL) return got_error_set_errno(EINVAL, "gmtime_r"); if (!shortfmt) { t = asctime_r(&tm, datebuf); if (t == NULL) return got_error_set_errno(EINVAL, "invalid timestamp"); t[strcspn(t, "\n")] = '\0'; error = got_poll_write_full(s, t, strlen(t)); if (error) return error; return got_poll_write_full(s, " UTC\n", 5); } if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) return got_error_set_errno(EINVAL, "invalid timestamp"); return got_poll_write_full(s, datebuf, strlen(datebuf)); } /* from usr.sbin/smtpd/util.c */ static int bsnprintf(char *str, size_t size, const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = vsnprintf(str, size, format, ap); va_end(ap); if (ret < 0 || (size_t)ret >= size) return 0; return 1; } /* based on usr.sbin/smtpd/to.c */ static const char * time_to_text(time_t when, char *buf, size_t buf_size) { struct tm *lt; const char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const char *month[] = {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; const char *tz; long offset; lt = gmtime(&when); if (lt == NULL || when == 0) fatalx("time_to_text: localtime"); offset = lt->tm_gmtoff; tz = lt->tm_zone; /* We do not use strftime because it is subject to locale substitution*/ if (!bsnprintf(buf, buf_size, "%s, %d %s %d %02d:%02d:%02d %c%02d%02d (%s)", day[lt->tm_wday], lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900, lt->tm_hour, lt->tm_min, lt->tm_sec, offset >= 0 ? '+' : '-', abs((int)offset / 3600), abs((int)offset % 3600) / 60, tz)) fatalx("time_to_text: bsnprintf"); return buf; } static void send_email(int s, const char *myfromaddr, const char *fromaddr, const char *recipient, const char *replytoaddr, const char *subject) { const struct got_error *error; char *line = NULL; size_t linesize = 0; ssize_t linelen; int firstline = 1, shortfmt = 0; char datebuf[40]; const char *datestr; datestr = time_to_text(time(NULL), datebuf, sizeof(datebuf)); if (read_smtp_code(s, "220")) fatalx("unexpected SMTP greeting received"); if (send_smtp_msg(s, "HELO localhost\r\n")) fatalx("could not send HELO"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "MAIL FROM:<%s>\r\n", myfromaddr)) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "RCPT TO:<%s>\r\n", recipient)) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "DATA\r\n")) fatalx("could not send MAIL FROM"); if (read_smtp_code(s, "354")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "From: %s\r\n", fromaddr)) fatalx("could not send From header"); if (send_smtp_msg(s, "To: %s\r\n", recipient)) fatalx("could not send To header"); if (replytoaddr) { if (send_smtp_msg(s, "Reply-To: %s\r\n", replytoaddr)) fatalx("could not send Reply-To header"); } if (send_smtp_msg(s, "Date: %s\r\n", datestr)) fatalx("could not send Date header"); if (send_smtp_msg(s, "Subject: %s\r\n", subject)) fatalx("could not send Subject header"); if (send_smtp_msg(s, "\r\n")) fatalx("could not send body delimiter"); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (firstline && isdigit((unsigned char)line[0])) shortfmt = 1; firstline = 0; if (line[0] == '.') { /* dot stuffing */ error = got_poll_write_full(s, ".", 1); if (error) fatalx("write: %s", error->msg); } if (shortfmt) { char *t; t = strchr(line, ' '); if (t != NULL) { *t++ = '\0'; error = print_date(s, line, shortfmt); if (error) fatalx("write: %s", error->msg); error = got_poll_write_full(s, t, strlen(t)); continue; } } if (!shortfmt && !strncmp(line, "date: ", 6)) { error = got_poll_write_full(s, line, 6); if (error) fatalx("write: %s", error->msg); error = print_date(s, line + 6, shortfmt); if (error) fatalx("write: %s", error->msg); continue; } error = got_poll_write_full(s, line, linelen); if (error) fatalx("write: %s", error->msg); } if (send_smtp_msg(s, "\r\n.\r\n")) fatalx("could not send data terminator"); if (read_smtp_code(s, "250")) fatalx("unexpected SMTP response received"); if (send_smtp_msg(s, "QUIT\r\n")) fatalx("could not send QUIT"); if (read_smtp_code(s, "221")) fatalx("unexpected SMTP response received"); close(s); free(line); } int main(int argc, char *argv[]) { char *default_fromaddr = NULL; const char *fromaddr = NULL, *recipient = NULL, *replytoaddr = NULL; const char *subject = "gotd notification"; const char *hostname = "127.0.0.1"; const char *port = "25"; const char *errstr; char *timeoutstr; int ch, s; log_init(0, LOG_DAEMON); while ((ch = getopt(argc, argv, "f:r:s:h:p:")) != -1) { switch (ch) { case 'h': hostname = optarg; break; case 'f': fromaddr = optarg; break; case 'p': port = optarg; break; case 'r': replytoaddr = optarg; break; case 's': subject = optarg; break; default: usage(); /* NOTREACHED */ break; } } argc -= optind; argv += optind; if (argc != 1) usage(); /* used by the regression test suite */ timeoutstr = getenv("GOT_NOTIFY_TIMEOUT"); if (timeoutstr) { smtp_timeout = strtonum(timeoutstr, 0, 600, &errstr); if (errstr != NULL) fatalx("timeout in seconds is %s: %s", errstr, timeoutstr); } #ifndef PROFILE if (pledge("stdio dns inet getpw", NULL) == -1) err(1, "pledge"); #endif default_fromaddr = set_default_fromaddr(); #ifndef PROFILE if (pledge("stdio dns inet", NULL) == -1) err(1, "pledge"); #endif recipient = argv[0]; if (fromaddr == NULL) fromaddr = default_fromaddr; s = dial(hostname, port); #ifndef PROFILE if (pledge("stdio", NULL) == -1) err(1, "pledge"); /* revoke fs access */ if (landlock_no_fs() == -1) err(1, "landlock_no_fs"); if (cap_enter() == -1) err(1, "cap_enter"); #endif send_email(s, default_fromaddr, fromaddr, recipient, replytoaddr, subject); free(default_fromaddr); return 0; } got-portable-0.119/gotd/libexec/got-notify-email/Makefile.am0000664000175000017500000000102415066536113017401 libexec_PROGRAMS = got-notify-email include $(top_builddir)/Makefile.common got_notify_email_SOURCES = got-notify-email.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/pollfd.c got_notify_email_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) got-portable-0.119/gotd/libexec/got-notify-email/Makefile.in0000664000175000017500000005376115066537207017436 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-notify-email$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotd/libexec/got-notify-email ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_notify_email_OBJECTS = got-notify-email.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) got_notify_email_OBJECTS = $(am_got_notify_email_OBJECTS) got_notify_email_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ ./$(DEPDIR)/got-notify-email.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_notify_email_SOURCES) DIST_SOURCES = $(got_notify_email_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ got_notify_email_SOURCES = got-notify-email.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/pollfd.c got_notify_email_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/got-notify-email/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/got-notify-email/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-notify-email$(EXEEXT): $(got_notify_email_OBJECTS) $(got_notify_email_DEPENDENCIES) $(EXTRA_got_notify_email_DEPENDENCIES) @rm -f got-notify-email$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_notify_email_OBJECTS) $(got_notify_email_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-notify-email.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-email.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-email.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotd/libexec/got-notify-http/0000775000175000017500000000000015066537274015331 5got-portable-0.119/gotd/libexec/got-notify-http/Makefile.am0000664000175000017500000000133515066536113017276 libexec_PROGRAMS = got-notify-http include $(top_builddir)/Makefile.common EXTRA_DIST = utf8d.h got_notify_http_SOURCES = got-notify-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pollfd.c got_notify_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat LDADD += $(zlib_LIBS) $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) \ $(libtls_LIBS) $(libcrypto_LIBS) if HOST_FREEBSD LDADD += -lmd endif if HOST_OPENBSD LDADD += -ltls endif AM_CPPFLAGS += $(zlib_CFLAGS) $(libbsd_CFLAGS) $(libmd_CFLAGS) \ $(libtls_CFLAGS) $(libcrypto_CFLAGS) got-portable-0.119/gotd/libexec/got-notify-http/utf8d.h0000664000175000017500000000513715066535721016455 /* * Copyright (c) 2008-2009 Bjoern Hoehrmann * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 static const uint8_t utf8d[] = { 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, // 00..1f 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, // 20..3f 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, // 40..5f 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, // 60..7f 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 }; static uint32_t inline decode(uint32_t* state, uint32_t* codep, uint32_t byte) { uint32_t type = utf8d[byte]; *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte); *state = utf8d[256 + *state*16 + type]; return *state; } got-portable-0.119/gotd/libexec/got-notify-http/got-notify-http.c0000664000175000017500000005711515066536113020471 /* * Copyright (c) 2024 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_version.h" #include "got_object.h" #include "got_lib_hash.h" #include "bufio.h" #include "log.h" #include "utf8d.h" #define USERAGENT "got-notify-http/" GOT_VERSION_STR static int http_timeout = 300; /* 5 minutes in seconds */ __dead static void usage(void) { fprintf(stderr, "usage: %s [-c] -r repo -h host -p port -u user path\n", getprogname()); exit(1); } static int dial(const char *host, const char *port) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int s, error, save_errno; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, port, &hints, &res0); if (error) errx(1, "failed to resolve %s:%s: %s", host, port, gai_strerror(error)); s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { cause = "connect"; save_errno = errno; close(s); errno = save_errno; s = -1; continue; } break; } freeaddrinfo(res0); if (s == -1) fatal("%s %s:%s", cause, host, port); return s; } static void escape(FILE *fp, const uint8_t *s) { uint32_t codepoint, state; const uint8_t *start = s; state = 0; for (; *s; ++s) { switch (decode(&state, &codepoint, *s)) { case UTF8_ACCEPT: switch (codepoint) { case '"': case '\\': fprintf(fp, "\\%c", *s); break; case '\b': fprintf(fp, "\\b"); break; case '\f': fprintf(fp, "\\f"); break; case '\n': fprintf(fp, "\\n"); break; case '\r': fprintf(fp, "\\r"); break; case '\t': fprintf(fp, "\\t"); break; default: /* other control characters */ if (codepoint < ' ' || codepoint == 0x7F) { fprintf(fp, "\\u%04x", codepoint); break; } fwrite(start, 1, s - start + 1, fp); break; } start = s + 1; break; case UTF8_REJECT: /* bad UTF-8 sequence; try to recover */ fputs("\\uFFFD", fp); state = UTF8_ACCEPT; start = s + 1; break; } } } static void json_field(FILE *fp, const char *key, const char *val, int comma) { fprintf(fp, "\"%s\":\"", key); escape(fp, val); fprintf(fp, "\"%s", comma ? "," : ""); } static void json_date(FILE *fp, const char *key, const char *date, int comma) { fprintf(fp, "\"%s\":%s%s", key, date, comma ? "," : ""); } static void json_author(FILE *fp, const char *type, char *address, int comma) { char *gt, *lt, *at, *email, *endname; fprintf(fp, "\"%s\":{", type); gt = strchr(address, '<'); if (gt != NULL) { /* long format, e.g. "Omar Polo " */ json_field(fp, "full", address, 1); endname = gt; while (endname > address && endname[-1] == ' ') endname--; *endname = '\0'; json_field(fp, "name", address, 1); email = gt + 1; lt = strchr(email, '>'); if (lt) *lt = '\0'; json_field(fp, "mail", email, 1); at = strchr(email, '@'); if (at) *at = '\0'; json_field(fp, "user", email, 0); } else { /* short format only shows the username */ json_field(fp, "user", address, 0); } fprintf(fp, "}%s", comma ? "," : ""); } static int jsonify_branch_rm(FILE *fp, char *line, const char *repo, const char *user) { char *ref, *id; line = strchr(line, ' '); if (line == NULL) errx(1, "invalid branch rm line"); line += strspn(line, " "); ref = line; line = strchr(line, ':'); if (line == NULL) errx(1, "invalid branch rm line"); *line++ = '\0'; id = line + strspn(line, " "); fputc('{', fp); json_field(fp, "type", "branch-deleted", 1); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "ref", ref, 1); json_field(fp, "id", id, 0); fputc('}', fp); return 0; } static int jsonify_commit_short(FILE *fp, char *line, const char *repo, const char *user) { char *t, *date, *id, *author, *message; t = line; date = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; id = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; author = t; if ((t = strchr(t, ' ')) == NULL) errx(1, "malformed line"); *t++ = '\0'; message = t; fprintf(fp, "{\"type\":\"commit\",\"short\":true,"); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "id", id, 1); json_author(fp, "committer", author, 1); json_date(fp, "date", date, 1); json_field(fp, "short_message", message, 0); fprintf(fp, "}"); return 0; } static int jsonify_commit(FILE *fp, const char *repo, const char *user, char **line, ssize_t *linesize) { const char *errstr; char *author = NULL; char *filename, *t; char *l; ssize_t linelen; int parent = 0; int msglen = 0, msgwrote = 0; int n, files = 0; int done = 0; enum { P_FROM, P_VIA, P_DATE, P_PARENT, P_MSGLEN, P_MSG, P_DST, P_SUM, } phase = P_FROM; l = *line; if (strncmp(l, "commit ", 7) != 0) errx(1, "%s: unexpected line: %s", __func__, l); l += 7; fprintf(fp, "{\"type\":\"commit\",\"short\":false,"); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "id", l, 1); while (!done) { if ((linelen = getline(line, linesize, stdin)) == -1) break; if ((*line)[linelen - 1] == '\n') (*line)[--linelen] = '\0'; l = *line; switch (phase) { case P_FROM: if (strncmp(l, "from: ", 6) != 0) errx(1, "unexpected from line"); l += 6; author = strdup(l); if (author == NULL) fatal("strdup"); json_author(fp, "author", l, 1); phase = P_VIA; break; case P_VIA: /* optional */ if (!strncmp(l, "via: ", 5)) { l += 5; json_author(fp, "committer", l, 1); phase = P_DATE; break; } if (author == NULL) /* impossible */ fatalx("from not specified"); json_author(fp, "committer", author, 1); free(author); author = NULL; phase = P_DATE; /* fallthrough */ case P_DATE: /* optional */ if (!strncmp(l, "date: ", 6)) { l += 6; json_date(fp, "date", l, 1); phase = P_PARENT; break; } phase = P_PARENT; /* fallthrough */ case P_PARENT: /* optional - more than one */ if (!strncmp(l, "parent ", 7)) { l += 7; l += strcspn(l, ":"); l += strspn(l, " "); if (parent == 0) { parent = 1; fprintf(fp, "\"parents\":["); } fputc('"', fp); escape(fp, l); fputc('"', fp); break; } if (parent != 0) { fprintf(fp, "],"); parent = 0; } phase = P_MSGLEN; /* fallthrough */ case P_MSGLEN: if (strncmp(l, "messagelen: ", 12) != 0) errx(1, "unexpected messagelen line"); l += 12; msglen = strtonum(l, 1, INT_MAX, &errstr); if (errstr) errx(1, "message len is %s: %s", errstr, l); msglen++; phase = P_MSG; break; case P_MSG: /* * The commit message is indented with one extra * space which is not accounted for in messagelen, * but we also strip the trailing \n so that * accounts for it. * * Since we read line-by-line and there is always * a \n added at the end of the message, * tolerate one byte less than advertised. */ if (*l != ' ') errx(1, "unexpected line in commit message"); l++; /* skip leading space */ linelen--; if (msgwrote == 0 && linelen != 0) { json_field(fp, "short_message", l, 1); fprintf(fp, "\"message\":\""); escape(fp, l); escape(fp, "\n"); msgwrote += linelen; } else if (msgwrote != 0) { escape(fp, l); escape(fp, "\n"); } msglen -= linelen + 1; if (msglen <= 1) { fprintf(fp, "\","); phase = P_DST; break; } break; case P_DST: if (files == 0 && !strcmp(l, " ")) break; if (files == 0) fputs("\"diffstat\":{\"files\":[", fp); if (*l == '\0') { fputs("],", fp); phase = P_SUM; break; } if (*l != ' ') errx(1, "bad diffstat line"); l++; if (files != 0) fputc(',', fp); fputc('{', fp); switch (*l) { case 'A': json_field(fp, "action", "added", 1); break; case 'D': json_field(fp, "action", "deleted", 1); break; case 'M': json_field(fp, "action", "modified", 1); break; case 'm': json_field(fp, "action", "mode changed", 1); break; default: json_field(fp, "action", "unknown", 1); break; } l++; while (*l == ' ') *l++ = '\0'; if (*l == '\0') errx(1, "invalid diffstat: no filename"); filename = l; l = strrchr(l, '|'); if (l == NULL) errx(1, "invalid diffstat: no separator"); t = l - 1; while (t > filename && *t == ' ') *t-- = '\0'; json_field(fp, "file", filename, 1); l++; while (*l == ' ') l++; t = strchr(l, '+'); if (t == NULL) errx(1, "invalid diffstat: no added counter"); *t++ = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "added counter is %s: %s", errstr, l); fprintf(fp, "\"added\":%d,", n); l = ++t; while (*l == ' ') l++; t = strchr(l, '-'); if (t == NULL) errx(1, "invalid diffstat: no del counter"); *t = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "del counter is %s: %s", errstr, l); fprintf(fp, "\"removed\":%d", n); fputc('}', fp); files++; break; case P_SUM: fputs("\"total\":{", fp); t = l; l = strchr(l, ' '); if (l == NULL) errx(1, "missing number of additions"); *l++ = '\0'; n = strtonum(t, 0, INT_MAX, &errstr); if (errstr) errx(1, "add counter is %s: %s", errstr, t); fprintf(fp, "\"added\":%d,", n); l = strchr(l, ','); if (l == NULL) errx(1, "missing number of deletions"); l++; while (*l == ' ') l++; t = strchr(l, ' '); if (t == NULL) errx(1, "malformed diffstat sum line"); *t = '\0'; n = strtonum(l, 0, INT_MAX, &errstr); if (errstr) errx(1, "del counter is %s: %s", errstr, l); fprintf(fp, "\"removed\":%d", n); fputs("}}", fp); done = 1; break; default: /* unreachable */ errx(1, "unexpected line: %s", *line); } } if (ferror(stdin)) fatalx("getline"); if (!done) fatalx("%s: unexpected EOF", __func__); fputc('}', fp); return 0; } static int jsonify_tag(FILE *fp, const char *repo, const char *user, char **line, ssize_t *linesize) { const char *errstr; char *l; ssize_t linelen; int msglen = 0, msgwrote = 0; int done = 0; enum { P_FROM, P_DATE, P_OBJECT, P_MSGLEN, P_MSG, } phase = P_FROM; l = *line; if (strncmp(l, "tag ", 4) != 0) errx(1, "%s: unexpected line: %s", __func__, l); l += 4; fputc('{', fp); json_field(fp, "type", "tag", 1); json_field(fp, "repo", repo, 1); json_field(fp, "authenticated_user", user, 1); json_field(fp, "tag", l, 1); while (!done) { if ((linelen = getline(line, linesize, stdin)) == -1) break; if ((*line)[linelen - 1] == '\n') (*line)[--linelen] = '\0'; l = *line; switch (phase) { case P_FROM: if (strncmp(l, "from: ", 6) != 0) errx(1, "unexpected from line"); l += 6; json_author(fp, "tagger", l, 1); phase = P_DATE; break; case P_DATE: /* optional */ if (!strncmp(l, "date: ", 6)) { l += 6; json_date(fp, "date", l, 1); phase = P_OBJECT; break; } phase = P_OBJECT; /* fallthrough */ case P_OBJECT: /* optional */ if (!strncmp(l, "object: ", 8)) { char *type, *id; l += 8; type = l; id = strchr(l, ' '); if (id == NULL) errx(1, "malformed tag object line"); *id++ = '\0'; fputs("\"object\":{", fp); json_field(fp, "type", type, 1); json_field(fp, "id", id, 0); fputs("},", fp); phase = P_MSGLEN; break; } phase = P_MSGLEN; /* fallthrough */ case P_MSGLEN: if (strncmp(l, "messagelen: ", 12) != 0) errx(1, "unexpected messagelen line"); l += 12; msglen = strtonum(l, 1, INT_MAX, &errstr); if (errstr) errx(1, "message len is %s: %s", errstr, l); msglen++; phase = P_MSG; break; case P_MSG: if (*l != ' ') errx(1, "unexpected line in tag message"); l++; /* skip leading space */ linelen--; if (msgwrote == 0 && linelen != 0) { fprintf(fp, "\"message\":\""); escape(fp, l); escape(fp, "\n"); msgwrote += linelen; } else if (msgwrote != 0) { escape(fp, l); escape(fp, "\n"); } msglen -= linelen + 1; if (msglen <= 0) { fprintf(fp, "\""); done = 1; break; } break; default: /* unreachable */ errx(1, "unexpected line: %s", *line); } } if (ferror(stdin)) fatal("getline"); if (!done) fatalx("%s: unexpected EOF", __func__); fputc('}', fp); return 0; } static int jsonify(FILE *fp, const char *repo, const char *user) { char *line = NULL; size_t linesize = 0; ssize_t linelen; int needcomma = 0; fprintf(fp, "{\"notifications\":["); while ((linelen = getline(&line, &linesize, stdin)) != -1) { if (line[linelen - 1] == '\n') line[--linelen] = '\0'; if (*line == '\0') continue; if (needcomma) fputc(',', fp); needcomma = 1; if (strncmp(line, "Removed refs/heads/", 19) == 0) { if (jsonify_branch_rm(fp, line, repo, user) == -1) fatal("jsonify_branch_rm"); continue; } if (strncmp(line, "commit ", 7) == 0) { if (jsonify_commit(fp, repo, user, &line, &linesize) == -1) fatal("jsonify_commit"); continue; } if (*line >= '0' && *line <= '9') { if (jsonify_commit_short(fp, line, repo, user) == -1) fatal("jsonify_commit_short"); continue; } if (strncmp(line, "tag ", 4) == 0) { if (jsonify_tag(fp, repo, user, &line, &linesize) == -1) fatal("jsonify_tag"); continue; } errx(1, "unexpected line: %s", line); } if (ferror(stdin)) fatal("getline"); fprintf(fp, "]}"); return 0; } static char sixet2ch(int c) { c &= 0x3F; if (c < 26) return 'A' + c; c -= 26; if (c < 26) return 'a' + c; c -= 26; if (c < 10) return '0' + c; c -= 10; if (c == 0) return '+'; if (c == 1) return '/'; errx(1, "invalid sixet 0x%x", c); } static char * basic_auth(const char *username, const char *password) { char *str, *tmp, *end, *s, *p; char buf[3]; int len, i, r; r = asprintf(&str, "%s:%s", username, password); if (r == -1) fatal("asprintf"); /* * Will need 4 * r/3 bytes to encode the string, plus a * rounding to the next multiple of 4 for padding, plus NUL. */ len = 4 * r / 3; len = (len + 3) & ~3; len++; tmp = calloc(1, len); if (tmp == NULL) fatal("calloc"); s = str; p = tmp; while (*s != '\0') { memset(buf, 0, sizeof(buf)); for (i = 0; i < 3 && *s != '\0'; ++i, ++s) buf[i] = *s; *p++ = sixet2ch(buf[0] >> 2); *p++ = sixet2ch((buf[1] >> 4) | (buf[0] << 4)); if (i > 1) *p++ = sixet2ch((buf[1] << 2) | (buf[2] >> 6)); if (i > 2) *p++ = sixet2ch(buf[2]); } for (end = tmp + len - 1; p < end; ++p) *p = '='; free(str); return tmp; } static inline int bufio2poll(struct bufio *bio) { int f, ret = 0; /* * If we have data queued up, retry for both POLLIN and POLLOUT * since we want to push this data to the server while still * processing an eventual reply. Otherwise, we could wait * indefinitely for the server to reply without us having * sent the HTTP request completely. */ if (bio->wbuf.len) return POLLIN|POLLOUT; f = bufio_ev(bio); if (f & BUFIO_WANT_READ) ret |= POLLIN; if (f & BUFIO_WANT_WRITE) ret |= POLLOUT; return ret; } static unsigned char * compute_hmac_sha256(FILE *payload, off_t paylen, const char *hmac_secret, size_t secret_len, unsigned char *hmac_sig_buf, unsigned int *hmac_siglen) { HMAC_CTX *ctx; char buf[4096]; off_t n; ssize_t r; *hmac_siglen = 0; ctx = HMAC_CTX_new(); if (ctx == NULL) { log_warnx("HMAC_CTX_new failed"); return NULL; } if (!HMAC_Init_ex(ctx, hmac_secret, secret_len, EVP_sha256(), NULL)) { log_warnx("HMAC_Init_ex failed"); goto fail; } n = paylen; while (n > 0) { r = fread(buf, 1, n > sizeof(buf) ? sizeof(buf) : n, payload); if (r == 0) { if (feof(payload)) { log_warnx("HMAC payload truncated"); goto fail; } log_warn("failed to read HMAC payload"); goto fail; } if (!HMAC_Update(ctx, buf, r)) { log_warn("HMAC_Update"); goto fail; } n -= r; } if (!HMAC_Final(ctx, hmac_sig_buf, hmac_siglen)) { log_warnx("HMAC_Final failed"); goto fail; } *hmac_siglen = HMAC_size(ctx); HMAC_CTX_free(ctx); return hmac_sig_buf; fail: HMAC_CTX_free(ctx); return NULL; } int main(int argc, char **argv) { FILE *tmpfp; struct bufio bio; struct pollfd pfd; struct timespec timeout; const char *username; const char *password; const char *timeoutstr; const char *hmac_secret; const char *errstr; const char *repo = NULL; const char *host = NULL, *port = NULL, *path = NULL; const char *gotd_auth_user = NULL; char *auth, *line, *spc; unsigned char *hmac_sig = NULL; unsigned char hmac_sig_buf[EVP_MAX_MD_SIZE]; unsigned int hmac_siglen; char hex[SHA256_DIGEST_STRING_LENGTH]; size_t len; ssize_t r; off_t paylen; int tls = 0; int response_code = 0, done = 0; int ch, flags, ret, nonstd = 0; #ifndef PROFILE if (pledge("stdio rpath tmppath dns inet", NULL) == -1) err(1, "pledge"); #endif log_init(0, LOG_DAEMON); while ((ch = getopt(argc, argv, "ch:p:r:u:")) != -1) { switch (ch) { case 'c': tls = 1; break; case 'h': host = optarg; break; case 'p': port = optarg; break; case 'r': repo = optarg; break; case 'u': gotd_auth_user = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (host == NULL || repo == NULL || gotd_auth_user == NULL || argc != 1) usage(); if (tls && port == NULL) port = "443"; path = argv[0]; username = getenv("GOT_NOTIFY_HTTP_USER"); password = getenv("GOT_NOTIFY_HTTP_PASS"); if ((username != NULL && password == NULL) || (username == NULL && password != NULL)) fatalx("username or password are not specified"); if (username && *password == '\0') fatalx("password can't be empty"); /* used by the regression test suite */ timeoutstr = getenv("GOT_NOTIFY_TIMEOUT"); if (timeoutstr) { http_timeout = strtonum(timeoutstr, 0, 600, &errstr); if (errstr != NULL) fatalx("timeout in seconds is %s: %s", errstr, timeoutstr); } memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = http_timeout; tmpfp = got_opentemp(); if (tmpfp == NULL) fatal("opentemp"); jsonify(tmpfp, repo, gotd_auth_user); paylen = ftello(tmpfp); if (paylen == -1) fatal("ftello"); if (fseeko(tmpfp, 0, SEEK_SET) == -1) fatal("fseeko"); #ifndef PROFILE /* drop tmppath */ if (pledge("stdio rpath dns inet", NULL) == -1) err(1, "pledge"); #endif hmac_secret = getenv("GOT_NOTIFY_HTTP_HMAC_SECRET"); if (hmac_secret) { hmac_sig = compute_hmac_sha256(tmpfp, paylen, hmac_secret, strlen(hmac_secret), hmac_sig_buf, &hmac_siglen); if (hmac_sig == NULL || hmac_siglen != SHA256_DIGEST_LENGTH) fatalx("HMAC computation failed"); if (got_sha256_digest_to_str(hmac_sig, hex, sizeof(hex)) == NULL) fatalx("HMAC conversion to hex string failed"); if (fseeko(tmpfp, 0, SEEK_SET) == -1) fatal("fseeko"); } memset(&pfd, 0, sizeof(pfd)); pfd.fd = dial(host, port); if ((flags = fcntl(pfd.fd, F_GETFL)) == -1) fatal("fcntl(F_GETFL)"); if (fcntl(pfd.fd, F_SETFL, flags | O_NONBLOCK) == -1) fatal("fcntl(F_SETFL)"); if (bufio_init(&bio) == -1) fatal("bufio_init"); bufio_set_fd(&bio, pfd.fd); if (tls && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) fatal("bufio_starttls"); #ifndef PROFILE /* drop rpath dns inet */ if (pledge("stdio", NULL) == -1) err(1, "pledge"); /* revoke fs access */ if (landlock_no_fs() == -1) err(1, "landlock_no_fs"); if (cap_enter() == -1) err(1, "cap_enter"); #endif if ((!tls && strcmp(port, "80") != 0) || (tls && strcmp(port, "443")) != 0) nonstd = 1; ret = bufio_compose_fmt(&bio, "POST %s HTTP/1.1\r\n" "Host: %s%s%s\r\n" "Content-Type: application/json\r\n" "Content-Length: %lld\r\n" "User-Agent: %s\r\n" "Connection: close\r\n" "%s%s%s%s", path, host, nonstd ? ":" : "", nonstd ? port : "", (long long)paylen, USERAGENT, hmac_sig ? "X-Gotd-Signature: " : "", hmac_sig ? "sha256=" : "", hmac_sig ? hex : "", hmac_sig ? "\r\n" : ""); if (ret == -1) fatal("bufio_compose_fmt"); if (username) { auth = basic_auth(username, password); ret = bufio_compose_fmt(&bio, "Authorization: basic %s\r\n", auth); if (ret == -1) fatal("bufio_compose_fmt"); free(auth); } if (bufio_compose(&bio, "\r\n", 2) == -1) fatal("bufio_compose"); while (!done) { struct timespec elapsed, start, stop; char buf[BUFSIZ]; pfd.events = bufio2poll(&bio); clock_gettime(CLOCK_MONOTONIC, &start); ret = ppoll(&pfd, 1, &timeout, NULL); if (ret == -1) fatal("poll"); clock_gettime(CLOCK_MONOTONIC, &stop); timespecsub(&stop, &start, &elapsed); timespecsub(&timeout, &elapsed, &timeout); if (ret == 0 || timeout.tv_sec <= 0) fatalx("timeout"); if (bio.wbuf.len > 0) { if (bufio_write(&bio) == -1 && errno != EAGAIN) fatalx("bufio_write: %s", bufio_io_err(&bio)); } r = bufio_read(&bio); if (r == -1 && errno != EAGAIN) fatalx("bufio_read: %s", bufio_io_err(&bio)); if (r == 0) fatalx("unexpected EOF from upstream HTTP server"); for (;;) { line = buf_getdelim(&bio.rbuf, "\r\n", &len); if (line == NULL) break; if (response_code && *line == '\0') { /* * end of headers, don't bother * reading the body, if there is. */ done = 1; break; } if (response_code) { buf_drain(&bio.rbuf, len); continue; } spc = strchr(line, ' '); if (spc == NULL) fatalx("bad HTTP response from server"); *spc++ = '\0'; if (strcasecmp(line, "HTTP/1.1") != 0) log_warnx("warning: unexpected protocol: %s", line); line = spc; spc = strchr(line, ' '); if (spc == NULL) fatalx("bad HTTP response from server"); *spc++ = '\0'; response_code = strtonum(line, 100, 599, &errstr); if (errstr != NULL) log_warnx("warning: response code is %s: %s", errstr, line); buf_drain(&bio.rbuf, len); } if (done) break; if (!feof(tmpfp) && bio.wbuf.len < sizeof(buf)) { len = fread(buf, 1, sizeof(buf), tmpfp); if (len == 0) { if (ferror(tmpfp)) fatal("fread"); continue; } if (bufio_compose(&bio, buf, len) == -1) fatal("buf_compose"); } } if (response_code >= 200 && response_code < 300) return 0; fatalx("request failed with code %d", response_code); } got-portable-0.119/gotd/libexec/got-notify-http/Makefile.in0000664000175000017500000005575715066537207017335 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ libexec_PROGRAMS = got-notify-http$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd @HOST_OPENBSD_TRUE@am__append_2 = -ltls subdir = gotd/libexec/got-notify-http ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_got_notify_http_OBJECTS = got-notify-http.$(OBJEXT) \ $(top_builddir)/lib/bufio.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) got_notify_http_OBJECTS = $(am_got_notify_http_OBJECTS) got_notify_http_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bufio.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ ./$(DEPDIR)/got-notify-http.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(got_notify_http_SOURCES) DIST_SOURCES = $(got_notify_http_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libmd_CFLAGS) $(libtls_CFLAGS) $(libcrypto_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ EXTRA_DIST = utf8d.h got_notify_http_SOURCES = got-notify-http.c \ $(top_srcdir)/lib/bufio.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pollfd.c got_notify_http_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a LDADD = -L$(top_builddir)/compat -lopenbsd-compat $(zlib_LIBS) \ $(libbsd_LIBS) $(libutil_LIBS) $(libmd_LIBS) $(libtls_LIBS) \ $(libcrypto_LIBS) $(am__append_1) $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/got-notify-http/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/got-notify-http/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libexecdir)" && $(am__rm_f) $$files clean-libexecPROGRAMS: -$(am__rm_f) $(libexec_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bufio.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) got-notify-http$(EXEEXT): $(got_notify_http_OBJECTS) $(got_notify_http_DEPENDENCIES) $(EXTRA_got_notify_http_DEPENDENCIES) @rm -f got-notify-http$(EXEEXT) $(AM_V_CCLD)$(LINK) $(got_notify_http_OBJECTS) $(got_notify_http_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bufio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got-notify-http.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libexecPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-http.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/bufio.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f ./$(DEPDIR)/got-notify-http.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libexecPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecPROGRAMS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libexecPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotd/libexec/Makefile.in0000664000175000017500000004623615066537207014251 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = gotd/libexec ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = got-notify-email got-notify-http all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/libexec/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/libexec/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotd/parse.c0000664000175000017500000030363115066537233012041 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 24 "../gotd/parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "log.h" #include "gotd.h" #include "auth.h" #include "listen.h" #include "secrets.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int, int, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); static char *port_sprintf(int); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotd *gotd; static struct gotd_repo *new_repo; static int conf_limit_user_connections(const char *, int); static struct gotd_repo *conf_new_repo(const char *); static void conf_new_access_rule(struct gotd_repo *, enum gotd_access, int, char *); static int conf_protect_ref_namespace(char **, struct got_pathlist_head *, char *); static int conf_protect_tag_namespace(struct gotd_repo *, char *); static int conf_protect_branch_namespace( struct gotd_repo *, char *); static int conf_protect_branch(struct gotd_repo *, char *); static int conf_notify_branch(struct gotd_repo *, char *); static int conf_notify_ref_namespace(struct gotd_repo *, char *); static int conf_notify_email(struct gotd_repo *, char *, char *, char *, char *, char *); static int conf_notify_http(struct gotd_repo *, char *, char *, char *, int); static enum gotd_procid gotd_proc_id; typedef struct { union { long long number; char *string; struct timeval tv; } v; int lineno; } YYSTYPE; #line 176 "../gotd/parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ PATH = 258, /* PATH */ ERROR = 259, /* ERROR */ LISTEN = 260, /* LISTEN */ ON = 261, /* ON */ USER = 262, /* USER */ REPOSITORY = 263, /* REPOSITORY */ PERMIT = 264, /* PERMIT */ DENY = 265, /* DENY */ RO = 266, /* RO */ RW = 267, /* RW */ CONNECTION = 268, /* CONNECTION */ LIMIT = 269, /* LIMIT */ REQUEST = 270, /* REQUEST */ TIMEOUT = 271, /* TIMEOUT */ PROTECT = 272, /* PROTECT */ NAMESPACE = 273, /* NAMESPACE */ BRANCH = 274, /* BRANCH */ TAG = 275, /* TAG */ REFERENCE = 276, /* REFERENCE */ RELAY = 277, /* RELAY */ PORT = 278, /* PORT */ NOTIFY = 279, /* NOTIFY */ EMAIL = 280, /* EMAIL */ FROM = 281, /* FROM */ REPLY = 282, /* REPLY */ TO = 283, /* TO */ URL = 284, /* URL */ INSECURE = 285, /* INSECURE */ HMAC = 286, /* HMAC */ AUTH = 287, /* AUTH */ STRING = 288, /* STRING */ NUMBER = 289 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define PATH 258 #define ERROR 259 #define LISTEN 260 #define ON 261 #define USER 262 #define REPOSITORY 263 #define PERMIT 264 #define DENY 265 #define RO 266 #define RW 267 #define CONNECTION 268 #define LIMIT 269 #define REQUEST 270 #define TIMEOUT 271 #define PROTECT 272 #define NAMESPACE 273 #define BRANCH 274 #define TAG 275 #define REFERENCE 276 #define RELAY 277 #define PORT 278 #define NOTIFY 279 #define EMAIL 280 #define FROM 281 #define REPLY 282 #define TO 283 #define URL 284 #define INSECURE 285 #define HMAC 286 #define AUTH 287 #define STRING 288 #define NUMBER 289 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_PATH = 3, /* PATH */ YYSYMBOL_ERROR = 4, /* ERROR */ YYSYMBOL_LISTEN = 5, /* LISTEN */ YYSYMBOL_ON = 6, /* ON */ YYSYMBOL_USER = 7, /* USER */ YYSYMBOL_REPOSITORY = 8, /* REPOSITORY */ YYSYMBOL_PERMIT = 9, /* PERMIT */ YYSYMBOL_DENY = 10, /* DENY */ YYSYMBOL_RO = 11, /* RO */ YYSYMBOL_RW = 12, /* RW */ YYSYMBOL_CONNECTION = 13, /* CONNECTION */ YYSYMBOL_LIMIT = 14, /* LIMIT */ YYSYMBOL_REQUEST = 15, /* REQUEST */ YYSYMBOL_TIMEOUT = 16, /* TIMEOUT */ YYSYMBOL_PROTECT = 17, /* PROTECT */ YYSYMBOL_NAMESPACE = 18, /* NAMESPACE */ YYSYMBOL_BRANCH = 19, /* BRANCH */ YYSYMBOL_TAG = 20, /* TAG */ YYSYMBOL_REFERENCE = 21, /* REFERENCE */ YYSYMBOL_RELAY = 22, /* RELAY */ YYSYMBOL_PORT = 23, /* PORT */ YYSYMBOL_NOTIFY = 24, /* NOTIFY */ YYSYMBOL_EMAIL = 25, /* EMAIL */ YYSYMBOL_FROM = 26, /* FROM */ YYSYMBOL_REPLY = 27, /* REPLY */ YYSYMBOL_TO = 28, /* TO */ YYSYMBOL_URL = 29, /* URL */ YYSYMBOL_INSECURE = 30, /* INSECURE */ YYSYMBOL_HMAC = 31, /* HMAC */ YYSYMBOL_AUTH = 32, /* AUTH */ YYSYMBOL_STRING = 33, /* STRING */ YYSYMBOL_NUMBER = 34, /* NUMBER */ YYSYMBOL_35_n_ = 35, /* '\n' */ YYSYMBOL_36_ = 36, /* '=' */ YYSYMBOL_37_ = 37, /* '{' */ YYSYMBOL_38_ = 38, /* '}' */ YYSYMBOL_YYACCEPT = 39, /* $accept */ YYSYMBOL_grammar = 40, /* grammar */ YYSYMBOL_varset = 41, /* varset */ YYSYMBOL_numberstring = 42, /* numberstring */ YYSYMBOL_timeout = 43, /* timeout */ YYSYMBOL_main = 44, /* main */ YYSYMBOL_connection = 45, /* connection */ YYSYMBOL_conflags_l = 46, /* conflags_l */ YYSYMBOL_conflags = 47, /* conflags */ YYSYMBOL_protect = 48, /* protect */ YYSYMBOL_protectflags_l = 49, /* protectflags_l */ YYSYMBOL_protectflags = 50, /* protectflags */ YYSYMBOL_notify = 51, /* notify */ YYSYMBOL_notifyflags_l = 52, /* notifyflags_l */ YYSYMBOL_notifyflags = 53, /* notifyflags */ YYSYMBOL_repository = 54, /* repository */ YYSYMBOL_55_1 = 55, /* $@1 */ YYSYMBOL_repoopts1 = 56, /* repoopts1 */ YYSYMBOL_repoopts2 = 57, /* repoopts2 */ YYSYMBOL_nl = 58, /* nl */ YYSYMBOL_optnl = 59 /* optnl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_uint8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 142 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 39 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 21 /* YYNRULES -- Number of rules. */ #define YYNRULES 68 /* YYNSTATES -- Number of states. */ #define YYNSTATES 139 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 289 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 38, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 29, 30, 31, 32, 33, 34 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 141, 141, 142, 143, 144, 145, 148, 166, 167, 175, 183, 229, 246, 256, 259, 260, 262, 263, 266, 275, 285, 286, 288, 289, 292, 301, 311, 322, 323, 325, 326, 329, 338, 347, 357, 369, 381, 395, 407, 421, 435, 451, 465, 481, 497, 515, 527, 541, 555, 571, 581, 593, 605, 617, 631, 647, 647, 667, 706, 713, 721, 728, 729, 732, 733, 736, 739, 740 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "PATH", "ERROR", "LISTEN", "ON", "USER", "REPOSITORY", "PERMIT", "DENY", "RO", "RW", "CONNECTION", "LIMIT", "REQUEST", "TIMEOUT", "PROTECT", "NAMESPACE", "BRANCH", "TAG", "REFERENCE", "RELAY", "PORT", "NOTIFY", "EMAIL", "FROM", "REPLY", "TO", "URL", "INSECURE", "HMAC", "AUTH", "STRING", "NUMBER", "'\\n'", "'='", "'{'", "'}'", "$accept", "grammar", "varset", "numberstring", "timeout", "main", "connection", "conflags_l", "conflags", "protect", "protectflags_l", "protectflags", "notify", "notifyflags_l", "notifyflags", "repository", "$@1", "repoopts1", "repoopts2", "nl", "optnl", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-31) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -31, 1, -31, -2, -6, -26, 6, -23, -31, -12, 3, -31, 18, 29, -31, -31, -31, -31, 22, 59, 41, -31, 54, -31, -31, -31, -31, 49, 55, 16, 41, 42, -31, 41, 56, -31, -31, -31, -31, 45, 41, 15, -31, -31, 42, 58, 53, -6, -4, 23, -31, -31, 41, 2, -31, -31, -6, -6, -31, -16, 71, 41, -31, 60, 74, 35, 61, 41, -31, -31, -31, 62, -31, -31, 63, -31, 65, 50, -31, 66, 67, 68, 40, 26, 41, -31, -31, -31, 57, 41, -31, 75, 8, 69, 72, 70, 41, -31, -31, 50, 73, 76, 79, -31, 43, -31, 26, -31, 19, 81, 77, 80, 82, -31, 83, 84, 44, 91, 85, -31, 94, 86, -31, -31, 87, -31, 46, 92, 98, -31, -31, 89, 48, 100, -31, -31, 51, -31, -31 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 14, 0, 0, 8, 9, 13, 56, 0, 0, 68, 16, 0, 4, 5, 6, 12, 0, 0, 0, 68, 0, 7, 68, 0, 11, 10, 19, 67, 0, 68, 0, 20, 15, 18, 0, 0, 0, 0, 0, 62, 63, 68, 0, 17, 58, 0, 0, 61, 0, 0, 68, 22, 0, 0, 0, 0, 68, 29, 65, 57, 0, 59, 60, 0, 27, 0, 0, 32, 0, 0, 0, 50, 0, 68, 64, 26, 25, 0, 68, 33, 0, 34, 0, 0, 0, 68, 66, 21, 24, 0, 0, 0, 53, 51, 28, 31, 23, 35, 38, 0, 52, 0, 30, 0, 0, 0, 36, 0, 54, 39, 0, 42, 46, 0, 55, 0, 37, 40, 43, 47, 0, 0, 41, 44, 48, 0, 45, 49 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -31, -31, -31, 11, -31, -31, -31, 88, 118, -31, 27, 90, -31, 21, 93, -31, -31, 78, -31, -31, -30 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 9, 16, 37, 10, 11, 39, 40, 50, 88, 89, 51, 95, 96, 12, 27, 52, 53, 85, 31 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { 38, 2, 74, 41, 13, 45, 3, 17, 4, 5, 44, 46, 47, 22, 6, 59, 60, 75, 45, 48, 18, 19, 69, 23, 46, 47, 49, 14, 15, 28, 101, 77, 48, 61, 7, 102, 8, 83, 24, 49, 70, 114, 63, 20, 64, 63, 115, 64, 65, 35, 36, 65, 66, 25, 97, 66, 18, 19, 58, 99, 67, 80, 26, 81, 56, 57, 106, 72, 73, 59, 60, 93, 94, 111, 112, 29, 30, 122, 123, 129, 130, 134, 135, 43, 137, 138, 33, 32, 34, 76, 42, 55, 79, 78, 82, 98, 86, 84, 87, 90, 91, 92, 103, 100, 116, 104, 108, 110, 105, 109, 117, 118, 121, 124, 131, 119, 120, 126, 125, 127, 128, 132, 133, 136, 21, 0, 107, 113, 0, 0, 0, 71, 54, 0, 0, 0, 0, 0, 62, 0, 0, 0, 68 }; static const yytype_int8 yycheck[] = { 30, 0, 18, 33, 6, 3, 5, 33, 7, 8, 40, 9, 10, 36, 13, 19, 20, 33, 3, 17, 14, 15, 52, 35, 9, 10, 24, 33, 34, 7, 22, 61, 17, 37, 33, 27, 35, 67, 35, 24, 38, 22, 19, 37, 21, 19, 27, 21, 25, 33, 34, 25, 29, 35, 84, 29, 14, 15, 47, 89, 37, 26, 33, 28, 11, 12, 96, 56, 57, 19, 20, 31, 32, 30, 31, 16, 35, 33, 34, 33, 34, 33, 34, 38, 33, 34, 37, 33, 33, 18, 34, 33, 18, 33, 33, 38, 33, 35, 33, 33, 33, 33, 33, 28, 23, 33, 33, 28, 38, 33, 33, 31, 28, 22, 22, 33, 33, 23, 33, 33, 33, 23, 33, 23, 6, -1, 99, 106, -1, -1, -1, 53, 44, -1, -1, -1, -1, -1, 48, -1, -1, -1, 49 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 40, 0, 5, 7, 8, 13, 33, 35, 41, 44, 45, 54, 6, 33, 34, 42, 33, 14, 15, 37, 47, 36, 35, 35, 35, 33, 55, 7, 16, 35, 59, 33, 37, 33, 33, 34, 43, 59, 46, 47, 59, 34, 38, 59, 3, 9, 10, 17, 24, 48, 51, 56, 57, 46, 33, 11, 12, 42, 19, 20, 37, 50, 19, 21, 25, 29, 37, 53, 59, 38, 56, 42, 42, 18, 33, 18, 59, 33, 18, 26, 28, 33, 59, 35, 58, 33, 33, 49, 50, 33, 33, 33, 31, 32, 52, 53, 59, 38, 59, 28, 22, 27, 33, 33, 38, 59, 49, 33, 33, 28, 30, 31, 52, 22, 27, 23, 33, 31, 33, 33, 28, 33, 34, 22, 33, 23, 33, 33, 33, 34, 22, 23, 33, 33, 34, 23, 33, 34 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 39, 40, 40, 40, 40, 40, 41, 42, 42, 43, 43, 44, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 50, 51, 51, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 55, 54, 56, 56, 56, 56, 56, 56, 57, 57, 58, 59, 59 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 1, 1, 1, 1, 3, 2, 1, 5, 2, 3, 2, 3, 4, 5, 2, 3, 2, 3, 3, 2, 5, 2, 3, 2, 2, 3, 3, 5, 6, 8, 5, 7, 8, 10, 7, 9, 10, 12, 7, 9, 10, 12, 2, 4, 5, 4, 6, 7, 0, 7, 2, 3, 3, 2, 1, 1, 3, 2, 2, 2, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 7: /* varset: STRING '=' STRING */ #line 148 "../gotd/parse.y" { char *s = (yyvsp[-2].v.string); while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (symset((yyvsp[-2].v.string), (yyvsp[0].v.string), 0) == -1) fatal("cannot store variable"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1423 "../gotd/parse.c" break; case 9: /* numberstring: NUMBER */ #line 167 "../gotd/parse.y" { if (asprintf(&(yyval.v.string), "%lld", (long long)(yyvsp[0].v.number)) == -1) { yyerror("asprintf: %s", strerror(errno)); YYERROR; } } #line 1434 "../gotd/parse.c" break; case 10: /* timeout: NUMBER */ #line 175 "../gotd/parse.y" { if ((yyvsp[0].v.number) < 0) { yyerror("invalid timeout: %lld", (yyvsp[0].v.number)); YYERROR; } (yyval.v.tv).tv_sec = (yyvsp[0].v.number); (yyval.v.tv).tv_usec = 0; } #line 1447 "../gotd/parse.c" break; case 11: /* timeout: STRING */ #line 183 "../gotd/parse.y" { const char *errstr; const char *type = "seconds"; size_t len; int mul = 1; if (*(yyvsp[0].v.string) == '\0') { yyerror("invalid number of seconds: %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } len = strlen((yyvsp[0].v.string)); switch ((yyvsp[0].v.string)[len - 1]) { case 'S': case 's': (yyvsp[0].v.string)[len - 1] = '\0'; break; case 'M': case 'm': type = "minutes"; mul = 60; (yyvsp[0].v.string)[len - 1] = '\0'; break; case 'H': case 'h': type = "hours"; mul = 60 * 60; (yyvsp[0].v.string)[len - 1] = '\0'; break; } (yyval.v.tv).tv_usec = 0; (yyval.v.tv).tv_sec = strtonum((yyvsp[0].v.string), 0, INT_MAX / mul, &errstr); if (errstr) { yyerror("number of %s is %s: %s", type, errstr, (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } (yyval.v.tv).tv_sec *= mul; free((yyvsp[0].v.string)); } #line 1496 "../gotd/parse.c" break; case 12: /* main: LISTEN ON STRING */ #line 229 "../gotd/parse.y" { if (!got_path_is_absolute((yyvsp[0].v.string))) yyerror("bad unix socket path \"%s\": " "must be an absolute path", (yyvsp[0].v.string)); if (gotd_proc_id == GOTD_PROC_GOTD) { if (strlcpy(gotd->unix_socket_path, (yyvsp[0].v.string), sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { yyerror("%s: unix socket path too long", __func__); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1518 "../gotd/parse.c" break; case 13: /* main: USER numberstring */ #line 246 "../gotd/parse.y" { if (strlcpy(gotd->user_name, (yyvsp[0].v.string), sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { yyerror("%s: user name too long", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1533 "../gotd/parse.c" break; case 19: /* conflags: REQUEST TIMEOUT timeout */ #line 266 "../gotd/parse.y" { if ((yyvsp[0].v.tv).tv_sec <= 0) { yyerror("invalid timeout: %lld", (long long)(yyvsp[0].v.tv).tv_sec); YYERROR; } memcpy(&gotd->request_timeout, &(yyvsp[0].v.tv), sizeof(gotd->request_timeout)); } #line 1547 "../gotd/parse.c" break; case 20: /* conflags: LIMIT USER STRING NUMBER */ #line 275 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD && conf_limit_user_connections((yyvsp[-1].v.string), (yyvsp[0].v.number)) == -1) { free((yyvsp[-1].v.string)); YYERROR; } free((yyvsp[-1].v.string)); } #line 1560 "../gotd/parse.c" break; case 25: /* protectflags: TAG NAMESPACE STRING */ #line 292 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_tag_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1574 "../gotd/parse.c" break; case 26: /* protectflags: BRANCH NAMESPACE STRING */ #line 301 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1589 "../gotd/parse.c" break; case 27: /* protectflags: BRANCH STRING */ #line 311 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1603 "../gotd/parse.c" break; case 32: /* notifyflags: BRANCH STRING */ #line 329 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_branch(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1617 "../gotd/parse.c" break; case 33: /* notifyflags: REFERENCE NAMESPACE STRING */ #line 338 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_ref_namespace(new_repo, (yyvsp[0].v.string))) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1631 "../gotd/parse.c" break; case 34: /* notifyflags: EMAIL TO STRING */ #line 347 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[0].v.string), NULL, NULL, NULL)) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1646 "../gotd/parse.c" break; case 35: /* notifyflags: EMAIL FROM STRING TO STRING */ #line 357 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL, NULL, NULL)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1663 "../gotd/parse.c" break; case 36: /* notifyflags: EMAIL TO STRING REPLY TO STRING */ #line 369 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-3].v.string), (yyvsp[0].v.string), NULL, NULL)) { free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); } #line 1680 "../gotd/parse.c" break; case 37: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING */ #line 381 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-5].v.string), (yyvsp[-3].v.string), (yyvsp[0].v.string), NULL, NULL)) { free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); } #line 1699 "../gotd/parse.c" break; case 38: /* notifyflags: EMAIL TO STRING RELAY STRING */ #line 395 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-2].v.string), NULL, (yyvsp[0].v.string), NULL)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1716 "../gotd/parse.c" break; case 39: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING */ #line 407 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-4].v.string), (yyvsp[-2].v.string), NULL, (yyvsp[0].v.string), NULL)) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1735 "../gotd/parse.c" break; case 40: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING */ #line 421 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-5].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL)) { free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1754 "../gotd/parse.c" break; case 41: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING */ #line 435 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-7].v.string), (yyvsp[-5].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL)) { free((yyvsp[-7].v.string)); free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-5].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1775 "../gotd/parse.c" break; case 42: /* notifyflags: EMAIL TO STRING RELAY STRING PORT STRING */ #line 451 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1794 "../gotd/parse.c" break; case 43: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING PORT STRING */ #line 465 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-6].v.string), (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1815 "../gotd/parse.c" break; case 44: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING */ #line 481 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1836 "../gotd/parse.c" break; case 45: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING */ #line 497 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-9].v.string), (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string))) { free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1859 "../gotd/parse.c" break; case 46: /* notifyflags: EMAIL TO STRING RELAY STRING PORT NUMBER */ #line 515 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1876 "../gotd/parse.c" break; case 47: /* notifyflags: EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER */ #line 527 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-6].v.string), (yyvsp[-4].v.string), NULL, (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-6].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1895 "../gotd/parse.c" break; case 48: /* notifyflags: EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER */ #line 541 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1914 "../gotd/parse.c" break; case 49: /* notifyflags: EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER */ #line 555 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, (yyvsp[-9].v.string), (yyvsp[-7].v.string), (yyvsp[-4].v.string), (yyvsp[-2].v.string), port_sprintf((yyvsp[0].v.number)))) { free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); YYERROR; } } free((yyvsp[-9].v.string)); free((yyvsp[-7].v.string)); free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); } #line 1935 "../gotd/parse.c" break; case 50: /* notifyflags: URL STRING */ #line 571 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[0].v.string), NULL, NULL, 0)) { free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[0].v.string)); } #line 1950 "../gotd/parse.c" break; case 51: /* notifyflags: URL STRING AUTH STRING */ #line 581 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[-2].v.string), (yyvsp[0].v.string), NULL, 0)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1967 "../gotd/parse.c" break; case 52: /* notifyflags: URL STRING AUTH STRING INSECURE */ #line 593 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[-3].v.string), (yyvsp[-1].v.string), NULL, 1)) { free((yyvsp[-3].v.string)); free((yyvsp[-1].v.string)); YYERROR; } } free((yyvsp[-3].v.string)); free((yyvsp[-1].v.string)); } #line 1984 "../gotd/parse.c" break; case 53: /* notifyflags: URL STRING HMAC STRING */ #line 605 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[-2].v.string), NULL, (yyvsp[0].v.string), 0)) { free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 2001 "../gotd/parse.c" break; case 54: /* notifyflags: URL STRING AUTH STRING HMAC STRING */ #line 617 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[-4].v.string), (yyvsp[-2].v.string), (yyvsp[0].v.string), 0)) { free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-4].v.string)); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 2020 "../gotd/parse.c" break; case 55: /* notifyflags: URL STRING AUTH STRING INSECURE HMAC STRING */ #line 631 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, (yyvsp[-5].v.string), (yyvsp[-3].v.string), (yyvsp[0].v.string), 1)) { free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); YYERROR; } } free((yyvsp[-5].v.string)); free((yyvsp[-3].v.string)); free((yyvsp[0].v.string)); } #line 2039 "../gotd/parse.c" break; case 56: /* $@1: %empty */ #line 647 "../gotd/parse.y" { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->name, (yyvsp[0].v.string)) == 0) { yyerror("duplicate repository '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (gotd_proc_id == GOTD_PROC_GOTD || gotd_proc_id == GOTD_PROC_GITWRAPPER) { new_repo = conf_new_repo((yyvsp[0].v.string)); } free((yyvsp[0].v.string)); } #line 2061 "../gotd/parse.c" break; case 57: /* repository: REPOSITORY STRING $@1 '{' optnl repoopts2 '}' */ #line 663 "../gotd/parse.y" { } #line 2068 "../gotd/parse.c" break; case 58: /* repoopts1: PATH STRING */ #line 667 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD || gotd_proc_id == GOTD_PROC_GITWRAPPER) { if (!got_path_is_absolute((yyvsp[0].v.string))) { yyerror("%s: path %s is not absolute", __func__, (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } if (realpath((yyvsp[0].v.string), new_repo->path) == NULL) { /* * To give admins a chance to create * missing repositories at run-time * we only warn about ENOENT here. * * And ignore 'permission denied' when * running in gitwrapper. Users may be * able to access this repository via * gotd regardless. */ if (errno == ENOENT) { log_warn("%s", (yyvsp[0].v.string)); } else if (errno != EACCES || gotd_proc_id != GOTD_PROC_GITWRAPPER) { yyerror("realpath %s: %s", (yyvsp[0].v.string), strerror(errno)); free((yyvsp[0].v.string)); YYERROR; } if (strlcpy(new_repo->path, (yyvsp[0].v.string), sizeof(new_repo->path)) >= sizeof(new_repo->path)) yyerror("path too long"); } } free((yyvsp[0].v.string)); } #line 2112 "../gotd/parse.c" break; case 59: /* repoopts1: PERMIT RO numberstring */ #line 706 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2124 "../gotd/parse.c" break; case 60: /* repoopts1: PERMIT RW numberstring */ #line 713 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ | GOTD_AUTH_WRITE, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2137 "../gotd/parse.c" break; case 61: /* repoopts1: DENY numberstring */ #line 721 "../gotd/parse.y" { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_DENIED, 0, (yyvsp[0].v.string)); } else free((yyvsp[0].v.string)); } #line 2149 "../gotd/parse.c" break; #line 2153 "../gotd/parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 743 "../gotd/parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "auth", AUTH }, { "branch", BRANCH }, { "connection", CONNECTION }, { "deny", DENY }, { "email", EMAIL }, { "from", FROM }, { "hmac", HMAC }, { "insecure", INSECURE }, { "limit", LIMIT }, { "listen", LISTEN }, { "namespace", NAMESPACE }, { "notify", NOTIFY }, { "on", ON }, { "path", PATH }, { "permit", PERMIT }, { "port", PORT }, { "protect", PROTECT }, { "reference", REFERENCE }, { "relay", RELAY }, { "reply", REPLY }, { "repository", REPOSITORY }, { "request", REQUEST }, { "ro", RO }, { "rw", RW }, { "tag", TAG }, { "timeout", TIMEOUT }, { "to", TO }, { "url", URL }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int conf_fd, int secret, int required) { struct file *nfile; int fd = -1; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } fd = dup(conf_fd); if (fd == -1) return NULL; nfile->stream = fdopen(fd, "r"); if (nfile->stream == NULL) { if (required) log_warn("open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } int gotd_parse_config(const char *filename, int conf_fd, enum gotd_procid proc_id, struct gotd_secrets *secrets, struct gotd *env) { struct sym *sym, *next; struct gotd_repo *repo; int require_config_file = (proc_id != GOTD_PROC_GITWRAPPER); memset(env, 0, sizeof(*env)); gotd = env; gotd_proc_id = proc_id; gotd->secrets = secrets; TAILQ_INIT(&gotd->repos); /* Apply default values. */ if (strlcpy(gotd->unix_socket_path, GOTD_UNIX_SOCKET, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { fprintf(stderr, "%s: unix socket path too long", __func__); return -1; } if (strlcpy(gotd->user_name, GOTD_USER, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { fprintf(stderr, "%s: user name too long", __func__); return -1; } gotd->request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd->request_timeout.tv_usec = 0; if (conf_fd == -1 && !require_config_file) return 0; file = newfile(filename, conf_fd, 0, require_config_file); if (file == NULL) return require_config_file ? -1 : 0; yyparse(); errors = file->errors; closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotd->verbosity > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (errors) return (-1); TAILQ_FOREACH(repo, &gotd->repos, entry) { if (repo->path[0] == '\0') { log_warnx("repository \"%s\": no path provided in " "configuration file", repo->name); return (-1); } } if (proc_id == GOTD_PROC_GOTD && TAILQ_EMPTY(&gotd->repos)) { log_warnx("no repository defined in configuration file"); return (-1); } return (0); } static int uid_connection_limit_cmp(const void *pa, const void *pb) { const struct gotd_uid_connection_limit *a = pa, *b = pb; if (a->uid < b->uid) return -1; else if (a->uid > b->uid); return 1; return 0; } static int conf_limit_user_connections(const char *user, int maximum) { uid_t uid; struct gotd_uid_connection_limit *limit; size_t nlimits; if (maximum < 1) { yyerror("max connections cannot be smaller 1"); return -1; } if (maximum > GOTD_MAXCLIENTS) { yyerror("max connections must be <= %d", GOTD_MAXCLIENTS); return -1; } if (gotd_parseuid(user, &uid) == -1) { yyerror("%s: no such user", user); return -1; } limit = gotd_find_uid_connection_limit(gotd->connection_limits, gotd->nconnection_limits, uid); if (limit) { limit->max_connections = maximum; return 0; } limit = gotd->connection_limits; nlimits = gotd->nconnection_limits + 1; limit = reallocarray(limit, nlimits, sizeof(*limit)); if (limit == NULL) fatal("reallocarray"); limit[nlimits - 1].uid = uid; limit[nlimits - 1].max_connections = maximum; gotd->connection_limits = limit; gotd->nconnection_limits = nlimits; qsort(gotd->connection_limits, gotd->nconnection_limits, sizeof(gotd->connection_limits[0]), uid_connection_limit_cmp); return 0; } const struct got_error * gotd_conf_new_repo(struct gotd_repo **new_repo, const char *name) { struct gotd_repo *repo; repo = calloc(1, sizeof(*repo)); if (repo == NULL) return got_error_from_errno("calloc"); STAILQ_INIT(&repo->rules); RB_INIT(&repo->protected_tag_namespaces); RB_INIT(&repo->protected_branch_namespaces); RB_INIT(&repo->protected_branches); RB_INIT(&repo->protected_branches); RB_INIT(&repo->notification_refs); RB_INIT(&repo->notification_ref_namespaces); STAILQ_INIT(&repo->notification_targets); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) { free(repo); return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } *new_repo = repo; return NULL; } static struct gotd_repo * conf_new_repo(const char *name) { const struct got_error *err; struct gotd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); err = gotd_conf_new_repo(&repo, name); if (err) fatalx("%s", err->msg); TAILQ_INSERT_TAIL(&gotd->repos, repo, entry); gotd->nrepos++; return repo; }; static void conf_new_access_rule(struct gotd_repo *repo, enum gotd_access access, int authorization, char *identifier) { struct gotd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; rule->authorization = authorization; rule->identifier = identifier; STAILQ_INSERT_TAIL(&repo->rules, rule, entry); } static int refname_is_valid(char *refname) { if (strncmp(refname, "refs/", 5) != 0) { yyerror("reference name must begin with \"refs/\": %s", refname); return 0; } if (!got_ref_name_is_valid(refname)) { yyerror("invalid reference name: %s", refname); return 0; } return 1; } static int conf_protect_ref_namespace(char **new, struct got_pathlist_head *refs, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; *new = NULL; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, refs, s, NULL); if (error || pe == NULL) { free(s); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protected namespace %s", namespace); return -1; } *new = s; return 0; } static int conf_protect_tag_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_tag_namespaces, namespace) == -1) return -1; repo->nprotected_tag_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_branch_namespaces) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_branch_namespaces, namespace) == -1) return -1; repo->nprotected_branch_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_tag_namespaces) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *new; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&new, &repo->protected_branches, refname, NULL); if (error || new == NULL) { free(refname); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protect branch %s", branchname); return -1; } repo->nprotected_branches++; return 0; } static int conf_notify_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *pe; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&pe, &repo->notification_refs, refname, NULL); if (error) { free(refname); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(refname); else repo->num_notification_refs++; return 0; } static int conf_notify_ref_namespace(struct gotd_repo *repo, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, &repo->notification_ref_namespaces, s, NULL); if (error) { free(s); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(s); else repo->num_notification_ref_namespaces++; return 0; } static int conf_notify_email(struct gotd_repo *repo, char *sender, char *recipient, char *responder, char *hostname, char *port) { struct gotd_notification_target *target; STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_EMAIL) continue; if (strcmp(target->conf.email.recipient, recipient) == 0) { yyerror("duplicate email notification for '%s' in " "repository '%s'", recipient, repo->name); return -1; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_EMAIL; if (sender) { target->conf.email.sender = strdup(sender); if (target->conf.email.sender == NULL) fatal("strdup"); } target->conf.email.recipient = strdup(recipient); if (target->conf.email.recipient == NULL) fatal("strdup"); if (responder) { target->conf.email.responder = strdup(responder); if (target->conf.email.responder == NULL) fatal("strdup"); } if (hostname) { target->conf.email.hostname = strdup(hostname); if (target->conf.email.hostname == NULL) fatal("strdup"); } if (port) { target->conf.email.port = strdup(port); if (target->conf.email.port == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); return 0; } static int conf_notify_http(struct gotd_repo *repo, char *url, char *auth, char *hmac, int insecure) { const struct got_error *error; struct gotd_notification_target *target; char *proto, *hostname, *port, *path; int tls = 0, ret = 0; error = gotd_parse_url(&proto, &hostname, &port, &path, url); if (error) { yyerror("invalid HTTP notification URL '%s' in " "repository '%s': %s", url, repo->name, error->msg); return -1; } tls = !strcmp(proto, "https"); if (strcmp(proto, "http") != 0 && strcmp(proto, "https") != 0) { yyerror("invalid protocol '%s' in notification URL '%s' in " "repository '%s", proto, url, repo->name); ret = -1; goto done; } if (port == NULL) { if (strcmp(proto, "http") == 0) port = strdup("80"); if (strcmp(proto, "https") == 0) port = strdup("443"); if (port == NULL) { error = got_error_from_errno("strdup"); ret = -1; goto done; } } if (auth != NULL && gotd_proc_id == GOTD_PROC_GOTD && (gotd->secrets == NULL || gotd_secrets_get(gotd->secrets, GOTD_SECRET_AUTH, auth) == NULL)) { yyerror("no auth secret `%s' defined", auth); ret = -1; goto done; } if (hmac != NULL && gotd_proc_id == GOTD_PROC_GOTD && (gotd->secrets == NULL && gotd_secrets_get(gotd->secrets, GOTD_SECRET_HMAC, hmac) == NULL)) { yyerror("no hmac secret `%s' defined", hmac); ret = -1; goto done; } if (!insecure && strcmp(proto, "http") == 0 && auth) { yyerror("%s: HTTP notifications with basic authentication " "over plaintext HTTP will leak credentials; add the " "'insecure' config keyword if this is intentional", url); ret = -1; goto done; } STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_HTTP) continue; if (target->conf.http.tls == tls && !strcmp(target->conf.http.hostname, hostname) && !strcmp(target->conf.http.port, port) && !strcmp(target->conf.http.path, path)) { yyerror("duplicate notification for URL '%s' in " "repository '%s'", url, repo->name); ret = -1; goto done; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_HTTP; target->conf.http.tls = tls; target->conf.http.hostname = hostname; target->conf.http.port = port; target->conf.http.path = path; hostname = port = path = NULL; if (auth) { target->conf.http.auth = strdup(auth); if (target->conf.http.auth == NULL) fatal("strdup"); } if (hmac) { target->conf.http.hmac = strdup(hmac); if (target->conf.http.hmac == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); done: free(proto); free(hostname); free(port); free(path); return ret; } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } struct gotd_repo * gotd_find_repo_by_name(const char *repo_name, struct gotd_repolist *repos) { struct gotd_repo *repo; size_t namelen; TAILQ_FOREACH(repo, repos, entry) { namelen = strlen(repo->name); if (strncmp(repo->name, repo_name, namelen) != 0) continue; if (repo_name[namelen] == '\0' || strcmp(&repo_name[namelen], ".git") == 0) return repo; } return NULL; } struct gotd_repo * gotd_find_repo_by_path(const char *repo_path, struct gotd *gotd) { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->path, repo_path) == 0) return repo; } return NULL; } struct gotd_uid_connection_limit * gotd_find_uid_connection_limit(struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid) { /* This array is always sorted to allow for binary search. */ int i, left = 0, right = nlimits - 1; while (left <= right) { i = ((left + right) / 2); if (limits[i].uid == uid) return &limits[i]; if (limits[i].uid > uid) left = i + 1; else right = i - 1; } return NULL; } int gotd_parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } const struct got_error * gotd_parse_url(char **proto, char **host, char **port, char **request_path, const char *url) { const struct got_error *err = NULL; char *s, *p, *q; *proto = *host = *port = *request_path = NULL; p = strstr(url, "://"); if (!p) return got_error(GOT_ERR_PARSE_URI); *proto = strndup(url, p - url); if (*proto == NULL) { err = got_error_from_errno("strndup"); goto done; } s = p + 3; p = strstr(s, "/"); if (p == NULL) { err = got_error(GOT_ERR_PARSE_URI); goto done; } q = memchr(s, ':', p - s); if (q) { *host = strndup(s, q - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } *port = strndup(q + 1, p - (q + 1)); if (*port == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*port)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } else { *host = strndup(s, p - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } while (p[0] == '/' && p[1] == '/') p++; *request_path = strdup(p); if (*request_path == NULL) { err = got_error_from_errno("strdup"); goto done; } if ((*request_path)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } done: if (err) { free(*proto); *proto = NULL; free(*host); *host = NULL; free(*port); *port = NULL; free(*request_path); *request_path = NULL; } return err; } static char * port_sprintf(int p) { static char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)p); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)p); return portno; } got-portable-0.119/gotd/repo_write.h0000664000175000017500000000165015066535721013107 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void repo_write_main(const char *, const char *, int *, int *, FILE *, FILE *, FILE *, FILE *, int, int); void repo_write_shutdown(void); got-portable-0.119/gotd/repo_read.h0000664000175000017500000000157015066535721012671 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void repo_read_main(const char *, const char *, int *, int *); void repo_read_shutdown(void); got-portable-0.119/gotd/listen.c0000664000175000017500000003550015066536113012216 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_compat.h" #include "gotd.h" #include "log.h" #include "listen.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct gotd_listen_client { STAILQ_ENTRY(gotd_listen_client) entry; uint32_t id; int fd; uid_t euid; }; STAILQ_HEAD(gotd_listen_clients, gotd_listen_client); static struct gotd_listen_clients gotd_listen_clients[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY clients_hash_key; static volatile int listen_client_cnt; static int inflight; static int listener_halted; struct gotd_uid_connection_counter { STAILQ_ENTRY(gotd_uid_connection_counter) entry; uid_t euid; int nconnections; }; STAILQ_HEAD(gotd_client_uids, gotd_uid_connection_counter); static struct gotd_client_uids gotd_client_uids[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY uid_hash_key; static struct { pid_t pid; const char *title; int fd; struct gotd_imsgev iev; struct gotd_imsgev parent_iev; struct event pause_ev; struct gotd_uid_connection_limit *connection_limits; size_t nconnection_limits; size_t nconnection_limits_received; } gotd_listen; static int inflight; static void listen_shutdown(void); static void listen_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: break; case SIGUSR1: break; case SIGTERM: case SIGINT: listen_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static void clients_init(void) { uint64_t slot; arc4random_buf(&clients_hash_key, sizeof(clients_hash_key)); for (slot = 0; slot < nitems(gotd_listen_clients); slot++) STAILQ_INIT(&gotd_listen_clients[slot]); } static uint64_t client_hash(uint32_t client_id) { return SipHash24(&clients_hash_key, &client_id, sizeof(client_id)); } static void add_client(struct gotd_listen_client *client) { uint64_t slot = client_hash(client->id) % nitems(gotd_listen_clients); STAILQ_INSERT_HEAD(&gotd_listen_clients[slot], client, entry); listen_client_cnt++; } static struct gotd_listen_client * find_client(uint32_t client_id) { uint64_t slot; struct gotd_listen_client *c; slot = client_hash(client_id) % nitems(gotd_listen_clients); STAILQ_FOREACH(c, &gotd_listen_clients[slot], entry) { if (c->id == client_id) return c; } return NULL; } static uint32_t get_client_id(void) { int duplicate = 0; uint32_t id; do { id = arc4random(); duplicate = (find_client(id) != NULL); } while (duplicate || id == 0); return id; } static uint64_t uid_hash(uid_t euid) { return SipHash24(&uid_hash_key, &euid, sizeof(euid)); } static void add_uid_connection_counter(struct gotd_uid_connection_counter *counter) { uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids); STAILQ_INSERT_HEAD(&gotd_client_uids[slot], counter, entry); } static void remove_uid_connection_counter(struct gotd_uid_connection_counter *counter) { uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids); STAILQ_REMOVE(&gotd_client_uids[slot], counter, gotd_uid_connection_counter, entry); } static struct gotd_uid_connection_counter * find_uid_connection_counter(uid_t euid) { uint64_t slot; struct gotd_uid_connection_counter *c; slot = uid_hash(euid) % nitems(gotd_client_uids); STAILQ_FOREACH(c, &gotd_client_uids[slot], entry) { if (c->euid == euid) return c; } return NULL; } static const struct got_error * disconnect(struct gotd_listen_client *client) { struct gotd_uid_connection_counter *counter; uint64_t slot; int client_fd; log_debug("client on fd %d disconnecting", client->fd); slot = client_hash(client->id) % nitems(gotd_listen_clients); STAILQ_REMOVE(&gotd_listen_clients[slot], client, gotd_listen_client, entry); counter = find_uid_connection_counter(client->euid); if (counter) { if (counter->nconnections > 0) counter->nconnections--; if (counter->nconnections == 0) { remove_uid_connection_counter(counter); free(counter); } } client_fd = client->fd; free(client); inflight--; listen_client_cnt--; if (close(client_fd) == -1) return got_error_from_errno("close"); if (listener_halted && listen_client_cnt == 0) listen_shutdown(); return NULL; } static int accept_reserve(int fd, struct sockaddr *addr, socklen_t *addrlen, int reserve, volatile int *counter) { int ret; int sock_flags = SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (getdtablecount() + reserve + ((*counter + 1) * GOTD_FD_NEEDED) >= getdtablesize()) { log_debug("inflight fds exceeded"); errno = EMFILE; return -1; } #ifdef __APPLE__ /* TA: silence warning from GCC. */ (void)sock_flags; ret = accept(fd, addr, addrlen); #else ret = accept4(fd, addr, addrlen, sock_flags); #endif if (ret > -1) { (*counter)++; } return ret; } static void gotd_accept(int fd, short event, void *arg) { struct gotd_imsgev *iev = arg; struct sockaddr_storage ss; struct timeval backoff; socklen_t len; int s = -1; struct gotd_listen_client *client = NULL; struct gotd_uid_connection_counter *counter = NULL; struct gotd_imsg_connect iconn; uid_t euid; gid_t egid; backoff.tv_sec = 1; backoff.tv_usec = 0; if (event_add(&iev->ev, NULL) == -1) { log_warn("event_add"); return; } if (event & EV_TIMEOUT) return; len = sizeof(ss); /* Other backoff conditions apart from EMFILE/ENFILE? */ s = accept_reserve(fd, (struct sockaddr *)&ss, &len, GOTD_FD_RESERVE, &inflight); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: return; case EMFILE: case ENFILE: event_del(&iev->ev); evtimer_add(&gotd_listen.pause_ev, &backoff); return; default: log_warn("accept"); /* Prevent endless looping on errors. */ event_del(&iev->ev); event_loopexit(NULL); return; } } if (listen_client_cnt >= GOTD_MAXCLIENTS) goto err; if (getpeereid(s, &euid, &egid) == -1) { log_warn("getpeerid"); goto err; } counter = find_uid_connection_counter(euid); if (counter == NULL) { counter = calloc(1, sizeof(*counter)); if (counter == NULL) { log_warn("%s: calloc", __func__); goto err; } counter->euid = euid; counter->nconnections = 1; add_uid_connection_counter(counter); } else { int max_connections = GOTD_MAX_CONN_PER_UID; struct gotd_uid_connection_limit *limit; limit = gotd_find_uid_connection_limit( gotd_listen.connection_limits, gotd_listen.nconnection_limits, euid); if (limit) max_connections = limit->max_connections; if (counter->nconnections >= max_connections) { const struct got_error *error; struct imsgbuf ibuf; log_warnx("maximum connections exceeded for uid %d", euid); /* Report error to client and close connection. */ if (imsgbuf_init(&ibuf, s) == -1) { log_warn("imsgbuf_init"); goto err; } error = got_error(GOT_ERR_CONNECTION_LIMIT); if (gotd_imsg_send_error(&ibuf, GOTD_PROC_LISTEN, 0, error) == -1) log_warn("imsg send error"); goto err; } counter->nconnections++; } client = calloc(1, sizeof(*client)); if (client == NULL) { log_warn("%s: calloc", __func__); goto err; } client->id = get_client_id(); client->fd = s; client->euid = euid; s = -1; add_client(client); log_debug("%s: new client connected on fd %d uid %d gid %d", __func__, client->fd, euid, egid); memset(&iconn, 0, sizeof(iconn)); iconn.client_id = client->id; iconn.euid = euid; iconn.egid = egid; s = dup(client->fd); if (s == -1) { log_warn("%s: dup", __func__); goto err; } if (gotd_imsg_compose_event(&gotd_listen.parent_iev, GOTD_IMSG_CONNECT, GOTD_PROC_LISTEN, s, &iconn, sizeof(iconn)) == -1) { log_warn("imsg compose CONNECT"); goto err; } return; err: inflight--; if (client) disconnect(client); if (s != -1) close(s); } static const struct got_error * recv_listen_socket(struct imsg *imsg) { struct gotd_imsg_listen_socket isocket; size_t datalen; if (gotd_listen.fd != -1 || gotd_listen.nconnection_limits_received != 0) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(isocket)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&isocket, imsg->data, sizeof(isocket)); gotd_listen.fd = imsg_get_fd(imsg); if (gotd_listen.fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); #ifndef PROFILE /* The "recvfd" promise is no longer needed. */ if (pledge("stdio sendfd unix", NULL) == -1) fatal("pledge"); #endif gotd_listen.nconnection_limits = isocket.nconnection_limits; gotd_listen.nconnection_limits_received = 0; if (gotd_listen.nconnection_limits > 0) { gotd_listen.connection_limits = calloc(gotd_listen.nconnection_limits, sizeof(gotd_listen.connection_limits[0])); if (gotd_listen.connection_limits == NULL) return got_error_from_errno("calloc"); } return NULL; } static const struct got_error * recv_connection_limit(struct imsg *imsg) { struct gotd_uid_connection_limit *limit; size_t datalen, idx; if (gotd_listen.nconnection_limits == 0 || gotd_listen.nconnection_limits_received >= gotd_listen.nconnection_limits) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(*limit)) return got_error(GOT_ERR_PRIVSEP_LEN); idx = gotd_listen.nconnection_limits_received; limit = &gotd_listen.connection_limits[idx]; memcpy(limit, imsg->data, sizeof(*limit)); gotd_listen.nconnection_limits_received++; return NULL; } static void start_listening(void) { struct gotd_imsgev *iev; iev = &gotd_listen.iev; if (imsgbuf_init(&iev->ibuf, gotd_listen.fd) == -1) fatal("imsgbuf_init"); iev->handler = gotd_accept; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, gotd_listen.fd, EV_READ | EV_PERSIST, gotd_accept, iev); if (event_add(&iev->ev, NULL)) fatalx("event add"); evtimer_set(&gotd_listen.pause_ev, gotd_accept, NULL); log_debug("listening for client connections"); } static const struct got_error * recv_disconnect(struct imsg *imsg) { struct gotd_imsg_disconnect idisconnect; size_t datalen; struct gotd_listen_client *client = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(idisconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&idisconnect, imsg->data, sizeof(idisconnect)); log_debug("client disconnecting"); client = find_client(idisconnect.client_id); if (client == NULL) return got_error(GOT_ERR_CLIENT_ID); return disconnect(client); } static void listen_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_LISTEN_SOCKET: err = recv_listen_socket(&imsg); if (err) break; if (gotd_listen.nconnection_limits == 0) start_listening(); break; case GOTD_IMSG_CONNECTION_LIMIT: err = recv_connection_limit(&imsg); if (err) break; if (gotd_listen.nconnection_limits == gotd_listen.nconnection_limits_received) start_listening(); break; case GOTD_IMSG_DISCONNECT: err = recv_disconnect(&imsg); if (err) log_warnx("disconnect: %s", err->msg); break; case GOTD_IMSG_HALT: { uint32_t reload_client_id; struct gotd_listen_client *client; event_del(&gotd_listen.iev.ev); evtimer_del(&gotd_listen.pause_ev); listener_halted = 1; log_debug("gotd reloading; stopped listening for " "connections"); if (imsg_get_data(&imsg, &reload_client_id, sizeof(reload_client_id)) == -1) { err = got_error_from_errno("imsg-get_data"); break; } client = find_client(reload_client_id); if (client) disconnect(client); break; } default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); if (!listener_halted) event_loopexit(NULL); } } void listen_main(const char *title) { struct gotd_imsgev *iev; struct event evsigint, evsigterm, evsighup, evsigusr1; clients_init(); arc4random_buf(&uid_hash_key, sizeof(uid_hash_key)); gotd_listen.title = title; gotd_listen.pid = getpid(); gotd_listen.fd = -1; gotd_listen.connection_limits = NULL; gotd_listen.nconnection_limits = 0; gotd_listen.nconnection_limits_received = 0; signal_set(&evsigint, SIGINT, listen_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, listen_sighdlr, NULL); signal_set(&evsighup, SIGHUP, listen_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, listen_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); iev = &gotd_listen.parent_iev; if (imsgbuf_init(&iev->ibuf, GOTD_FILENO_MSG_PIPE) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = listen_dispatch; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, listen_dispatch, iev); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LISTENER_READY, GOTD_PROC_GOTD, -1, NULL, 0) == -1) fatal("imsg compose LISTENER_READY"); event_dispatch(); listen_shutdown(); } static void listen_shutdown(void) { log_debug("%s: shutting down", gotd_listen.title); free(gotd_listen.connection_limits); if (gotd_listen.fd != -1) close(gotd_listen.fd); exit(0); } got-portable-0.119/gotd/auth.h0000664000175000017500000000147015066535721011671 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void auth_main(const char *); got-portable-0.119/gotd/secrets.h0000664000175000017500000000242315066535721012377 /* * Copyright (c) 2024 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum gotd_secret_type { GOTD_SECRET_AUTH, GOTD_SECRET_HMAC, }; struct gotd_secret { enum gotd_secret_type type; char *label; char *user; char *pass; char *hmac; }; struct gotd_secrets { struct gotd_secret *secrets; size_t len; size_t cap; }; const struct got_error *gotd_secrets_parse(const char *, FILE *, struct gotd_secrets **); struct gotd_secret *gotd_secrets_get(struct gotd_secrets *, enum gotd_secret_type, const char *); void gotd_secrets_free(struct gotd_secrets *); got-portable-0.119/gotd/session_read.c0000664000175000017500000006055015066536113013401 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_opentemp.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_gitproto.h" #include "gotd.h" #include "log.h" #include "session_read.h" enum gotd_session_read_state { GOTD_STATE_EXPECT_LIST_REFS, GOTD_STATE_EXPECT_CAPABILITIES, GOTD_STATE_EXPECT_WANT, GOTD_STATE_EXPECT_HAVE_OR_DONE, GOTD_STATE_DONE, }; static struct gotd_session_read { pid_t pid; const char *title; struct got_repository *repo; int *pack_fds; int *temp_fds; struct gotd_imsgev parent_iev; struct gotd_imsgev notifier_iev; struct timeval request_timeout; enum gotd_session_read_state state; struct gotd_imsgev repo_child_iev; int repo_child_packfd; } gotd_session; static struct gotd_session_client { struct gotd_client_capability *capabilities; size_t ncapa_alloc; size_t ncapabilities; uint32_t id; int fd; int delta_cache_fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; char *packfile_path; char *packidx_path; int nref_updates; int accept_flush_pkt; int flush_disconnect; } gotd_session_client; static void session_read_shutdown(void); static void disconnect(struct gotd_session_client *client) { log_debug("uid %d: disconnecting", client->euid); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_DISCONNECT, GOTD_PROC_SESSION_READ, -1, NULL, 0) == -1) log_warn("imsg compose DISCONNECT"); imsgbuf_clear(&gotd_session.repo_child_iev.ibuf); event_del(&gotd_session.repo_child_iev.ev); evtimer_del(&client->tmo); close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->packfile_path) { if (unlink(client->packfile_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packfile_path); free(client->packfile_path); } if (client->packidx_path) { if (unlink(client->packidx_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packidx_path); free(client->packidx_path); } free(client->capabilities); session_read_shutdown(); } static void disconnect_on_error(struct gotd_session_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); if (imsgbuf_init(&ibuf, client->fd) == -1) { log_warn("imsgbuf_init"); } else { gotd_imsg_send_error(&ibuf, 0, GOTD_PROC_SESSION_READ, err); imsgbuf_clear(&ibuf); } } disconnect(client); } static void gotd_request_timeout(int fd, short events, void *arg) { struct gotd_session_client *client = arg; log_warnx("disconnecting uid %d due to timeout", client->euid); disconnect(client); } static void session_read_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: session_read_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static const struct got_error * recv_packfile_done(struct imsg *imsg) { size_t datalen; log_debug("packfile-done received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); return NULL; } static void session_dispatch_repo_child(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_PACKFILE_DONE: do_disconnect = 1; err = recv_packfile_done(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else { if (err) log_warnx("uid %d: %s", client->euid, err->msg); } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_capabilities(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capabilities icapas; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(icapas)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapas, imsg->data, sizeof(icapas)); client->ncapa_alloc = icapas.ncapabilities; client->capabilities = calloc(client->ncapa_alloc, sizeof(*client->capabilities)); if (client->capabilities == NULL) { client->ncapa_alloc = 0; return got_error_from_errno("calloc"); } log_debug("expecting %zu capabilities from uid %d", client->ncapa_alloc, client->euid); return NULL; } static const struct got_error * recv_capability(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capability icapa; struct gotd_client_capability *capa; size_t datalen; char *key, *value = NULL; if (client->capabilities == NULL || client->ncapabilities >= client->ncapa_alloc) { return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); } memset(&icapa, 0, sizeof(icapa)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icapa)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapa, imsg->data, sizeof(icapa)); if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len) return got_error(GOT_ERR_PRIVSEP_LEN); key = strndup(imsg->data + sizeof(icapa), icapa.key_len); if (key == NULL) return got_error_from_errno("strndup"); if (icapa.value_len > 0) { value = strndup(imsg->data + sizeof(icapa) + icapa.key_len, icapa.value_len); if (value == NULL) { free(key); return got_error_from_errno("strndup"); } } capa = &client->capabilities[client->ncapabilities++]; capa->key = key; capa->value = value; if (value) log_debug("uid %d: capability %s=%s", client->euid, key, value); else log_debug("uid %d: capability %s", client->euid, key); return NULL; } static const struct got_error * forward_want(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_want ireq; struct gotd_imsg_want iwant; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); memset(&iwant, 0, sizeof(iwant)); memcpy(iwant.object_id, ireq.object_id, SHA1_DIGEST_LENGTH); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_WANT, GOTD_PROC_SESSION_READ, -1, &iwant, sizeof(iwant)) == -1) return got_error_from_errno("imsg compose WANT"); return NULL; } static const struct got_error * forward_have(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_have ireq; struct gotd_imsg_have ihave; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, datalen); memset(&ihave, 0, sizeof(ihave)); memcpy(ihave.object_id, ireq.object_id, SHA1_DIGEST_LENGTH); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_HAVE, GOTD_PROC_SESSION_READ, -1, &ihave, sizeof(ihave)) == -1) return got_error_from_errno("imsg compose HAVE"); return NULL; } static int client_has_capability(struct gotd_session_client *client, const char *capastr) { struct gotd_client_capability *capa; size_t i; if (client->ncapabilities == 0) return 0; for (i = 0; i < client->ncapabilities; i++) { capa = &client->capabilities[i]; if (strcmp(capa->key, capastr) == 0) return 1; } return 0; } static const struct got_error * send_packfile(struct gotd_session_client *client) { const struct got_error *err = NULL; struct gotd_imsg_send_packfile ipack; int pipe[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); memset(&ipack, 0, sizeof(ipack)); if (client_has_capability(client, GOT_CAPA_SIDE_BAND_64K)) ipack.report_progress = 1; client->delta_cache_fd = got_opentempfd(); if (client->delta_cache_fd == -1) return got_error_from_errno("got_opentempfd"); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_SEND_PACKFILE, GOTD_PROC_GOTD, client->delta_cache_fd, &ipack, sizeof(ipack)) == -1) { err = got_error_from_errno("imsg compose SEND_PACKFILE"); close(pipe[0]); close(pipe[1]); close(client->delta_cache_fd); client->delta_cache_fd = -1; return err; } /* * Send pack data pipe end 0 to gotsh(1) (expects just an fd, no data). * * We will forward the other pipe end to the repo_read process only * once we have confirmation that gotsh(1) has received its end. * It is important that we send a pipe end to gotsh(1) before the * repo_read process starts sending pack progress messages via imsg * to prevent spurious "unexpected privsep message" errors from gotsh. */ if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_PACKFILE_PIPE, GOTD_PROC_GOTD, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKFILE_PIPE"); close(pipe[0]); close(pipe[1]); return err; } gotd_session.repo_child_packfd = pipe[1]; return NULL; } static void session_dispatch_client(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; if (events & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { disconnect_on_error(client, err); return; } if (client->flush_disconnect) { disconnect(client); return; } } if (events & EV_READ) { n = imsgbuf_read(ibuf); if (n == -1) { err = got_error_from_errno("imsgbuf_read"); disconnect_on_error(client, err); return; } if (n == 0) { err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } while (err == NULL) { n = imsg_get(ibuf, &imsg); if (n == -1) { err = got_error_from_errno("imsg_get"); break; } if (n == 0) break; evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_CAPABILITIES: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capabilities received"); break; } log_debug("receiving capabilities from uid %d", client->euid); err = recv_capabilities(client, &imsg); break; case GOTD_IMSG_CAPABILITY: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); break; } err = recv_capability(client, &imsg); if (err || client->ncapabilities < client->ncapa_alloc) break; gotd_session.state = GOTD_STATE_EXPECT_WANT; client->accept_flush_pkt = 1; log_debug("uid %d: expecting want-lines", client->euid); break; case GOTD_IMSG_WANT: if (gotd_session.state != GOTD_STATE_EXPECT_WANT) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected want-line received"); break; } log_debug("received want-line from uid %d", client->euid); client->accept_flush_pkt = 1; err = forward_want(client, &imsg); break; case GOTD_IMSG_HAVE: if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected have-line received"); break; } log_debug("received have-line from uid %d", client->euid); err = forward_have(client, &imsg); if (err) break; client->accept_flush_pkt = 1; break; case GOTD_IMSG_FLUSH: if (gotd_session.state != GOTD_STATE_EXPECT_WANT && gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } if (!client->accept_flush_pkt) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } /* * Accept just one flush packet at a time. * Future client state transitions will set this flag * again if another flush packet is expected. */ client->accept_flush_pkt = 0; log_debug("received flush-pkt from uid %d", client->euid); if (gotd_session.state == GOTD_STATE_EXPECT_WANT) { gotd_session.state = GOTD_STATE_EXPECT_HAVE_OR_DONE; log_debug("uid %d: expecting have-lines " "or 'done'", client->euid); } else if (gotd_session.state == GOTD_STATE_EXPECT_HAVE_OR_DONE) { client->accept_flush_pkt = 1; log_debug("uid %d: expecting more have-lines " "or 'done'", client->euid); } else if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { /* should not happen, see above */ err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected client state"); break; } break; case GOTD_IMSG_DONE: if (gotd_session.state != GOTD_STATE_EXPECT_HAVE_OR_DONE) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } log_debug("received 'done' from uid %d", client->euid); gotd_session.state = GOTD_STATE_DONE; client->accept_flush_pkt = 1; err = send_packfile(client); break; case GOTD_IMSG_PACKFILE_READY: if (gotd_session.repo_child_packfd == -1) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } /* * gotsh(1) has received its send of the pack pipe. * Send pack pipe end 1 to repo child process. */ if (gotd_imsg_compose_event( &gotd_session.repo_child_iev, GOTD_IMSG_PACKFILE_PIPE, GOTD_PROC_GOTD, gotd_session.repo_child_packfd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose " "PACKFILE_PIPE"); } else gotd_session.repo_child_packfd = -1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { if (err->code != GOT_ERR_EOF) disconnect_on_error(client, err); } else { gotd_imsg_event_add(iev); evtimer_add(&client->tmo, &gotd_session.request_timeout); } } static const struct got_error * list_refs_request(void) { static const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL, GOTD_PROC_SESSION_READ, fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL"); close(fd); return err; } gotd_session.state = GOTD_STATE_EXPECT_CAPABILITIES; log_debug("uid %d: expecting capabilities", client->euid); return NULL; } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_session_client *client = &gotd_session_client; struct gotd_imsg_connect iconnect; size_t datalen; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); if (iconnect.username_len == 0 || datalen != sizeof(iconnect) + iconnect.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); client->euid = iconnect.euid; client->egid = iconnect.egid; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->username = strndup(imsg->data + sizeof(iconnect), iconnect.username_len); if (client->username == NULL) return got_error_from_errno("strndup"); if (imsgbuf_init(&client->iev.ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&client->iev.ibuf); client->iev.handler = session_dispatch_client; client->iev.events = EV_READ; client->iev.handler_arg = NULL; event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ, session_dispatch_client, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_request_timeout, client); evtimer_add(&client->tmo, &gotd_session.request_timeout); return NULL; } static const struct got_error * recv_repo_child(struct imsg *imsg) { struct gotd_imsg_connect_repo_child ichild; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ichild)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ichild, imsg->data, sizeof(ichild)); if (ichild.proc_id != GOTD_PROC_REPO_READ) return got_error_msg(GOT_ERR_PRIVSEP_MSG, "bad child process type"); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (imsgbuf_init(&gotd_session.repo_child_iev.ibuf, fd)) { close(fd); return got_error_from_errno("imsgbuf_init"); } imsgbuf_allow_fdpass(&gotd_session.repo_child_iev.ibuf); gotd_session.repo_child_iev.handler = session_dispatch_repo_child; gotd_session.repo_child_iev.events = EV_READ; gotd_session.repo_child_iev.handler_arg = NULL; event_set(&gotd_session.repo_child_iev.ev, gotd_session.repo_child_iev.ibuf.fd, EV_READ, session_dispatch_repo_child, &gotd_session.repo_child_iev); gotd_imsg_event_add(&gotd_session.repo_child_iev); /* The "recvfd" pledge promise is no longer needed. */ if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1) fatal("pledge"); return NULL; } static void session_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_list_refs = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CONNECT: err = recv_connect(&imsg); break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; case GOTD_IMSG_REQUEST_TIMEOUT: if (imsg_get_data(&imsg, &gotd_session.request_timeout, sizeof(gotd_session.request_timeout)) == -1) err = got_error_from_errno("imsg_get_data"); break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_repo_child(&imsg); if (err) break; do_list_refs = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else if (do_list_refs) err = list_refs_request(); if (err) log_warnx("uid %d: %s", client->euid, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void session_read_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; gotd_session.title = title; gotd_session.pid = getpid(); gotd_session.pack_fds = pack_fds; gotd_session.temp_fds = temp_fds; gotd_session.request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd_session.request_timeout.tv_usec = 0; gotd_session.repo_child_packfd = -1; if (imsgbuf_init(&gotd_session.notifier_iev.ibuf, -1) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&gotd_session.notifier_iev.ibuf); err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(gotd_session.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } if (got_repo_get_object_format(gotd_session.repo) != GOT_HASH_SHA1) { err = got_error_msg(GOT_ERR_NOT_IMPL, "sha256 object IDs unsupported in network protocol"); goto done; } got_repo_temp_fds_set(gotd_session.repo, temp_fds); signal_set(&evsigint, SIGINT, session_read_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, session_read_sighdlr, NULL); signal_set(&evsighup, SIGHUP, session_read_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, session_read_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); gotd_session.state = GOTD_STATE_EXPECT_LIST_REFS; gotd_session_client.fd = -1; gotd_session_client.nref_updates = -1; gotd_session_client.delta_cache_fd = -1; gotd_session_client.accept_flush_pkt = 1; if (imsgbuf_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&gotd_session.parent_iev.ibuf); gotd_session.parent_iev.handler = session_dispatch; gotd_session.parent_iev.events = EV_READ; gotd_session.parent_iev.handler_arg = NULL; event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd, EV_READ, session_dispatch, &gotd_session.parent_iev); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_CLIENT_SESSION_READY, GOTD_PROC_SESSION_READ, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose CLIENT_SESSION_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); session_read_shutdown(); } static void session_read_shutdown(void) { log_debug("%s: shutting down", gotd_session.title); if (gotd_session.repo) got_repo_close(gotd_session.repo); got_repo_pack_fds_close(gotd_session.pack_fds); got_repo_temp_fds_close(gotd_session.temp_fds); free(gotd_session_client.username); if (gotd_session.repo_child_packfd != -1) close(gotd_session.repo_child_packfd); exit(0); } got-portable-0.119/gotd/chroot-openbsd.c0000664000175000017500000000155715066536113013653 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" int enter_chroot(const char *path) { (void)path; return 0; } got-portable-0.119/gotd/repo_write.c0000664000175000017500000022247115066536113013104 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buf.h" #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_reference.h" #include "got_path.h" #include "got_diff.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_opentemp.h" #include "got_lib_delta.h" #include "got_lib_delta_cache.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_object_idset.h" #include "got_lib_object_parse.h" #include "got_lib_ratelimit.h" #include "got_lib_pack.h" #include "got_lib_pack_index.h" #include "got_lib_repository.h" #include "got_lib_poll.h" #include "log.h" #include "gotd.h" #include "repo_write.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct repo_write { pid_t pid; const char *title; struct got_repository *repo; int *pack_fds; int *temp_fds; FILE *base_file; FILE *accum_file; int session_fd; struct gotd_imsgev session_iev; struct got_pathlist_head protected_tag_namespaces; struct got_pathlist_head protected_branch_namespaces; struct got_pathlist_head protected_branches; struct { FILE *f1; FILE *f2; int fd1; int fd2; } diff; int refs_listed; int have_packfile; struct got_pathlist_head *protected_refs_cur; size_t nprotected_refs_needed; size_t nprotected_refs_received; } repo_write; struct gotd_ref_update { STAILQ_ENTRY(gotd_ref_update) entry; struct got_reference *ref; int ref_is_new; int delete_ref; struct got_object_id old_id; struct got_object_id new_id; }; STAILQ_HEAD(gotd_ref_updates, gotd_ref_update); static struct repo_write_client { uint32_t id; int fd; int pack_pipe; struct got_pack pack; struct got_packidx *packidx; uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; int packidx_fd; struct gotd_ref_updates ref_updates; int nref_updates; int nref_del; int nref_new; int nref_move; } repo_write_client; static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigterm_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigterm(int signo) { sigterm_received = 1; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigterm_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * send_peeled_tag_ref(struct got_reference *ref, struct got_object *obj, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct got_tag_object *tag; size_t namelen, len; char *peeled_refname = NULL; struct got_object_id *id; struct ibuf *wbuf; err = got_object_tag_open(&tag, repo_write.repo, obj); if (err) return err; if (asprintf(&peeled_refname, "%s^{}", got_ref_get_name(ref)) == -1) { err = got_error_from_errno("asprintf"); goto done; } id = got_object_tag_get_object_id(tag); namelen = strlen(peeled_refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_REF, GOTD_PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, peeled_refname, namelen) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } imsg_close(ibuf, wbuf); done: got_object_tag_close(tag); return err; } static const struct got_error * send_ref(struct got_reference *ref, struct imsgbuf *ibuf) { const struct got_error *err; const char *refname = got_ref_get_name(ref); size_t namelen; struct got_object_id *id = NULL; struct got_object *obj = NULL; size_t len; struct ibuf *wbuf; namelen = strlen(refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); err = got_ref_resolve(&id, repo_write.repo, ref); if (err) return err; wbuf = imsg_create(ibuf, GOTD_IMSG_REF, GOTD_PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, refname, namelen) == -1) return got_error_from_errno("imsg_add REF"); imsg_close(ibuf, wbuf); err = got_object_open(&obj, repo_write.repo, id); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) err = send_peeled_tag_ref(ref, obj, ibuf); done: if (obj) got_object_close(obj); free(id); return err; } static const struct got_error * list_refs(struct imsg *imsg) { const struct got_error *err; struct repo_write_client *client = &repo_write_client; struct got_reflist_head refs; struct got_reflist_entry *re; size_t datalen; struct gotd_imsg_reflist irefs; struct imsgbuf ibuf; TAILQ_INIT(&refs); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_write.refs_listed) { return got_error_msg(GOT_ERR_CLIENT_ID, "duplicate list-refs request"); } repo_write.refs_listed = 1; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->nref_updates = 0; client->nref_del = 0; client->nref_new = 0; client->nref_move = 0; if (imsgbuf_init(&ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); err = got_ref_list(&refs, repo_write.repo, "", got_ref_cmp_by_name, NULL); if (err) return err; memset(&irefs, 0, sizeof(irefs)); TAILQ_FOREACH(re, &refs, entry) { struct got_object_id *id; int obj_type; if (got_ref_is_symbolic(re->ref)) continue; irefs.nrefs++; /* Account for a peeled tag refs. */ err = got_ref_resolve(&id, repo_write.repo, re->ref); if (err) goto done; err = got_object_get_type(&obj_type, repo_write.repo, id); free(id); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_TAG) irefs.nrefs++; } if (imsg_compose(&ibuf, GOTD_IMSG_REFLIST, GOTD_PROC_REPO_WRITE, repo_write.pid, -1, &irefs, sizeof(irefs)) == -1) { err = got_error_from_errno("imsg_compose REFLIST"); goto done; } TAILQ_FOREACH(re, &refs, entry) { if (got_ref_is_symbolic(re->ref)) continue; err = send_ref(re->ref, &ibuf); if (err) goto done; } err = gotd_imsg_flush(&ibuf); done: got_ref_list_free(&refs); imsgbuf_clear(&ibuf); return err; } static const struct got_error * validate_namespace(const char *namespace) { size_t len = strlen(namespace); if (len < 5 || strncmp("refs/", namespace, 5) != 0 || namespace[len -1] != '/') { return got_error_fmt(GOT_ERR_BAD_REF_NAME, "reference namespace '%s'", namespace); } return NULL; } static const struct got_error * protect_ref_namespace(const char *refname, const char *namespace) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, refname, strlen(namespace)) == 0) return got_error_fmt(GOT_ERR_REFS_PROTECTED, "%s", namespace); return NULL; } static const struct got_error * verify_object_type(struct got_object_id *id, int expected_obj_type, struct got_pack *pack, struct got_packidx *packidx) { const struct got_error *err; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object *obj; int idx; const char *typestr; idx = got_packidx_get_object_idx(packidx, id); if (idx == -1) { got_object_id_hex(id, hex, sizeof(hex)); return got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); } err = got_object_open_from_packfile(&obj, id, pack, packidx, idx, repo_write.repo); if (err) return err; if (obj->type != expected_obj_type) { got_object_id_hex(id, hex, sizeof(hex)); got_object_type_label(&typestr, expected_obj_type); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a %s object", hex, typestr); } got_object_close(obj); return err; } static const struct got_error * protect_tag_namespace(const char *namespace, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref_update->ref), strlen(namespace)) != 0) return NULL; if (!ref_update->ref_is_new) return got_error_fmt(GOT_ERR_REFS_PROTECTED, "%s", namespace); return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_TAG, pack, packidx); } static const struct got_error * protect_require_yca(struct got_object_id *tip_id, size_t max_commits_to_traverse, struct got_pack *pack, struct got_packidx *packidx, struct got_reference *ref) { const struct got_error *err; uint8_t *buf = NULL; size_t len; struct got_object_id *expected_yca_id = NULL; struct got_object *obj = NULL; struct got_commit_object *commit = NULL; char hex[SHA1_DIGEST_STRING_LENGTH]; const struct got_object_id_queue *parent_ids; struct got_object_id_queue ids; struct got_object_qid *pid, *qid; struct got_object_idset *traversed_set = NULL; int found_yca = 0, obj_type; STAILQ_INIT(&ids); err = got_ref_resolve(&expected_yca_id, repo_write.repo, ref); if (err) return err; err = got_object_get_type(&obj_type, repo_write.repo, expected_yca_id); if (err) goto done; if (obj_type != GOT_OBJ_TYPE_COMMIT) { got_object_id_hex(expected_yca_id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a commit object", hex); goto done; } traversed_set = got_object_idset_alloc(); if (traversed_set == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } err = got_object_qid_alloc(&qid, tip_id); if (err) goto done; STAILQ_INSERT_TAIL(&ids, qid, entry); while (!STAILQ_EMPTY(&ids)) { err = check_cancelled(NULL); if (err) break; qid = STAILQ_FIRST(&ids); if (got_object_id_cmp(&qid->id, expected_yca_id) == 0) { found_yca = 1; break; } if (max_commits_to_traverse > 0 && got_object_idset_num_elements(traversed_set) >= max_commits_to_traverse) break; if (got_object_idset_contains(traversed_set, &qid->id)) { STAILQ_REMOVE_HEAD(&ids, entry); got_object_qid_free(qid); qid = NULL; continue; } err = got_object_idset_add(traversed_set, &qid->id, NULL); if (err) goto done; err = got_object_open(&obj, repo_write.repo, &qid->id); if (err && err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; if (obj) { err = got_object_commit_open(&commit, repo_write.repo, obj); if (err) goto done; } else { int idx; idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx == -1) { got_object_id_hex(&qid->id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); goto done; } err = got_object_open_from_packfile(&obj, &qid->id, pack, packidx, idx, repo_write.repo); if (err) goto done; if (obj->type != GOT_OBJ_TYPE_COMMIT) { got_object_id_hex(&qid->id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_OBJ_TYPE, "%s is not pointing at a commit object", hex); goto done; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; err = got_object_parse_commit(&commit, buf, len, GOT_HASH_SHA1); if (err) goto done; free(buf); buf = NULL; } got_object_close(obj); obj = NULL; STAILQ_REMOVE_HEAD(&ids, entry); got_object_qid_free(qid); qid = NULL; if (got_object_commit_get_nparents(commit) == 0) break; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(pid, parent_ids, entry) { err = check_cancelled(NULL); if (err) goto done; err = got_object_qid_alloc(&qid, &pid->id); if (err) goto done; STAILQ_INSERT_TAIL(&ids, qid, entry); qid = NULL; } got_object_commit_close(commit); commit = NULL; } if (!found_yca) { err = got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", got_ref_get_name(ref)); } done: got_object_idset_free(traversed_set); got_object_id_queue_free(&ids); free(buf); if (obj) got_object_close(obj); if (commit) got_object_commit_close(commit); free(expected_yca_id); return err; } static const struct got_error * protect_branch_namespace(const char *namespace, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { const struct got_error *err; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref_update->ref), strlen(namespace)) != 0) return NULL; if (ref_update->ref_is_new) { return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_COMMIT, pack, packidx); } return protect_require_yca(&ref_update->new_id, be32toh(packidx->hdr.fanout_table[0xff]), pack, packidx, ref_update->ref); } static const struct got_error * protect_branch(const char *refname, struct got_pack *pack, struct got_packidx *packidx, struct gotd_ref_update *ref_update) { if (strcmp(refname, got_ref_get_name(ref_update->ref)) != 0) return NULL; /* Always allow new branches to be created. */ if (ref_update->ref_is_new) { return verify_object_type(&ref_update->new_id, GOT_OBJ_TYPE_COMMIT, pack, packidx); } return protect_require_yca(&ref_update->new_id, be32toh(packidx->hdr.fanout_table[0xff]), pack, packidx, ref_update->ref); } static const struct got_error * recv_ref_update(struct imsg *imsg) { static const char zero_id[SHA1_DIGEST_LENGTH]; const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_ref_update iref; size_t datalen; char *refname = NULL; struct got_reference *ref = NULL; struct got_object_id *id = NULL; struct imsgbuf ibuf; struct gotd_ref_update *ref_update = NULL; log_debug("ref-update received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); if (datalen != sizeof(iref) + iref.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (imsgbuf_init(&ibuf, client->fd)) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); refname = strndup(imsg->data + sizeof(iref), iref.name_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } ref_update = calloc(1, sizeof(*ref_update)); if (ref_update == NULL) { err = got_error_from_errno("malloc"); goto done; } memcpy(ref_update->old_id.hash, iref.old_id, SHA1_DIGEST_LENGTH); memcpy(ref_update->new_id.hash, iref.new_id, SHA1_DIGEST_LENGTH); err = got_ref_open(&ref, repo_write.repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; if (memcmp(ref_update->new_id.hash, zero_id, sizeof(zero_id)) == 0) { err = got_error_fmt(GOT_ERR_BAD_OBJ_ID, "%s", refname); goto done; } err = got_ref_alloc(&ref, refname, &ref_update->new_id); if (err) goto done; ref_update->ref_is_new = 1; client->nref_new++; } if (got_ref_is_symbolic(ref)) { err = got_error_fmt(GOT_ERR_BAD_REF_TYPE, "'%s' is a symbolic reference and cannot " "be updated", got_ref_get_name(ref)); goto done; } if (strncmp("refs/", got_ref_get_name(ref), 5) != 0) { err = got_error_fmt(GOT_ERR_BAD_REF_NAME, "%s: does not begin with 'refs/'", got_ref_get_name(ref)); goto done; } err = protect_ref_namespace(got_ref_get_name(ref), "refs/got/"); if (err) goto done; err = protect_ref_namespace(got_ref_get_name(ref), "refs/remotes/"); if (err) goto done; if (!ref_update->ref_is_new) { /* * Ensure the client's idea of this update is still valid. * At this point we can only return an error, to prevent * the client from uploading a pack file which will likely * have to be discarded. */ err = got_ref_resolve(&id, repo_write.repo, ref); if (err) goto done; if (got_object_id_cmp(id, &ref_update->old_id) != 0) { err = got_error_fmt(GOT_ERR_REF_BUSY, "%s has been modified by someone else " "while transaction was in progress", got_ref_get_name(ref)); goto done; } } gotd_imsg_send_ack(&ref_update->new_id, &ibuf, GOTD_PROC_REPO_WRITE, repo_write.pid); ref_update->ref = ref; if (memcmp(ref_update->new_id.hash, zero_id, sizeof(zero_id)) == 0) { ref_update->delete_ref = 1; client->nref_del++; } STAILQ_INSERT_HEAD(&client->ref_updates, ref_update, entry); client->nref_updates++; ref = NULL; ref_update = NULL; done: if (ref) got_ref_close(ref); free(ref_update); free(refname); free(id); return err; } static const struct got_error * pack_index_progress(void *arg, uint32_t nobj_total, uint32_t nobj_indexed, uint32_t nobj_loose, uint32_t nobj_resolved) { int p_indexed = 0, p_resolved = 0; int nobj_delta = nobj_total - nobj_loose; if (nobj_total > 0) p_indexed = (nobj_indexed * 100) / nobj_total; if (nobj_delta > 0) p_resolved = (nobj_resolved * 100) / nobj_delta; if (p_resolved > 0) { log_debug("indexing %d objects %d%%; resolving %d deltas %d%%", nobj_total, p_indexed, nobj_delta, p_resolved); } else log_debug("indexing %d objects %d%%", nobj_total, p_indexed); return NULL; } static const struct got_error * read_more_pack_stream(int infd, BUF *buf, size_t minsize) { const struct got_error *err = NULL; uint8_t readahead[65536]; size_t have, newlen; err = got_poll_read_full(infd, &have, readahead, sizeof(readahead), minsize); if (err) return err; err = buf_append(&newlen, buf, readahead, have); if (err) return err; return NULL; } static const struct got_error * copy_object_type_and_size(uint8_t *type, uint64_t *size, int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; uint8_t t = 0; uint64_t s = 0; uint8_t sizebuf[8]; size_t i = 0; off_t obj_offset = *outsize; do { /* We do not support size values which don't fit in 64 bit. */ if (i > 9) return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE, "packfile offset %lld", (long long)obj_offset); if (buf_len(buf) - *buf_pos < sizeof(sizebuf[0])) { err = read_more_pack_stream(infd, buf, sizeof(sizebuf[0])); if (err) return err; } sizebuf[i] = buf_getc(buf, *buf_pos); *buf_pos += sizeof(sizebuf[i]); if (i == 0) { t = (sizebuf[i] & GOT_PACK_OBJ_SIZE0_TYPE_MASK) >> GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT; s = (sizebuf[i] & GOT_PACK_OBJ_SIZE0_VAL_MASK); } else { size_t shift = 4 + 7 * (i - 1); s |= ((sizebuf[i] & GOT_PACK_OBJ_SIZE_VAL_MASK) << shift); } i++; } while (sizebuf[i - 1] & GOT_PACK_OBJ_SIZE_MORE); err = got_pack_hwrite(outfd, sizebuf, i, ctx); if (err) return err; *outsize += i; *type = t; *size = s; return NULL; } static const struct got_error * copy_ref_delta(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; size_t remain = buf_len(buf) - *buf_pos; if (remain < SHA1_DIGEST_LENGTH) { err = read_more_pack_stream(infd, buf, SHA1_DIGEST_LENGTH - remain); if (err) return err; } err = got_pack_hwrite(outfd, buf_get(buf) + *buf_pos, SHA1_DIGEST_LENGTH, ctx); if (err) return err; *buf_pos += SHA1_DIGEST_LENGTH; *outsize += SHA1_DIGEST_LENGTH; return NULL; } static const struct got_error * copy_offset_delta(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; uint64_t o = 0; uint8_t offbuf[8]; size_t i = 0; off_t obj_offset = *outsize; do { /* We do not support offset values which don't fit in 64 bit. */ if (i > 8) return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE, "packfile offset %lld", (long long)obj_offset); if (buf_len(buf) - *buf_pos < sizeof(offbuf[0])) { err = read_more_pack_stream(infd, buf, sizeof(offbuf[0])); if (err) return err; } offbuf[i] = buf_getc(buf, *buf_pos); *buf_pos += sizeof(offbuf[i]); if (i == 0) o = (offbuf[i] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); else { o++; o <<= 7; o += (offbuf[i] & GOT_PACK_OBJ_DELTA_OFF_VAL_MASK); } i++; } while (offbuf[i - 1] & GOT_PACK_OBJ_DELTA_OFF_MORE); if (o < sizeof(struct got_packfile_hdr) || o > *outsize) return got_error(GOT_ERR_PACK_OFFSET); err = got_pack_hwrite(outfd, offbuf, i, ctx); if (err) return err; *outsize += i; return NULL; } static const struct got_error * copy_zstream(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos, struct got_hash *ctx) { const struct got_error *err = NULL; z_stream z; int zret; char voidbuf[1024]; size_t consumed_total = 0; off_t zstream_offset = *outsize; memset(&z, 0, sizeof(z)); z.zalloc = Z_NULL; z.zfree = Z_NULL; zret = inflateInit(&z); if (zret != Z_OK) { if (zret == Z_ERRNO) return got_error_from_errno("inflateInit"); if (zret == Z_MEM_ERROR) { errno = ENOMEM; return got_error_from_errno("inflateInit"); } return got_error_msg(GOT_ERR_DECOMPRESSION, "inflateInit failed"); } while (zret != Z_STREAM_END) { size_t last_total_in, consumed; /* * Decompress into the void. Object data will be parsed * later, when the pack file is indexed. For now, we just * want to locate the end of the compressed stream. */ while (zret != Z_STREAM_END && buf_len(buf) - *buf_pos > 0) { last_total_in = z.total_in; z.next_in = buf_get(buf) + *buf_pos; z.avail_in = buf_len(buf) - *buf_pos; z.next_out = voidbuf; z.avail_out = sizeof(voidbuf); zret = inflate(&z, Z_SYNC_FLUSH); if (zret != Z_OK && zret != Z_BUF_ERROR && zret != Z_STREAM_END) { err = got_error_fmt(GOT_ERR_DECOMPRESSION, "packfile offset %lld", (long long)zstream_offset); goto done; } consumed = z.total_in - last_total_in; err = got_pack_hwrite(outfd, buf_get(buf) + *buf_pos, consumed, ctx); if (err) goto done; err = buf_discard(buf, *buf_pos + consumed); if (err) goto done; *buf_pos = 0; consumed_total += consumed; } if (zret != Z_STREAM_END) { err = read_more_pack_stream(infd, buf, 1); if (err) goto done; } } if (err == NULL) *outsize += consumed_total; done: inflateEnd(&z); return err; } static const struct got_error * validate_object_type(int obj_type) { switch (obj_type) { case GOT_OBJ_TYPE_BLOB: case GOT_OBJ_TYPE_COMMIT: case GOT_OBJ_TYPE_TREE: case GOT_OBJ_TYPE_TAG: case GOT_OBJ_TYPE_REF_DELTA: case GOT_OBJ_TYPE_OFFSET_DELTA: return NULL; default: break; } return got_error(GOT_ERR_OBJ_TYPE); } static const struct got_error * ensure_all_objects_exist_locally(struct gotd_ref_updates *ref_updates) { const struct got_error *err = NULL; struct gotd_ref_update *ref_update; struct got_object *obj; STAILQ_FOREACH(ref_update, ref_updates, entry) { err = got_object_open(&obj, repo_write.repo, &ref_update->new_id); if (err) return err; got_object_close(obj); } return NULL; } static const struct got_error * recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t *sha1, int infd, int outfd) { const struct got_error *err; struct repo_write_client *client = &repo_write_client; struct got_packfile_hdr hdr; size_t have; uint32_t nhave = 0; struct got_hash ctx; uint8_t expected_sha1[SHA1_DIGEST_LENGTH]; char hex[SHA1_DIGEST_STRING_LENGTH]; BUF *buf = NULL; size_t buf_pos = 0, remain; ssize_t w; *outsize = 0; *nobj = 0; /* if only deleting references there's nothing to read */ if (client->nref_updates == client->nref_del) return NULL; got_hash_init(&ctx, GOT_HASH_SHA1); err = got_poll_read_full(infd, &have, &hdr, sizeof(hdr), sizeof(hdr)); if (err) return err; if (have != sizeof(hdr)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "short pack file"); *outsize += have; if (hdr.signature != htobe32(GOT_PACKFILE_SIGNATURE)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile signature"); if (hdr.version != htobe32(GOT_PACKFILE_VERSION)) return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile version"); *nobj = be32toh(hdr.nobjects); if (*nobj == 0) { /* * Clients which are creating new references only * will send us an empty pack file. */ if (client->nref_updates > 0 && client->nref_updates == client->nref_new) return NULL; /* * Clients which only move existing refs will send us an empty * pack file. All referenced objects must exist locally. */ err = ensure_all_objects_exist_locally(&client->ref_updates); if (err) { if (err->code != GOT_ERR_NO_OBJ) return err; return got_error_msg(GOT_ERR_BAD_PACKFILE, "bad packfile with zero objects"); } client->nref_move = client->nref_updates; return NULL; } log_debug("expecting %d objects", *nobj); err = got_pack_hwrite(outfd, &hdr, sizeof(hdr), &ctx); if (err) return err; err = buf_alloc(&buf, 65536); if (err) return err; while (nhave != *nobj) { uint8_t obj_type; uint64_t obj_size; err = copy_object_type_and_size(&obj_type, &obj_size, infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; err = validate_object_type(obj_type); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_REF_DELTA) { err = copy_ref_delta(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; } else if (obj_type == GOT_OBJ_TYPE_OFFSET_DELTA) { err = copy_offset_delta(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; } err = copy_zstream(infd, outfd, outsize, buf, &buf_pos, &ctx); if (err) goto done; nhave++; } log_debug("received %u objects", *nobj); got_hash_final(&ctx, expected_sha1); remain = buf_len(buf) - buf_pos; if (remain < SHA1_DIGEST_LENGTH) { err = read_more_pack_stream(infd, buf, SHA1_DIGEST_LENGTH - remain); if (err) return err; } got_sha1_digest_to_str(expected_sha1, hex, sizeof(hex)); log_debug("expect SHA1: %s", hex); got_sha1_digest_to_str(buf_get(buf) + buf_pos, hex, sizeof(hex)); log_debug("actual SHA1: %s", hex); if (memcmp(buf_get(buf) + buf_pos, expected_sha1, SHA1_DIGEST_LENGTH) != 0) { err = got_error(GOT_ERR_PACKFILE_CSUM); goto done; } memcpy(sha1, expected_sha1, SHA1_DIGEST_LENGTH); w = write(outfd, expected_sha1, SHA1_DIGEST_LENGTH); if (w == -1) { err = got_error_from_errno("write"); goto done; } if (w != SHA1_DIGEST_LENGTH) { err = got_error(GOT_ERR_IO); goto done; } *outsize += SHA1_DIGEST_LENGTH; if (fsync(outfd) == -1) { err = got_error_from_errno("fsync"); goto done; } if (lseek(outfd, 0L, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } done: buf_free(buf); return err; } static const struct got_error * report_pack_status(const struct got_error *unpack_err) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_packfile_status istatus; struct ibuf *wbuf; struct imsgbuf ibuf; const char *unpack_ok = "unpack ok\n"; size_t len; if (imsgbuf_init(&ibuf, client->fd)) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); if (unpack_err) istatus.reason_len = strlen(unpack_err->msg); else istatus.reason_len = strlen(unpack_ok); len = sizeof(istatus) + istatus.reason_len; wbuf = imsg_create(&ibuf, GOTD_IMSG_PACKFILE_STATUS, GOTD_PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create PACKFILE_STATUS"); goto done; } if (imsg_add(wbuf, &istatus, sizeof(istatus)) == -1) { err = got_error_from_errno("imsg_add PACKFILE_STATUS"); goto done; } if (imsg_add(wbuf, err ? err->msg : unpack_ok, istatus.reason_len) == -1) { err = got_error_from_errno("imsg_add PACKFILE_STATUS"); goto done; } imsg_close(&ibuf, wbuf); err = gotd_imsg_flush(&ibuf); done: imsgbuf_clear(&ibuf); return err; } static const struct got_error * recv_packfile(int *have_packfile, struct imsg *imsg) { const struct got_error *err = NULL, *unpack_err; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_recv_packfile ireq; struct got_object_id id; FILE *tempfiles[3] = { NULL, NULL, NULL }; struct repo_tempfile { int fd; int idx; } repo_tempfiles[3] = { { - 1, - 1 }, { - 1, - 1 }, { - 1, - 1 }, }; int i; size_t datalen; struct got_ratelimit rl; struct got_pack *pack = NULL; off_t pack_filesize = 0; uint32_t nobj = 0; log_debug("packfile request received"); *have_packfile = 0; got_ratelimit_init(&rl, 2, 0); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (client->pack_pipe == -1 || client->packidx_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); pack = &client->pack; memset(pack, 0, sizeof(*pack)); pack->fd = imsg_get_fd(imsg); if (pack->fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } err = got_delta_cache_alloc(&pack->delta_cache); if (err) goto done; for (i = 0; i < nitems(repo_tempfiles); i++) { struct repo_tempfile *t = &repo_tempfiles[i]; err = got_repo_temp_fds_get(&t->fd, &t->idx, repo_write.repo); if (err) goto done; } for (i = 0; i < nitems(tempfiles); i++) { int fd; FILE *f; fd = dup(repo_tempfiles[i].fd); if (fd == -1) { err = got_error_from_errno("dup"); goto done; } f = fdopen(fd, "w+"); if (f == NULL) { err = got_error_from_errno("fdopen"); close(fd); goto done; } tempfiles[i] = f; } log_debug("receiving pack data"); unpack_err = recv_packdata(&pack_filesize, &nobj, client->pack_sha1, client->pack_pipe, pack->fd); if (ireq.report_status) { err = report_pack_status(unpack_err); if (err) { /* Git clients hang up after sending the pack file. */ if (err->code == GOT_ERR_EOF) err = NULL; } } if (unpack_err) err = unpack_err; if (err) goto done; log_debug("pack data received"); /* * Clients which are creating new references only will * send us an empty pack file. */ if (nobj == 0 && pack_filesize == sizeof(struct got_packfile_hdr) && client->nref_updates > 0 && client->nref_updates == client->nref_new) goto done; /* * Clients which are deleting references only will send * no pack file. */ if (nobj == 0 && client->nref_del > 0 && client->nref_updates == client->nref_del) goto done; /* * Clients which only move existing refs will send us an empty * pack file. All referenced objects must exist locally. */ if (nobj == 0 && pack_filesize == sizeof(struct got_packfile_hdr) && client->nref_move > 0 && client->nref_updates == client->nref_move) goto done; pack->filesize = pack_filesize; *have_packfile = 1; memset(&id, 0, sizeof(id)); memcpy(&id.hash, client->pack_sha1, SHA1_DIGEST_LENGTH); id.algo = GOT_HASH_SHA1; log_debug("begin indexing pack (%lld bytes in size)", (long long)pack->filesize); err = got_pack_index(pack, client->packidx_fd, tempfiles[0], tempfiles[1], tempfiles[2], &id, pack_index_progress, NULL, &rl); if (err) goto done; log_debug("done indexing pack"); if (fsync(client->packidx_fd) == -1) { err = got_error_from_errno("fsync"); goto done; } if (lseek(client->packidx_fd, 0L, SEEK_SET) == -1) err = got_error_from_errno("lseek"); done: if (close(client->pack_pipe) == -1 && err == NULL) err = got_error_from_errno("close"); client->pack_pipe = -1; for (i = 0; i < nitems(repo_tempfiles); i++) { struct repo_tempfile *t = &repo_tempfiles[i]; if (t->idx != -1) got_repo_temp_fds_put(t->idx, repo_write.repo); } for (i = 0; i < nitems(tempfiles); i++) { if (tempfiles[i] && fclose(tempfiles[i]) == EOF && err == NULL) err = got_error_from_errno("fclose"); } if (err) got_pack_close(pack); return err; } static const struct got_error * verify_packfile(void) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; struct stat sb; char *id_str = NULL; struct got_object *obj = NULL; struct got_pathlist_entry *pe; char hex[SHA1_DIGEST_STRING_LENGTH]; if (STAILQ_EMPTY(&client->ref_updates)) { return got_error_msg(GOT_ERR_BAD_REQUEST, "cannot verify pack file without any ref-updates"); } if (client->pack.fd == -1) { return got_error_msg(GOT_ERR_BAD_REQUEST, "invalid pack file handle during pack verification"); } if (client->packidx_fd == -1) { return got_error_msg(GOT_ERR_BAD_REQUEST, "invalid pack index handle during pack verification"); } if (fstat(client->packidx_fd, &sb) == -1) return got_error_from_errno("pack index fstat"); if (client->packidx != NULL) return got_error(GOT_ERR_PRIVSEP_MSG); client->packidx = calloc(1, sizeof(*client->packidx)); if (client->packidx == NULL) return got_error_from_errno("calloc"); client->packidx->fd = client->packidx_fd; client->packidx_fd = -1; client->packidx->len = sb.st_size; err = got_packidx_init_hdr(client->packidx, 1, client->pack.filesize); if (err) return err; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (ref_update->delete_ref) continue; RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_tag_namespaces) { err = protect_tag_namespace(pe->path, &client->pack, client->packidx, ref_update); if (err) goto done; } /* * Objects which already exist in our repository need * not be present in the pack file. */ err = got_object_open(&obj, repo_write.repo, &ref_update->new_id); if (err && err->code != GOT_ERR_NO_OBJ) goto done; err = NULL; if (obj) { got_object_close(obj); obj = NULL; } else { int idx = got_packidx_get_object_idx(client->packidx, &ref_update->new_id); if (idx == -1) { got_object_id_hex(&ref_update->new_id, hex, sizeof(hex)); err = got_error_fmt(GOT_ERR_BAD_PACKFILE, "object %s is missing from pack file", hex); goto done; } } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branch_namespaces) { err = protect_branch_namespace(pe->path, &client->pack, client->packidx, ref_update); if (err) goto done; } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branches) { err = protect_branch(pe->path, &client->pack, client->packidx, ref_update); if (err) goto done; } } done: free(id_str); if (obj) got_object_close(obj); return err; } static const struct got_error * protect_refs_from_deletion(void) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; struct got_pathlist_entry *pe; const char *refname; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (!ref_update->delete_ref) continue; refname = got_ref_get_name(ref_update->ref); RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_tag_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branch_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branches) { if (strcmp(refname, pe->path) == 0) { return got_error_fmt(GOT_ERR_REF_PROTECTED, "%s", refname); } } } return NULL; } static const struct got_error * protect_refs_from_moving(void) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; struct got_pathlist_entry *pe; const char *refname; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (ref_update->delete_ref) continue; if (got_object_id_cmp(&ref_update->old_id, &ref_update->new_id) == 0) continue; refname = got_ref_get_name(ref_update->ref); RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_tag_namespaces) { err = protect_ref_namespace(refname, pe->path); if (err) return err; } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branch_namespaces) { if (strcmp(pe->path, refname) != 0) continue; err = protect_require_yca(&ref_update->new_id, 0, NULL, NULL, ref_update->ref); if (err) return err; break; } RB_FOREACH(pe, got_pathlist_head, &repo_write.protected_branches) { if (strcmp(pe->path, refname) != 0) continue; err = protect_require_yca(&ref_update->new_id, 0, NULL, NULL, ref_update->ref); if (err) return err; break; } } return NULL; } static const struct got_error * install_packfile(struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; struct gotd_imsg_packfile_install inst; int ret; memset(&inst, 0, sizeof(inst)); memcpy(inst.pack_sha1, client->pack_sha1, SHA1_DIGEST_LENGTH); ret = gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_INSTALL, GOTD_PROC_REPO_WRITE, -1, &inst, sizeof(inst)); if (ret == -1) return got_error_from_errno("imsg_compose PACKFILE_INSTALL"); return NULL; } static const struct got_error * send_ref_updates_start(int nref_updates, struct gotd_imsgev *iev) { struct gotd_imsg_ref_updates_start istart; int ret; memset(&istart, 0, sizeof(istart)); istart.nref_updates = nref_updates; ret = gotd_imsg_compose_event(iev, GOTD_IMSG_REF_UPDATES_START, GOTD_PROC_REPO_WRITE, -1, &istart, sizeof(istart)); if (ret == -1) return got_error_from_errno("imsg_compose REF_UPDATES_START"); return NULL; } static const struct got_error * send_ref_update(struct gotd_ref_update *ref_update, struct gotd_imsgev *iev) { struct gotd_imsg_ref_update iref; const char *refname = got_ref_get_name(ref_update->ref); struct ibuf *wbuf; size_t len; memset(&iref, 0, sizeof(iref)); memcpy(iref.old_id, ref_update->old_id.hash, SHA1_DIGEST_LENGTH); memcpy(iref.new_id, ref_update->new_id.hash, SHA1_DIGEST_LENGTH); iref.ref_is_new = ref_update->ref_is_new; iref.delete_ref = ref_update->delete_ref; iref.name_len = strlen(refname); len = sizeof(iref) + iref.name_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE, GOTD_PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE"); if (imsg_add(wbuf, &iref, sizeof(iref)) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); if (imsg_add(wbuf, refname, iref.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * update_refs(struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; err = send_ref_updates_start(client->nref_updates, iev); if (err) return err; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { err = send_ref_update(ref_update, iev); if (err) goto done; } done: return err; } static const struct got_error * receive_pack_pipe(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; size_t datalen; log_debug("receiving pack pipe descriptor"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->pack_pipe != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->pack_pipe = imsg_get_fd(imsg); if (client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * receive_pack_idx(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_write_client *client = &repo_write_client; size_t datalen; log_debug("receiving pack index output file"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->packidx_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->packidx_fd = imsg_get_fd(imsg); if (client->packidx_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * notify_removed_ref(const char *refname, struct got_object_id *id, struct gotd_imsgev *iev, int fd) { const struct got_error *err; char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; dprintf(fd, "Removed %s: %s\n", refname, id_str); free(id_str); return err; } static const char * format_author(char *author) { char *smallerthan; smallerthan = strchr(author, '<'); if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; return author; } static const struct got_error * print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, int fd) { const struct got_error *err = NULL; char *id_str = NULL, *logmsg0 = NULL; char *s, *nl; char *committer = NULL, *author = NULL; time_t committer_time; err = got_object_id_str(&id_str, id); if (err) return err; committer_time = got_object_commit_get_committer_time(commit); err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; s = logmsg0; while (isspace((unsigned char)s[0])) s++; nl = strchr(s, '\n'); if (nl) { *nl = '\0'; } if (strcmp(got_object_commit_get_author(commit), got_object_commit_get_committer(commit)) != 0) { author = strdup(got_object_commit_get_author(commit)); if (author == NULL) { err = got_error_from_errno("strdup"); goto done; } dprintf(fd, "%lld %.7s %.8s %s\n", (long long)committer_time, id_str, format_author(author), s); } else { committer = strdup(got_object_commit_get_committer(commit)); dprintf(fd, "%lld %.7s %.8s %s\n", (long long)committer_time, id_str, format_author(committer), s); } if (fsync(fd) == -1 && err == NULL) err = got_error_from_errno("fsync"); done: free(id_str); free(logmsg0); free(committer); free(author); return err; } static const struct got_error * print_diffstat(struct got_diffstat_cb_arg *dsa, int fd) { struct got_pathlist_entry *pe; RB_FOREACH(pe, got_pathlist_head, dsa->paths) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; dprintf(fd, " %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); } dprintf(fd, "\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); return NULL; } static const struct got_error * print_commit(struct got_commit_object *commit, struct got_object_id *id, struct got_repository *repo, struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *diffstat, int fd) { const struct got_error *err = NULL; char *id_str, *logmsg0, *logmsg, *line; time_t committer_time; const char *author, *committer; err = got_object_id_str(&id_str, id); if (err) return err; dprintf(fd, "commit %s\n", id_str); free(id_str); id_str = NULL; dprintf(fd, "from: %s\n", got_object_commit_get_author(commit)); author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) dprintf(fd, "via: %s\n", committer); committer_time = got_object_commit_get_committer_time(commit); dprintf(fd, "date: %lld\n", (long long)committer_time); if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int n = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; dprintf(fd, "parent %d: %s\n", n++, id_str); free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; dprintf(fd, "messagelen: %zu\n", strlen(logmsg0)); logmsg = logmsg0; do { line = strsep(&logmsg, "\n"); if (line) dprintf(fd, " %s\n", line); } while (line); free(logmsg0); err = print_diffstat(diffstat, fd); if (err) goto done; if (fsync(fd) == -1 && err == NULL) err = got_error_from_errno("fsync"); done: free(id_str); return err; } static const struct got_error * get_changed_paths(struct got_pathlist_head *paths, struct got_commit_object *commit, struct got_repository *repo, struct got_diffstat_cb_arg *dsa) { const struct got_error *err = NULL; struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; struct got_object_qid *qid; got_diff_blob_cb cb = got_diff_tree_collect_changed_paths; FILE *f1 = repo_write.diff.f1, *f2 = repo_write.diff.f2; int fd1 = repo_write.diff.fd1, fd2 = repo_write.diff.fd2; if (dsa) cb = got_diff_tree_compute_diffstat; err = got_opentemp_truncate(f1); if (err) return err; err = got_opentemp_truncate(f2); if (err) return err; err = got_opentemp_truncatefd(fd1); if (err) return err; err = got_opentemp_truncatefd(fd2); if (err) return err; qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (qid != NULL) { struct got_commit_object *pcommit; err = got_object_open_as_commit(&pcommit, repo, &qid->id); if (err) return err; tree_id1 = got_object_id_dup( got_object_commit_get_tree_id(pcommit)); if (tree_id1 == NULL) { got_object_commit_close(pcommit); return got_error_from_errno("got_object_id_dup"); } got_object_commit_close(pcommit); } if (tree_id1) { err = got_object_open_as_tree(&tree1, repo, tree_id1); if (err) goto done; } tree_id2 = got_object_commit_get_tree_id(commit); err = got_object_open_as_tree(&tree2, repo, tree_id2); if (err) goto done; err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo, cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0); done: if (tree1) got_object_tree_close(tree1); if (tree2) got_object_tree_close(tree2); free(tree_id1); return err; } static const struct got_error * print_commits(struct got_object_id *root_id, struct got_object_id *end_id, struct got_repository *repo, int fd) { const struct got_error *err; struct got_commit_graph *graph = NULL; struct got_object_id_queue reversed_commits; struct got_object_qid *qid; struct got_commit_object *commit = NULL; struct got_pathlist_head changed_paths; int ncommits = 0; const int shortlog_threshold = 50; struct got_object_id *yca_id = NULL; struct got_reference *head_ref = NULL; struct got_object_id *head_id = NULL; STAILQ_INIT(&reversed_commits); RB_INIT(&changed_paths); if (end_id && got_object_id_cmp(root_id, end_id) != 0) { err = got_commit_graph_find_youngest_common_ancestor( &yca_id, root_id, end_id, 1, 0, repo_write.repo, check_cancelled, NULL); if (err) return err; if (yca_id) end_id = yca_id; } if (end_id == NULL) { err = got_ref_open(&head_ref, repo_write.repo, GOT_REF_HEAD, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; } else { err = got_ref_resolve(&head_id, repo_write.repo, head_ref); if (err) goto done; if (got_object_id_cmp(root_id, head_id) != 0) { err = got_commit_graph_find_youngest_common_ancestor( &yca_id, root_id, head_id, 1, 0, repo_write.repo, check_cancelled, NULL); if (err) goto done; if (yca_id) end_id = yca_id; } } } /* XXX first-parent only for now */ err = got_commit_graph_open(&graph, "/", 1); if (err) return err; err = got_commit_graph_bfsort(graph, root_id, repo, check_cancelled, NULL); if (err) goto done; for (;;) { struct got_object_id id; err = got_commit_graph_iter_next(&id, graph, repo, check_cancelled, NULL); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) err = NULL; break; } err = got_object_open_as_commit(&commit, repo, &id); if (err) break; if (end_id && got_object_id_cmp(&id, end_id) == 0) break; err = got_object_qid_alloc(&qid, &id); if (err) break; STAILQ_INSERT_HEAD(&reversed_commits, qid, entry); ncommits++; got_object_commit_close(commit); if (end_id == NULL) break; } STAILQ_FOREACH(qid, &reversed_commits, entry) { struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE }; err = got_object_open_as_commit(&commit, repo, &qid->id); if (err) break; if (ncommits > shortlog_threshold) { err = print_commit_oneline(commit, &qid->id, repo, fd); if (err) break; } else { err = get_changed_paths(&changed_paths, commit, repo, &dsa); if (err) break; err = print_commit(commit, &qid->id, repo, &changed_paths, &dsa, fd); } got_object_commit_close(commit); commit = NULL; got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); } done: free(yca_id); free(head_id); if (head_ref) got_ref_close(head_ref); if (commit) got_object_commit_close(commit); got_object_id_queue_free(&reversed_commits); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (graph) got_commit_graph_close(graph); return err; } static const struct got_error * print_tag(struct got_object_id *id, const char *refname, struct got_repository *repo, int fd) { const struct got_error *err = NULL; struct got_tag_object *tag = NULL; const char *tagger = NULL; char *id_str = NULL, *tagmsg0 = NULL, *tagmsg, *line; time_t tagger_time; err = got_object_open_as_tag(&tag, repo, id); if (err) return err; tagger = got_object_tag_get_tagger(tag); tagger_time = got_object_tag_get_tagger_time(tag); err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (err) goto done; dprintf(fd, "tag %s\n", refname); dprintf(fd, "from: %s\n", tagger); dprintf(fd, "date: %lld\n", (long long)tagger_time); switch (got_object_tag_get_object_type(tag)) { case GOT_OBJ_TYPE_BLOB: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); break; case GOT_OBJ_TYPE_TREE: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); break; case GOT_OBJ_TYPE_COMMIT: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); break; case GOT_OBJ_TYPE_TAG: dprintf(fd, "object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); break; default: break; } tagmsg0 = strdup(got_object_tag_get_message(tag)); if (tagmsg0 == NULL) { err = got_error_from_errno("strdup"); goto done; } dprintf(fd, "messagelen: %zu\n", strlen(tagmsg0)); tagmsg = tagmsg0; do { line = strsep(&tagmsg, "\n"); if (line) dprintf(fd, " %s\n", line); } while (line); free(tagmsg0); done: if (tag) got_object_tag_close(tag); free(id_str); return err; } static const struct got_error * notify_changed_ref(const char *refname, struct got_object_id *old_id, struct got_object_id *new_id, struct gotd_imsgev *iev, int fd) { const struct got_error *err; int old_obj_type, new_obj_type; const char *label; char *new_id_str = NULL; err = got_object_get_type(&old_obj_type, repo_write.repo, old_id); if (err) return err; err = got_object_get_type(&new_obj_type, repo_write.repo, new_id); if (err) return err; switch (new_obj_type) { case GOT_OBJ_TYPE_COMMIT: err = print_commits(new_id, old_obj_type == GOT_OBJ_TYPE_COMMIT ? old_id : NULL, repo_write.repo, fd); break; case GOT_OBJ_TYPE_TAG: err = print_tag(new_id, refname, repo_write.repo, fd); break; default: err = got_object_type_label(&label, new_obj_type); if (err) goto done; err = got_object_id_str(&new_id_str, new_id); if (err) goto done; dprintf(fd, "%s: %s object %s\n", refname, label, new_id_str); break; } done: free(new_id_str); return err; } static const struct got_error * notify_created_ref(const char *refname, struct got_object_id *id, struct gotd_imsgev *iev, int fd) { const struct got_error *err = NULL; int obj_type; err = got_object_get_type(&obj_type, repo_write.repo, id); if (err) return err; if (obj_type == GOT_OBJ_TYPE_TAG) return print_tag(id, refname, repo_write.repo, fd); return print_commits(id, NULL, repo_write.repo, fd); } static const struct got_error * render_notification(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct gotd_imsg_notification_content ireq; size_t datalen, len; char *refname = NULL; struct ibuf *wbuf; int fd = -1; fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ireq)) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } memcpy(&ireq, imsg->data, sizeof(ireq)); if (datalen != sizeof(ireq) + ireq.refname_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } refname = strndup(imsg->data + sizeof(ireq), ireq.refname_len); if (refname == NULL) { err = got_error_from_errno("strndup"); goto done; } switch (ireq.action) { case GOTD_NOTIF_ACTION_CREATED: err = notify_created_ref(refname, &ireq.new_id, iev, fd); break; case GOTD_NOTIF_ACTION_REMOVED: err = notify_removed_ref(refname, &ireq.old_id, iev, fd); break; case GOTD_NOTIF_ACTION_CHANGED: err = notify_changed_ref(refname, &ireq.old_id, &ireq.new_id, iev, fd); break; } if (err != NULL) goto done; if (fsync(fd) == -1) { err = got_error_from_errno("fsync"); goto done; } len = sizeof(ireq) + ireq.refname_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, GOTD_PROC_REPO_WRITE, repo_write.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } if (imsg_add(wbuf, &ireq, sizeof(ireq)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, refname, ireq.refname_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: free(refname); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static const struct got_error * send_packfile_received(struct gotd_imsgev *iev, int have_packfile) { struct gotd_imsg_packfile_received recvd; int ret; if (have_packfile) recvd.pack_empty = 0; else recvd.pack_empty = 1; ret = gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_RECEIVED, GOTD_PROC_REPO_WRITE, -1, &recvd, sizeof(recvd)); if (ret == -1) return got_error_from_errno("imsg_compose PACKFILE_RECEIVED"); return NULL; } static const struct got_error * open_tree(struct got_tree_object **tree, struct got_pack *pack, struct got_packidx *packidx, int idx, struct got_object_id *tree_id) { const struct got_error *err; struct got_parsed_tree_entry *entries = NULL; size_t nentries = 0, nentries_alloc = 0, i; struct got_object *obj = NULL; uint8_t *buf = NULL; size_t len; *tree = NULL; err = got_packfile_open_object(&obj, pack, packidx, idx, tree_id); if (err) return err; if (obj->type != GOT_OBJ_TYPE_TREE) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); if (err) goto done; err = got_object_parse_tree(&entries, &nentries, &nentries_alloc, buf, len, GOT_HASH_SHA1); if (err) goto done; *tree = malloc(sizeof(**tree)); if (*tree == NULL) { err = got_error_from_errno("malloc"); goto done; } (*tree)->entries = calloc(nentries, sizeof(struct got_tree_entry)); if ((*tree)->entries == NULL) { err = got_error_from_errno("malloc"); goto done; } (*tree)->nentries = nentries; (*tree)->refcnt = 0; for (i = 0; i < nentries; i++) { struct got_parsed_tree_entry *pe = &entries[i]; struct got_tree_entry *te = &(*tree)->entries[i]; if (strlcpy(te->name, pe->name, sizeof(te->name)) >= sizeof(te->name)) { err = got_error(GOT_ERR_NO_SPACE); goto done; } memcpy(te->id.hash, pe->id, pe->digest_len); te->id.algo = GOT_HASH_SHA1; te->mode = pe->mode; te->idx = i; } done: if (err && *tree) { got_object_tree_close(*tree); *tree = NULL; } got_object_close(obj); free(buf); return err; } static struct got_tree_entry * find_entry_by_name(struct got_tree_object *tree, const char *name, size_t len) { int i; /* Note that tree entries are sorted in strncmp() order. */ for (i = 0; i < tree->nentries; i++) { struct got_tree_entry *te = &tree->entries[i]; int cmp = strncmp(te->name, name, len); if (cmp < 0) continue; if (cmp > 0) break; if (te->name[len] == '\0') return te; } return NULL; } static const struct got_error * find_id_by_path(struct got_object_id **id, struct got_pack *pack, struct got_packidx *packidx, struct got_tree_object *tree, const char *path) { const struct got_error *err = NULL; struct got_tree_object *subtree = NULL; struct got_tree_entry *te = NULL; const char *seg, *s; size_t seglen; *id = NULL; s = path; while (s[0] == '/') s++; seg = s; seglen = 0; subtree = tree; while (*s) { struct got_tree_object *next_tree; if (*s != '/') { s++; seglen++; if (*s) continue; } te = find_entry_by_name(subtree, seg, seglen); if (te == NULL) break; if (*s == '\0') break; seg = s + 1; seglen = 0; s++; if (*s) { int idx; idx = got_packidx_get_object_idx(packidx, &te->id); if (idx == -1) { te = NULL; break; } err = open_tree(&next_tree, pack, packidx, idx, &te->id); te = NULL; if (err) goto done; if (subtree != tree) got_object_tree_close(subtree); subtree = next_tree; } } if (te) { *id = got_object_id_dup(&te->id); if (*id == NULL) return got_error_from_errno("got_object_id_dup"); } else err = got_error_path(path, GOT_ERR_NO_TREE_ENTRY); done: if (subtree && subtree != tree) got_object_tree_close(subtree); return err; } static const struct got_error * get_content_from_packfile(struct gotd_imsgev *iev, struct imsg *imsg) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsg_packfile_get_content content_req; struct gotd_imsg_packfile_content_written written_resp; size_t datalen; char *refname = NULL; char *path = NULL; int fd = -1, idx; struct gotd_ref_update *ref_update; struct got_object_id *tree_id = NULL, *content_id = NULL; struct got_object *obj = NULL; uint8_t *buf = NULL; size_t len; struct got_commit_object *commit = NULL; struct got_tree_object *tree = NULL; FILE *outfile = NULL; memset(&written_resp, 0, sizeof(written_resp)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(content_req)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&content_req, imsg->data, sizeof(content_req)); if (content_req.path_len == 0 || content_req.refname_len == 0 || datalen != sizeof(content_req) + content_req.refname_len + content_req.path_len) return got_error(GOT_ERR_PRIVSEP_LEN); refname = strndup(imsg->data + sizeof(content_req), content_req.refname_len); if (strlen(refname) != content_req.refname_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } path = strndup(imsg->data + sizeof(content_req) + content_req.refname_len, content_req.path_len); if (strlen(path) != content_req.path_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (got_path_is_root_dir(path)) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } fd = imsg_get_fd(imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); goto done; } outfile = fdopen(fd, "w"); if (outfile == NULL) { err = got_error_from_errno("fdopen"); goto done; } fd = -1; STAILQ_FOREACH(ref_update, &client->ref_updates, entry) { if (strcmp(got_ref_get_name(ref_update->ref), refname) == 0) break; } if (ref_update == NULL) goto send_response; written_resp.ref_found = 1; idx = got_packidx_get_object_idx(client->packidx, &ref_update->new_id); if (idx == -1) goto send_response; err = got_packfile_open_object(&obj, &client->pack, client->packidx, idx, &ref_update->new_id); if (err) goto done; if (obj->type != GOT_OBJ_TYPE_COMMIT) goto send_response; err = got_packfile_extract_object_to_mem(&buf, &len, obj, &client->pack); if (err) goto done; got_object_close(obj); obj = NULL; err = got_object_parse_commit(&commit, buf, len, GOT_HASH_SHA1); if (err) goto done; tree_id = got_object_id_dup(commit->tree_id); if (tree_id == NULL) err = got_error_from_errno("got_object_id_dup"); got_object_commit_close(commit); commit = NULL; free(buf); buf = NULL; len = 0; idx = got_packidx_get_object_idx(client->packidx, tree_id); if (idx == -1) goto send_response; err = open_tree(&tree, &client->pack, client->packidx, idx, tree_id); if (err) goto done; err = find_id_by_path(&content_id, &client->pack, client->packidx, tree, path); if (err) goto done; idx = got_packidx_get_object_idx(client->packidx, content_id); if (idx == -1) goto send_response; err = got_packfile_open_object(&obj, &client->pack, client->packidx, idx, content_id); if (err) goto done; if (obj->type != GOT_OBJ_TYPE_BLOB) goto send_response; err = got_packfile_extract_object(&client->pack, obj, outfile, repo_write.base_file, repo_write.accum_file); if (err) goto done; written_resp.wrote_content = 1; send_response: if (imsg_compose(&iev->ibuf, GOTD_IMSG_PACKFILE_CONTENT_WRITTEN, GOTD_PROC_REPO_WRITE, repo_write.pid, -1, &written_resp, sizeof(written_resp)) == -1) { err = got_error_from_errno("imsg_compose " "PACKFILE_CONTENT_WRITTEn"); goto done; } err = gotd_imsg_flush(&iev->ibuf); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (outfile && fclose(outfile) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(refname); free(path); free(tree_id); free(buf); if (obj) got_object_close(obj); if (commit) got_object_commit_close(commit); return err; } static void repo_write_dispatch_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; struct repo_write_client *client = &repo_write_client; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } while (err == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; if (imsg.hdr.type != GOTD_IMSG_LIST_REFS_INTERNAL && !repo_write.refs_listed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } switch (imsg.hdr.type) { case GOTD_IMSG_LIST_REFS_INTERNAL: err = list_refs(&imsg); if (err) log_warnx("ls-refs: %s", err->msg); break; case GOTD_IMSG_REF_UPDATE: err = recv_ref_update(&imsg); if (err) log_warnx("ref-update: %s", err->msg); break; case GOTD_IMSG_PACKFILE_PIPE: err = receive_pack_pipe(&imsg, iev); if (err) { log_warnx("receiving pack pipe: %s", err->msg); break; } break; case GOTD_IMSG_PACKIDX_FILE: err = receive_pack_idx(&imsg, iev); if (err) { log_warnx("receiving pack index: %s", err->msg); break; } break; case GOTD_IMSG_RECV_PACKFILE: err = protect_refs_from_deletion(); if (err) break; err = recv_packfile(&repo_write.have_packfile, &imsg); if (err) { log_warnx("receive packfile: %s", err->msg); break; } if (repo_write.have_packfile) { err = verify_packfile(); if (err) { log_warnx("verify packfile: %s", err->msg); break; } } else { /* * Clients sending empty pack files might be * attempting to move a protected reference. */ err = protect_refs_from_moving(); if (err) break; } err = send_packfile_received(iev, repo_write.have_packfile); if (err) log_warnx("receive packfile: %s", err->msg); break; case GOTD_IMSG_PACKFILE_GET_CONTENT: if (!repo_write.have_packfile || client->packidx == NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = get_content_from_packfile(iev, &imsg); break; case GOTD_IMSG_PACKFILE_VERIFIED: if (repo_write.have_packfile) { err = install_packfile(iev); if (err) { log_warnx("install packfile: %s", err->msg); break; } /* * Ensure we re-read the pack index list * upon next access. */ repo_write.repo->pack_path_mtime.tv_sec = 0; repo_write.repo->pack_path_mtime.tv_nsec = 0; } err = update_refs(iev); if (err) log_warnx("update refs: %s", err->msg); break; case GOTD_IMSG_NOTIFY: err = render_notification(&imsg, iev); if (err) { log_warnx("render notification: %s", err->msg); shut = 1; } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, GOTD_PROC_REPO_WRITE, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_imsgev *iev = &repo_write.session_iev; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_write.session_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); repo_write.session_fd = imsg_get_fd(imsg); if (repo_write.session_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (imsgbuf_init(&iev->ibuf, repo_write.session_fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = repo_write_dispatch_session; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, repo_write_dispatch_session, iev); gotd_imsg_event_add(iev); return NULL; } static void repo_write_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_write_client *client = &repo_write_client; size_t npaths; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } while (err == NULL) { err = check_cancelled(NULL); if (err) break; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_PROTECTED_TAG_NAMESPACES: if (repo_write.protected_refs_cur != NULL || repo_write.nprotected_refs_needed != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist(&npaths, &imsg); if (err) break; repo_write.protected_refs_cur = &repo_write.protected_tag_namespaces; repo_write.nprotected_refs_needed = npaths; repo_write.nprotected_refs_received = 0; break; case GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES: if (repo_write.protected_refs_cur != NULL || repo_write.nprotected_refs_needed != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist(&npaths, &imsg); if (err) break; repo_write.protected_refs_cur = &repo_write.protected_branch_namespaces; repo_write.nprotected_refs_needed = npaths; repo_write.nprotected_refs_received = 0; break; case GOTD_IMSG_PROTECTED_BRANCHES: if (repo_write.protected_refs_cur != NULL || repo_write.nprotected_refs_needed != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist(&npaths, &imsg); if (err) break; repo_write.protected_refs_cur = &repo_write.protected_branches; repo_write.nprotected_refs_needed = npaths; repo_write.nprotected_refs_received = 0; break; case GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM: case GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM: case GOTD_IMSG_PROTECTED_BRANCHES_ELEM: if (repo_write.protected_refs_cur == NULL || repo_write.nprotected_refs_needed == 0 || repo_write.nprotected_refs_received >= repo_write.nprotected_refs_needed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist_elem(&imsg, repo_write.protected_refs_cur); if (err) break; if (++repo_write.nprotected_refs_received >= repo_write.nprotected_refs_needed) { repo_write.protected_refs_cur = NULL; repo_write.nprotected_refs_needed = 0; } break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_connect(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err && gotd_imsg_send_error_event(iev, GOTD_PROC_REPO_WRITE, client->id, err) == -1) log_warnx("could not send error to parent: %s", err->msg); done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void repo_write_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, FILE *base_file, FILE *accum_file, FILE *diff_f1, FILE *diff_f2, int diff_fd1, int diff_fd2) { const struct got_error *err = NULL; struct repo_write_client *client = &repo_write_client; struct gotd_imsgev iev; client->fd = -1; client->pack_pipe = -1; client->packidx_fd = -1; client->pack.fd = -1; repo_write.title = title; repo_write.pid = getpid(); repo_write.pack_fds = pack_fds; repo_write.temp_fds = temp_fds; repo_write.base_file = base_file; repo_write.accum_file = accum_file; repo_write.session_fd = -1; repo_write.session_iev.ibuf.fd = -1; RB_INIT(&repo_write.protected_tag_namespaces); RB_INIT(&repo_write.protected_branch_namespaces); RB_INIT(&repo_write.protected_branches); repo_write.diff.f1 = diff_f1; repo_write.diff.f2 = diff_f2; repo_write.diff.fd1 = diff_fd1; repo_write.diff.fd2 = diff_fd2; STAILQ_INIT(&repo_write_client.ref_updates); err = got_repo_open(&repo_write.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(repo_write.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } if (got_repo_get_object_format(repo_write.repo) != GOT_HASH_SHA1) { err = got_error_msg(GOT_ERR_NOT_IMPL, "sha256 object IDs unsupported in network protocol"); goto done; } got_repo_temp_fds_set(repo_write.repo, temp_fds); signal(SIGINT, catch_sigint); signal(SIGTERM, catch_sigterm); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); if (imsgbuf_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&iev.ibuf); iev.handler = repo_write_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, repo_write_dispatch, &iev); if (gotd_imsg_compose_event(&iev, GOTD_IMSG_REPO_CHILD_READY, GOTD_PROC_REPO_WRITE, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose REPO_CHILD_READY"); goto done; } event_dispatch(); done: if (fclose(diff_f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (fclose(diff_f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (close(diff_fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (close(diff_fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) log_warnx("%s: %s", title, err->msg); repo_write_shutdown(); } void repo_write_shutdown(void) { struct repo_write_client *client = &repo_write_client; struct gotd_ref_update *ref_update; log_debug("%s: shutting down", repo_write.title); while (!STAILQ_EMPTY(&client->ref_updates)) { ref_update = STAILQ_FIRST(&client->ref_updates); STAILQ_REMOVE_HEAD(&client->ref_updates, entry); got_ref_close(ref_update->ref); free(ref_update); } if (client->packidx) got_packidx_close(client->packidx); got_pack_close(&client->pack); if (client->fd != -1) close(client->fd); if (client->pack_pipe != -1) close(client->pack_pipe); if (client->packidx_fd != -1) close(client->packidx_fd); if (repo_write.repo) got_repo_close(repo_write.repo); got_repo_pack_fds_close(repo_write.pack_fds); got_repo_temp_fds_close(repo_write.temp_fds); if (repo_write.session_fd != -1) close(repo_write.session_fd); exit(0); } got-portable-0.119/gotd/gotd-secrets.conf.50000664000175000017500000000541615066535721014200 .\" .\" Copyright (c) 2024 Omar Polo .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTD-SECRETS.CONF 5 .Os .Sh NAME .Nm gotd-secrets.conf .Nd gotd secrets file .Sh DESCRIPTION .Nm contains authentication credentials for use with .Xr gotd 8 notifications. This file must be owned by the root user and must not be readable by any other users. .Pp The file format is line-based, with one entry per line. Comments can appear at the start of a line using a hash mark .Pq Sq # , and extend to the end of the line. Empty lines are ignored. .Pp Each entry consists of whitespace-separated tokens and defines a set of credentials. Any credential parameters containing whitespace should be surrounded by single or double quotes. .Pp Each set of credentials must be given a .Ar label which can be used to refer to credentials in .Xr gotd.conf 5 . This .Ar label must be unique among all credentials of the same type. .Pp The supported credential types and their parameters are: .Bl -tag -width Ds .It Ic auth Ar label Ic user Ar user Ic password Ar password The .Ic auth type represents HTTP Basic Authentication credentials consisting of a .Ar user and a .Ar password . .It Ic hmac Ar label Ar secret The .Ic hmac type represents shared secrets for use with HMAC signatures of HTTP request bodies. A suitable .Ar secret can be generated with .Xr openssl 1 as follows: .Pp .Dl $ openssl rand -base64 32 .El .Pp .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotd-secrets.conf Location of the .Nm configuration file. .El .Sh EXAMPLES Define credentials for HTTP basic authentication and HMAC signatures: .Bd -literal -offset indent # /etc/gotd-secrets.conf auth mochi user "flan" password "super-strong-password!" hmac hacker q0tcl8QhjYs7U75MW/2rwB30CpdbAhONkfLGxFHm/+8= .Ed .Pp These credentials can be referenced in .Xr gotd.conf 5 as follows: .Bd -literal -offset indent # /etc/gotd.conf repository "openbsd/src" { path "/var/git/src.git" permit rw :hackers notify { url https://example.com/ci/ auth mochi hmac hacker } } .El .Sh SEE ALSO .Xr got 1 , .Xr gotsh 1 , .Xr gotd.conf 5 , .Xr gotd 8 got-portable-0.119/gotd/session_write.c0000664000175000017500000015701115066536113013617 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_compat.h" #include "got_error.h" #include "got_repository.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "got_opentemp.h" #include "got_lib_hash.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_gitproto.h" #include "gotd.h" #include "log.h" #include "session_write.h" struct gotd_session_notif { STAILQ_ENTRY(gotd_session_notif) entry; int fd; enum gotd_notification_action action; char *refname; struct got_object_id old_id; struct got_object_id new_id; }; STAILQ_HEAD(gotd_session_notifications, gotd_session_notif) notifications; enum gotd_session_write_state { GOTD_STATE_EXPECT_LIST_REFS, GOTD_STATE_EXPECT_CAPABILITIES, GOTD_STATE_EXPECT_REF_UPDATE, GOTD_STATE_EXPECT_MORE_REF_UPDATES, GOTD_STATE_EXPECT_PACKFILE, GOTD_STATE_NOTIFY, }; static struct gotd_session_write { pid_t pid; const char *title; struct got_repository *repo; char repo_name[NAME_MAX]; int *pack_fds; int *temp_fds; int content_fd; struct gotd_imsgev parent_iev; struct gotd_imsgev notifier_iev; struct timeval request_timeout; enum gotd_session_write_state state; struct gotd_imsgev repo_child_iev; struct got_pathlist_head notification_refs; struct got_pathlist_head notification_ref_namespaces; size_t num_notification_refs_needed; size_t num_notification_refs_received; struct got_pathlist_head *notification_refs_cur; struct gotd_notification_targets notification_targets; int repo_child_packfd; } gotd_session; static struct gotd_session_client { struct gotd_client_capability *capabilities; size_t ncapa_alloc; size_t ncapabilities; uint32_t id; int fd; int delta_cache_fd; struct gotd_imsgev iev; struct event tmo; uid_t euid; gid_t egid; char *username; char *packfile_path; char *packidx_path; int nref_updates; int accept_flush_pkt; int flush_disconnect; } gotd_session_client; static void session_write_shutdown(void); static void disconnect(struct gotd_session_client *client) { log_debug("uid %d: disconnecting", client->euid); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_DISCONNECT, GOTD_PROC_SESSION_WRITE, -1, NULL, 0) == -1) log_warn("imsg compose DISCONNECT"); imsgbuf_clear(&gotd_session.repo_child_iev.ibuf); event_del(&gotd_session.repo_child_iev.ev); evtimer_del(&client->tmo); close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->packfile_path) { if (unlink(client->packfile_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packfile_path); free(client->packfile_path); } if (client->packidx_path) { if (unlink(client->packidx_path) == -1 && errno != ENOENT) log_warn("unlink %s: ", client->packidx_path); free(client->packidx_path); } free(client->capabilities); session_write_shutdown(); } static void disconnect_on_error(struct gotd_session_client *client, const struct got_error *err) { struct imsgbuf ibuf; if (err->code != GOT_ERR_EOF) { log_warnx("uid %d: %s", client->euid, err->msg); if (imsgbuf_init(&ibuf, client->fd) == -1) { log_warn("imsgbuf_init"); } else { gotd_imsg_send_error(&ibuf, 0, GOTD_PROC_SESSION_WRITE, err); imsgbuf_clear(&ibuf); } } disconnect(client); } static void gotd_request_timeout(int fd, short events, void *arg) { struct gotd_session_client *client = arg; log_warnx("disconnecting uid %d due to timeout", client->euid); disconnect(client); } static void session_write_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: session_write_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static const struct got_error * recv_packfile_received(int *pack_empty, struct imsg *imsg) { struct gotd_imsg_packfile_received recvd; size_t datalen; *pack_empty = 0; log_debug("packfile-received received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(recvd)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&recvd, imsg->data, sizeof(recvd)); if (recvd.pack_empty) *pack_empty = 1; return NULL; } static const struct got_error * request_gotsys_conf(struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct gotd_imsg_packfile_get_content content_req; const char *refname = "refs/heads/main"; const char *path = "gotsys.conf"; struct ibuf *wbuf; size_t len; int fd = -1; err = got_opentemp_truncatefd(gotd_session.content_fd); if (err) return err; len = sizeof(content_req) + strlen(refname) + strlen(path); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_PACKFILE_GET_CONTENT, GOTD_PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create PACKFILE_GET_CONTENT"); memset(&content_req, 0, sizeof(content_req)); content_req.refname_len = strlen(refname); content_req.path_len = strlen(path); if (imsg_add(wbuf, &content_req, sizeof(content_req)) == -1) return got_error_from_errno("imsg_add PACKFILE_GET_CONTENT"); if (imsg_add(wbuf, refname, content_req.refname_len) == -1) return got_error_from_errno("imsg_add PACKFILE_GET_CONTENT"); if (imsg_add(wbuf, path, content_req.path_len) == -1) return got_error_from_errno("imsg_add PACKFILE_GET_CONTENT"); fd = dup(gotd_session.content_fd); if (fd == -1) { ibuf_free(wbuf); return got_error_from_errno("dup"); } ibuf_fd_set(wbuf, fd); imsg_close(&iev->ibuf, wbuf); return gotd_imsg_flush(&iev->ibuf); } static int need_packfile_verification(void) { return (strcmp(gotd_session.repo_name, "gotsys") == 0 || strcmp(gotd_session.repo_name, "gotsys.git") == 0); } static const struct got_error * verify_packfile(struct gotd_imsgev *iev) { /* For now, verification is only implemented for gotsys.git. */ return request_gotsys_conf(iev); } static const struct got_error * recv_content_written(int *ref_found, struct imsg *imsg) { struct gotd_imsg_packfile_content_written cw; size_t datalen; *ref_found = 0; log_debug("content-written received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(cw)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&cw, imsg->data, sizeof(cw)); if (cw.ref_found) { *ref_found = 1; /* Currently we only look for gotsys.conf content. */ if (!cw.wrote_content) { return got_error_msg(GOT_ERR_BAD_OBJ_DATA, "gotsys.conf not found in pack file"); } } return NULL; } static const struct got_error * verify_gotsys_conf(void) { struct gotd_imsgev *iev = &gotd_session.parent_iev; int fd; fd = dup(gotd_session.content_fd); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_RUN_GOTSYS_CHECK, GOTD_PROC_SESSION_WRITE, fd, NULL, 0) == -1) { close(fd); return got_error_from_errno("imsg compose RUN_GOTSYS_CHECK"); } return NULL; } static const struct got_error * send_packfile_verified(struct gotd_imsgev *iev) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_VERIFIED, GOTD_PROC_SESSION_WRITE, -1, NULL, 0) == -1) return got_error_from_errno("imsg compose PACKFILE_VERIFIED"); return NULL; } static const struct got_error * recv_packfile_install(struct imsg *imsg) { struct gotd_imsg_packfile_install inst; size_t datalen; log_debug("packfile-install received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(inst)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inst, imsg->data, sizeof(inst)); return NULL; } static const struct got_error * recv_ref_updates_start(struct imsg *imsg) { struct gotd_imsg_ref_updates_start istart; size_t datalen; log_debug("ref-updates-start received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(istart)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&istart, imsg->data, sizeof(istart)); return NULL; } static const struct got_error * recv_ref_update(struct imsg *imsg) { struct gotd_imsg_ref_update iref; size_t datalen; log_debug("ref-update received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); return NULL; } static const struct got_error * send_ref_update_ok(struct gotd_session_client *client, struct gotd_imsg_ref_update *iref, const char *refname) { struct gotd_imsg_ref_update_ok iok; struct gotd_imsgev *iev = &client->iev; struct ibuf *wbuf; size_t len; memset(&iok, 0, sizeof(iok)); memcpy(iok.old_id, iref->old_id, SHA1_DIGEST_LENGTH); memcpy(iok.new_id, iref->new_id, SHA1_DIGEST_LENGTH); iok.name_len = strlen(refname); len = sizeof(iok) + iok.name_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_OK, GOTD_PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE_OK"); if (imsg_add(wbuf, &iok, sizeof(iok)) == -1) return got_error_from_errno("imsg_add REF_UPDATE_OK"); if (imsg_add(wbuf, refname, iok.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_OK"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * send_refs_updated(struct gotd_imsgev *iev) { if (gotd_imsg_compose_event(iev, GOTD_IMSG_REFS_UPDATED, GOTD_PROC_SESSION_WRITE, -1, NULL, 0) == -1) return got_error_from_errno("imsg compose REFS_UPDATED"); return NULL; } static const struct got_error * send_ref_update_ng(struct gotd_session_client *client, struct gotd_imsg_ref_update *iref, const char *refname, const char *reason) { const struct got_error *ng_err; struct gotd_imsg_ref_update_ng ing; struct gotd_imsgev *iev = &client->iev; struct ibuf *wbuf; size_t len; memset(&ing, 0, sizeof(ing)); memcpy(ing.old_id, iref->old_id, SHA1_DIGEST_LENGTH); memcpy(ing.new_id, iref->new_id, SHA1_DIGEST_LENGTH); ing.name_len = strlen(refname); ng_err = got_error_fmt(GOT_ERR_REF_BUSY, "%s", reason); ing.reason_len = strlen(ng_err->msg); len = sizeof(ing) + ing.name_len + ing.reason_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_NG, GOTD_PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) return got_error_from_errno("imsg_create REF_UPDATE_NG"); if (imsg_add(wbuf, &ing, sizeof(ing)) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); if (imsg_add(wbuf, refname, ing.name_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); if (imsg_add(wbuf, ng_err->msg, ing.reason_len) == -1) return got_error_from_errno("imsg_add REF_UPDATE_NG"); imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * install_pack(struct gotd_session_client *client, const char *repo_path, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_packfile_install inst; char hex[SHA1_DIGEST_STRING_LENGTH]; size_t datalen; char *packfile_path = NULL, *packidx_path = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(inst)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inst, imsg->data, sizeof(inst)); if (client->packfile_path == NULL) return got_error_msg(GOT_ERR_BAD_REQUEST, "client has no pack file"); if (client->packidx_path == NULL) return got_error_msg(GOT_ERR_BAD_REQUEST, "client has no pack file index"); if (got_sha1_digest_to_str(inst.pack_sha1, hex, sizeof(hex)) == NULL) return got_error_msg(GOT_ERR_NO_SPACE, "could not convert pack file SHA1 to hex"); if (asprintf(&packfile_path, "/%s/%s/pack-%s.pack", repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (asprintf(&packidx_path, "/%s/%s/pack-%s.idx", repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (rename(client->packfile_path, packfile_path) == -1) { err = got_error_from_errno3("rename", client->packfile_path, packfile_path); goto done; } free(client->packfile_path); client->packfile_path = NULL; if (rename(client->packidx_path, packidx_path) == -1) { err = got_error_from_errno3("rename", client->packidx_path, packidx_path); goto done; } /* Ensure we re-read the pack index list upon next access. */ gotd_session.repo->pack_path_mtime.tv_sec = 0; gotd_session.repo->pack_path_mtime.tv_nsec = 0; free(client->packidx_path); client->packidx_path = NULL; done: free(packfile_path); free(packidx_path); return err; } static const struct got_error * begin_ref_updates(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_ref_updates_start istart; size_t datalen; if (client->nref_updates != -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(istart)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&istart, imsg->data, sizeof(istart)); if (istart.nref_updates <= 0) return got_error(GOT_ERR_PRIVSEP_MSG); client->nref_updates = istart.nref_updates; return NULL; } static const struct got_error * validate_namespace(const char *namespace) { size_t len = strlen(namespace); if (len < 5 || strncmp("refs/", namespace, 5) != 0 || namespace[len - 1] != '/') { return got_error_fmt(GOT_ERR_BAD_REF_NAME, "reference namespace '%s'", namespace); } return NULL; } static const struct got_error * queue_notification(struct got_object_id *old_id, struct got_object_id *new_id, struct got_repository *repo, struct got_reference *ref) { const struct got_error *err = NULL; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; struct got_pathlist_entry *pe; struct gotd_session_notif *notif; if (iev->ibuf.fd == -1 || STAILQ_EMPTY(&gotd_session.notification_targets)) return NULL; /* notifications unused */ RB_FOREACH(pe, got_pathlist_head, &gotd_session.notification_refs) { const char *refname = pe->path; if (strcmp(got_ref_get_name(ref), refname) == 0) break; } if (pe == NULL) { RB_FOREACH(pe, got_pathlist_head, &gotd_session.notification_ref_namespaces) { const char *namespace = pe->path; err = validate_namespace(namespace); if (err) return err; if (strncmp(namespace, got_ref_get_name(ref), strlen(namespace)) == 0) break; } } /* * If a branch or a reference namespace was specified in the * configuration file then only send notifications if a match * was found. */ if (pe == NULL && (!RB_EMPTY(&gotd_session.notification_refs) || !RB_EMPTY(&gotd_session.notification_ref_namespaces))) return NULL; notif = calloc(1, sizeof(*notif)); if (notif == NULL) return got_error_from_errno("calloc"); notif->fd = -1; if (old_id == NULL) notif->action = GOTD_NOTIF_ACTION_CREATED; else if (new_id == NULL) notif->action = GOTD_NOTIF_ACTION_REMOVED; else notif->action = GOTD_NOTIF_ACTION_CHANGED; if (old_id != NULL) memcpy(¬if->old_id, old_id, sizeof(notif->old_id)); if (new_id != NULL) memcpy(¬if->new_id, new_id, sizeof(notif->new_id)); notif->refname = strdup(got_ref_get_name(ref)); if (notif->refname == NULL) { err = got_error_from_errno("strdup"); goto done; } STAILQ_INSERT_TAIL(¬ifications, notif, entry); done: if (err && notif) { free(notif->refname); free(notif); } return err; } /* Forward notification content to the NOTIFY process. */ static const struct got_error * forward_notification(struct gotd_session_client *client, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = &gotd_session.notifier_iev; struct gotd_session_notif *notif; struct gotd_imsg_notification_content icontent; char *refname = NULL, *id_str = NULL; size_t datalen; struct gotd_imsg_notify inotify; const char *action; struct ibuf *wbuf; memset(&inotify, 0, sizeof(inotify)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icontent)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icontent, imsg->data, sizeof(icontent)); if (datalen != sizeof(icontent) + icontent.refname_len) return got_error(GOT_ERR_PRIVSEP_LEN); refname = strndup(imsg->data + sizeof(icontent), icontent.refname_len); if (refname == NULL) return got_error_from_errno("strndup"); notif = STAILQ_FIRST(¬ifications); if (notif == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); if (notif->action != icontent.action || notif->fd == -1 || strcmp(notif->refname, refname) != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } if (notif->action == GOTD_NOTIF_ACTION_CREATED) { if (memcmp(¬if->new_id, &icontent.new_id, sizeof(notif->new_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } } else if (notif->action == GOTD_NOTIF_ACTION_REMOVED) { if (memcmp(¬if->old_id, &icontent.old_id, sizeof(notif->old_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } } else if (memcmp(¬if->old_id, &icontent.old_id, sizeof(notif->old_id)) != 0 || memcmp(¬if->new_id, &icontent.new_id, sizeof(notif->old_id)) != 0) { err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "received notification content for unknown event"); goto done; } switch (notif->action) { case GOTD_NOTIF_ACTION_CREATED: action = "created"; err = got_object_id_str(&id_str, ¬if->new_id); if (err) goto done; break; case GOTD_NOTIF_ACTION_REMOVED: action = "removed"; err = got_object_id_str(&id_str, ¬if->old_id); if (err) goto done; break; case GOTD_NOTIF_ACTION_CHANGED: action = "changed"; err = got_object_id_str(&id_str, ¬if->new_id); if (err) goto done; break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } strlcpy(inotify.repo_name, gotd_session.repo_name, sizeof(inotify.repo_name)); snprintf(inotify.subject_line, sizeof(inotify.subject_line), "%s: %s %s %s: %.12s", gotd_session.repo_name, client->username, action, notif->refname, id_str); inotify.username_len = strlen(client->username); wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, GOTD_PROC_SESSION_WRITE, gotd_session.pid, sizeof(inotify) + inotify.username_len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create NOTIFY"); goto done; } if (imsg_add(wbuf, &inotify, sizeof(inotify)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, client->username, inotify.username_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } ibuf_fd_set(wbuf, notif->fd); notif->fd = -1; imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: free(refname); free(id_str); return err; } /* Request notification content from REPO_WRITE process. */ static const struct got_error * request_notification(struct gotd_session_notif *notif) { const struct got_error *err = NULL; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; struct gotd_imsg_notification_content icontent; struct ibuf *wbuf; size_t len; int fd; fd = got_opentempfd(); if (fd == -1) return got_error_from_errno("got_opentemp"); memset(&icontent, 0, sizeof(icontent)); icontent.action = notif->action; memcpy(&icontent.old_id, ¬if->old_id, sizeof(notif->old_id)); memcpy(&icontent.new_id, ¬if->new_id, sizeof(notif->new_id)); icontent.refname_len = strlen(notif->refname); len = sizeof(icontent) + icontent.refname_len; wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY, GOTD_PROC_SESSION_WRITE, gotd_session.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create NOTIFY"); goto done; } if (imsg_add(wbuf, &icontent, sizeof(icontent)) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } if (imsg_add(wbuf, notif->refname, icontent.refname_len) == -1) { err = got_error_from_errno("imsg_add NOTIFY"); goto done; } notif->fd = dup(fd); if (notif->fd == -1) { err = got_error_from_errno("dup"); goto done; } ibuf_fd_set(wbuf, fd); fd = -1; imsg_close(&iev->ibuf, wbuf); gotd_imsg_event_add(iev); done: if (err && fd != -1) close(fd); return err; } static const struct got_error * update_ref(int *shut, struct gotd_session_client *client, const char *repo_path, struct imsg *imsg) { const struct got_error *err = NULL; struct got_repository *repo = gotd_session.repo; struct got_reference *ref = NULL; struct gotd_imsg_ref_update iref; struct got_object_id old_id, new_id; struct got_object_id *id = NULL; char *refname = NULL; size_t datalen; int locked = 0; char hex1[SHA1_DIGEST_STRING_LENGTH]; char hex2[SHA1_DIGEST_STRING_LENGTH]; log_debug("update-ref from uid %d", client->euid); if (client->nref_updates <= 0) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iref)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iref, imsg->data, sizeof(iref)); if (datalen != sizeof(iref) + iref.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); refname = strndup(imsg->data + sizeof(iref), iref.name_len); if (refname == NULL) return got_error_from_errno("strndup"); log_debug("updating ref %s for uid %d", refname, client->euid); memset(&old_id, 0, sizeof(old_id)); memcpy(old_id.hash, iref.old_id, SHA1_DIGEST_LENGTH); memset(&new_id, 0, sizeof(new_id)); memcpy(new_id.hash, iref.new_id, SHA1_DIGEST_LENGTH); err = got_repo_find_object_id(iref.delete_ref ? &old_id : &new_id, repo); if (err) goto done; if (iref.ref_is_new) { err = got_ref_open(&ref, repo, refname, 0); if (err) { if (err->code != GOT_ERR_NOT_REF) goto done; err = got_ref_alloc(&ref, refname, &new_id); if (err) goto done; err = got_ref_write(ref, repo); /* will lock/unlock */ if (err) goto done; err = queue_notification(NULL, &new_id, repo, ref); if (err) goto done; } else { err = got_ref_resolve(&id, repo, ref); if (err) goto done; got_object_id_hex(&new_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Addition %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } } else if (iref.delete_ref) { err = got_ref_open(&ref, repo, refname, 1 /* lock */); if (err) goto done; locked = 1; err = got_ref_resolve(&id, repo, ref); if (err) goto done; if (got_object_id_cmp(id, &old_id) != 0) { got_object_id_hex(&old_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Deletion %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } err = got_ref_delete(ref, repo); if (err) goto done; err = queue_notification(&old_id, NULL, repo, ref); if (err) goto done; free(id); id = NULL; } else { err = got_ref_open(&ref, repo, refname, 1 /* lock */); if (err) goto done; locked = 1; err = got_ref_resolve(&id, repo, ref); if (err) goto done; if (got_object_id_cmp(id, &old_id) != 0) { got_object_id_hex(&old_id, hex1, sizeof(hex1)); got_object_id_hex(id, hex2, sizeof(hex2)); err = got_error_fmt(GOT_ERR_REF_BUSY, "Update %s: %s failed; %s: %s has been " "created by someone else while transaction " "was in progress", got_ref_get_name(ref), hex1, got_ref_get_name(ref), hex2); goto done; } if (got_object_id_cmp(&new_id, &old_id) != 0) { err = got_ref_change_ref(ref, &new_id); if (err) goto done; err = got_ref_write(ref, repo); if (err) goto done; err = queue_notification(&old_id, &new_id, repo, ref); if (err) goto done; } free(id); id = NULL; } done: if (err) { if (err->code == GOT_ERR_LOCKFILE_TIMEOUT) { err = got_error_fmt(GOT_ERR_LOCKFILE_TIMEOUT, "could not acquire exclusive file lock for %s", refname); } send_ref_update_ng(client, &iref, refname, err->msg); } else send_ref_update_ok(client, &iref, refname); if (locked) { const struct got_error *unlock_err; unlock_err = got_ref_unlock(ref); if (unlock_err && err == NULL) err = unlock_err; } if (ref) got_ref_close(ref); free(refname); free(id); return err; } static const struct got_error * recv_notification_content(struct imsg *imsg) { struct gotd_imsg_notification_content inotif; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(inotif)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inotif, imsg->data, sizeof(inotif)); return NULL; } static const struct got_error * report_ref_updates(int do_notify) { const struct got_error *err; struct gotd_session_notif *notif; err = send_refs_updated(&gotd_session.parent_iev); if (err) { log_warn("%s", err->msg); return err; } if (do_notify) { notif = STAILQ_FIRST(¬ifications); if (notif == NULL) return NULL; err = request_notification(notif); if (err) { log_warn("could not send notification: %s", err->msg); return err; } } return NULL; } static void session_dispatch_repo_child(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0; int do_ref_updates = 0, do_ref_update = 0; int do_packfile_verification = 0; int do_content_verification = 0; int packfile_verified = 0; int do_packfile_install = 0, do_notify = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_PACKFILE_RECEIVED: { int pack_empty; err = recv_packfile_received(&pack_empty, &imsg); if (err) break; if (!pack_empty && need_packfile_verification()) do_packfile_verification = 1; else packfile_verified = 1; break; } case GOTD_IMSG_PACKFILE_CONTENT_WRITTEN: { int ref_found; err = recv_content_written(&ref_found, &imsg); if (err == NULL) { if (ref_found) do_content_verification = 1; else packfile_verified = 1; } break; } case GOTD_IMSG_PACKFILE_INSTALL: err = recv_packfile_install(&imsg); if (err == NULL) do_packfile_install = 1; break; case GOTD_IMSG_REF_UPDATES_START: err = recv_ref_updates_start(&imsg); if (err == NULL) do_ref_updates = 1; break; case GOTD_IMSG_REF_UPDATE: err = recv_ref_update(&imsg); if (err == NULL) do_ref_update = 1; break; case GOTD_IMSG_NOTIFY: err = recv_notification_content(&imsg); if (err == NULL) do_notify = 1; break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } if (do_disconnect || err) { if (err) disconnect_on_error(client, err); else disconnect(client); } else { if (do_packfile_verification) { err = verify_packfile(iev); } else if (do_content_verification) { err = verify_gotsys_conf(); } else if (packfile_verified) { err = send_packfile_verified(iev); } else if (do_packfile_install) err = install_pack(client, gotd_session.repo->path, &imsg); else if (do_ref_updates) err = begin_ref_updates(client, &imsg); else if (do_ref_update) err = update_ref(&shut, client, gotd_session.repo->path, &imsg); else if (do_notify) err = forward_notification(client, &imsg); if (err) log_warnx("uid %d: %s", client->euid, err->msg); if (do_ref_update && client->nref_updates > 0) { client->nref_updates--; if (client->nref_updates == 0) { err = report_ref_updates(do_notify); if (err) shut = 1; } } } imsg_free(&imsg); if (err) break; } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_capabilities(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capabilities icapas; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(icapas)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapas, imsg->data, sizeof(icapas)); client->ncapa_alloc = icapas.ncapabilities; client->capabilities = calloc(client->ncapa_alloc, sizeof(*client->capabilities)); if (client->capabilities == NULL) { client->ncapa_alloc = 0; return got_error_from_errno("calloc"); } log_debug("expecting %zu capabilities from uid %d", client->ncapa_alloc, client->euid); return NULL; } static const struct got_error * recv_capability(struct gotd_session_client *client, struct imsg *imsg) { struct gotd_imsg_capability icapa; struct gotd_client_capability *capa; size_t datalen; char *key, *value = NULL; if (client->capabilities == NULL || client->ncapabilities >= client->ncapa_alloc) { return got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); } memset(&icapa, 0, sizeof(icapa)); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(icapa)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&icapa, imsg->data, sizeof(icapa)); if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len) return got_error(GOT_ERR_PRIVSEP_LEN); key = strndup(imsg->data + sizeof(icapa), icapa.key_len); if (key == NULL) return got_error_from_errno("strndup"); if (icapa.value_len > 0) { value = strndup(imsg->data + sizeof(icapa) + icapa.key_len, icapa.value_len); if (value == NULL) { free(key); return got_error_from_errno("strndup"); } } capa = &client->capabilities[client->ncapabilities++]; capa->key = key; capa->value = value; if (value) log_debug("uid %d: capability %s=%s", client->euid, key, value); else log_debug("uid %d: capability %s", client->euid, key); return NULL; } static const struct got_error * forward_ref_update(struct gotd_session_client *client, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_ref_update ireq; struct gotd_imsg_ref_update *iref = NULL; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (datalen != sizeof(ireq) + ireq.name_len) return got_error(GOT_ERR_PRIVSEP_LEN); iref = malloc(datalen); if (iref == NULL) return got_error_from_errno("malloc"); memcpy(iref, imsg->data, datalen); if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_REF_UPDATE, GOTD_PROC_SESSION_WRITE, -1, iref, datalen) == -1) err = got_error_from_errno("imsg compose REF_UPDATE"); free(iref); return err; } static int client_has_capability(struct gotd_session_client *client, const char *capastr) { struct gotd_client_capability *capa; size_t i; if (client->ncapabilities == 0) return 0; for (i = 0; i < client->ncapabilities; i++) { capa = &client->capabilities[i]; if (strcmp(capa->key, capastr) == 0) return 1; } return 0; } static const struct got_error * recv_packfile(struct gotd_session_client *client) { const struct got_error *err = NULL; int pipe[2] = { -1, -1 }; if (client->packfile_path) { return got_error_fmt(GOT_ERR_PRIVSEP_MSG, "uid %d already has a pack file", client->euid); } if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1) return got_error_from_errno("socketpair"); /* * Send pack data pipe end 0 to gotsh(1) (expects just an fd, no data). * * We will forward the other pipe end to the repo_write process only * once we have confirmation that gotsh(1) has received its end. */ if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_PACKFILE_PIPE, GOTD_PROC_GOTD, pipe[0], NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKFILE_PIPE"); goto done; } pipe[0] = -1; gotd_session.repo_child_packfd = pipe[1]; pipe[1] = -1; done: if (pipe[0] != -1 && close(pipe[0]) == -1 && err == NULL) err = got_error_from_errno("close"); if (pipe[1] != -1 && close(pipe[1]) == -1 && err == NULL) err = got_error_from_errno("close"); return err; } static const struct got_error * send_packfds_to_repo_child(void) { const struct got_error *err = NULL; struct gotd_session_client *client = &gotd_session_client; char *basepath = NULL, *pack_path = NULL, *idx_path = NULL; int packfd = -1, idxfd = -1; struct gotd_imsg_recv_packfile ipack; /* * gotsh(1) has received its end of the pack pipe. * Send pack pipe end 1 to repo child process. */ if (gotd_imsg_compose_event( &gotd_session.repo_child_iev, GOTD_IMSG_PACKFILE_PIPE, GOTD_PROC_SESSION_WRITE, gotd_session.repo_child_packfd, NULL, 0) == -1) return got_error_from_errno("imsg compose PACKFILE_PIPE"); gotd_session.repo_child_packfd = -1; if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.pack", got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR, client->euid) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = got_opentemp_named_fd(&pack_path, &packfd, basepath, ""); if (err) goto done; if (fchmod(packfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", pack_path); goto done; } free(basepath); if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.idx", got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR, client->euid) == -1) { err = got_error_from_errno("asprintf"); basepath = NULL; goto done; } err = got_opentemp_named_fd(&idx_path, &idxfd, basepath, ""); if (err) goto done; if (fchmod(idxfd, GOT_DEFAULT_PACK_MODE) == -1) { err = got_error_from_errno2("fchmod", idx_path); goto done; } if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_PACKIDX_FILE, GOTD_PROC_SESSION_WRITE, idxfd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose PACKIDX_FILE"); goto done; } idxfd = -1; memset(&ipack, 0, sizeof(ipack)); if (client_has_capability(client, GOT_CAPA_REPORT_STATUS)) ipack.report_status = 1; if (gotd_imsg_compose_event(&gotd_session.repo_child_iev, GOTD_IMSG_RECV_PACKFILE, GOTD_PROC_SESSION_WRITE, packfd, &ipack, sizeof(ipack)) == -1) { err = got_error_from_errno("imsg compose RECV_PACKFILE"); goto done; } packfd = -1; done: free(basepath); if (packfd != -1 && close(packfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (idxfd != -1 && close(idxfd) == -1 && err == NULL) err = got_error_from_errno("close"); if (err) { free(pack_path); free(idx_path); } else { client->packfile_path = pack_path; client->packidx_path = idx_path; } return err; } static void session_dispatch_client(int fd, short events, void *arg) { struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_session_client *client = &gotd_session_client; const struct got_error *err = NULL; struct imsg imsg; ssize_t n; if (events & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { /* * The client has closed its socket. This can * happen when Git clients are done sending * pack file data. * Pending notifications should still be sent. */ if (STAILQ_FIRST(¬ifications) != NULL) return; if (err->code == GOT_ERR_ERRNO && errno == EPIPE) { disconnect(client); return; } disconnect_on_error(client, err); return; } if (client->flush_disconnect) { disconnect(client); return; } } if (events & EV_READ) { n = imsgbuf_read(ibuf); if (n == -1) { err = got_error_from_errno("imsgbuf_read"); disconnect_on_error(client, err); return; } if (n == 0) { /* * The client has closed its socket. This can * happen when Git clients are done sending * pack file data. * Pending notifications should still be sent. */ if (STAILQ_FIRST(¬ifications) != NULL) return; err = got_error(GOT_ERR_EOF); disconnect_on_error(client, err); return; } } while (err == NULL) { n = imsg_get(ibuf, &imsg); if (n == -1) { err = got_error_from_errno("imsg_get"); break; } if (n == 0) break; evtimer_del(&client->tmo); switch (imsg.hdr.type) { case GOTD_IMSG_CAPABILITIES: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capabilities received"); break; } log_debug("receiving capabilities from uid %d", client->euid); err = recv_capabilities(client, &imsg); break; case GOTD_IMSG_CAPABILITY: if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected capability received"); break; } err = recv_capability(client, &imsg); if (err || client->ncapabilities < client->ncapa_alloc) break; gotd_session.state = GOTD_STATE_EXPECT_REF_UPDATE; client->accept_flush_pkt = 1; log_debug("uid %d: expecting ref-update-lines", client->euid); break; case GOTD_IMSG_REF_UPDATE: if (gotd_session.state != GOTD_STATE_EXPECT_REF_UPDATE && gotd_session.state != GOTD_STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected ref-update-line received"); break; } log_debug("received ref-update-line from uid %d", client->euid); err = forward_ref_update(client, &imsg); if (err) break; gotd_session.state = GOTD_STATE_EXPECT_MORE_REF_UPDATES; client->accept_flush_pkt = 1; break; case GOTD_IMSG_FLUSH: if (gotd_session.state != GOTD_STATE_EXPECT_MORE_REF_UPDATES) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } if (!client->accept_flush_pkt) { err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected flush-pkt received"); break; } /* * Accept just one flush packet at a time. * Future client state transitions will set this flag * again if another flush packet is expected. */ client->accept_flush_pkt = 0; log_debug("received flush-pkt from uid %d", client->euid); if (gotd_session.state == GOTD_STATE_EXPECT_MORE_REF_UPDATES) { gotd_session.state = GOTD_STATE_EXPECT_PACKFILE; log_debug("uid %d: expecting packfile", client->euid); err = recv_packfile(client); } else { /* should not happen, see above */ err = got_error_msg(GOT_ERR_BAD_REQUEST, "unexpected client state"); break; } break; case GOTD_IMSG_PACKFILE_READY: if (gotd_session.state != GOTD_STATE_EXPECT_PACKFILE || gotd_session.repo_child_packfd == -1) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = send_packfds_to_repo_child(); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); err = got_error(GOT_ERR_PRIVSEP_MSG); break; } imsg_free(&imsg); } if (err) { if (err->code != GOT_ERR_EOF || (gotd_session.state != GOTD_STATE_EXPECT_PACKFILE && gotd_session.state != GOTD_STATE_NOTIFY)) disconnect_on_error(client, err); } else { gotd_imsg_event_add(iev); evtimer_add(&client->tmo, &gotd_session.request_timeout); } } static const struct got_error * list_refs_request(void) { static const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = &gotd_session.repo_child_iev; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); fd = dup(client->fd); if (fd == -1) return got_error_from_errno("dup"); if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL, GOTD_PROC_SESSION_WRITE, fd, NULL, 0) == -1) { err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL"); close(fd); return err; } gotd_session.state = GOTD_STATE_EXPECT_CAPABILITIES; log_debug("uid %d: expecting capabilities", client->euid); return NULL; } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_session_client *client = &gotd_session_client; struct gotd_imsg_connect iconnect; size_t datalen; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(iconnect)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iconnect, imsg->data, sizeof(iconnect)); if (iconnect.username_len == 0 || datalen != sizeof(iconnect) + iconnect.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); client->euid = iconnect.euid; client->egid = iconnect.egid; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->username = strndup(imsg->data + sizeof(iconnect), iconnect.username_len); if (client->username == NULL) return got_error_from_errno("strndup"); if (imsgbuf_init(&client->iev.ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&client->iev.ibuf); client->iev.handler = session_dispatch_client; client->iev.events = EV_READ; client->iev.handler_arg = NULL; event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ, session_dispatch_client, &client->iev); gotd_imsg_event_add(&client->iev); evtimer_set(&client->tmo, gotd_request_timeout, client); evtimer_add(&client->tmo, &gotd_session.request_timeout); return NULL; } static void session_dispatch_notifier(int fd, short event, void *arg) { const struct got_error *err; struct gotd_session_client *client = &gotd_session_client; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; struct gotd_session_notif *notif; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFICATION_SENT: if (gotd_session.state != GOTD_STATE_NOTIFY) { log_warn("unexpected imsg %d", imsg.hdr.type); break; } /* First notification on our list has now been sent. */ notif = STAILQ_FIRST(¬ifications); STAILQ_REMOVE_HEAD(¬ifications, entry); if (notif->fd != -1) close(notif->fd); free(notif); notif = STAILQ_FIRST(¬ifications); if (notif == NULL) { disconnect(client); break; /* NOTREACHED */ } /* Request content for the next notification. */ err = request_notification(notif); if (err) { log_warn("could not send notification: %s", err->msg); disconnect(client); } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); imsgbuf_clear(&iev->ibuf); } } static const struct got_error * recv_notifier(struct imsg *imsg) { struct gotd_imsgev *iev = &gotd_session.notifier_iev; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return NULL; /* notifications unused */ if (imsgbuf_init(&iev->ibuf, fd) == -1) { close(fd); return got_error_from_errno("imsgbuf_init"); } imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = session_dispatch_notifier; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, session_dispatch_notifier, iev); gotd_imsg_event_add(iev); return NULL; } static const struct got_error * recv_repo_child(struct imsg *imsg) { struct gotd_imsg_connect_repo_child ichild; struct gotd_session_client *client = &gotd_session_client; size_t datalen; int fd; if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS) return got_error(GOT_ERR_PRIVSEP_MSG); /* We should already have received a pipe to the listener. */ if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_MSG); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ichild)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ichild, imsg->data, sizeof(ichild)); if (ichild.proc_id != GOTD_PROC_REPO_WRITE) return got_error_msg(GOT_ERR_PRIVSEP_MSG, "bad child process type"); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (strlcpy(gotd_session.repo_name, ichild.repo_name, sizeof(gotd_session.repo_name)) >= sizeof(gotd_session.repo_name)) { return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } if (imsgbuf_init(&gotd_session.repo_child_iev.ibuf, fd) == -1) { close(fd); return got_error_from_errno("imsgbuf_init"); } imsgbuf_allow_fdpass(&gotd_session.repo_child_iev.ibuf); gotd_session.repo_child_iev.handler = session_dispatch_repo_child; gotd_session.repo_child_iev.events = EV_READ; gotd_session.repo_child_iev.handler_arg = NULL; event_set(&gotd_session.repo_child_iev.ev, gotd_session.repo_child_iev.ibuf.fd, EV_READ, session_dispatch_repo_child, &gotd_session.repo_child_iev); gotd_imsg_event_add(&gotd_session.repo_child_iev); /* The "recvfd" pledge promise is no longer needed. */ if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1) fatal("pledge"); return NULL; } static void session_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_imsgev *repo_child_iev = &gotd_session.repo_child_iev; struct gotd_session_client *client = &gotd_session_client; ssize_t n; int shut = 0; struct imsg imsg; size_t npaths; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; uint32_t client_id = 0; int do_disconnect = 0, do_list_refs = 0; int send_notifications = 0; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_ERROR: do_disconnect = 1; err = gotd_imsg_recv_error(&client_id, &imsg); break; case GOTD_IMSG_CONNECT: err = recv_connect(&imsg); break; case GOTD_IMSG_DISCONNECT: do_disconnect = 1; break; case GOTD_IMSG_NOTIFICATION_REFS: if (gotd_session.notification_refs_cur != NULL || gotd_session.num_notification_refs_needed != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist(&npaths, &imsg); if (err) break; gotd_session.notification_refs_cur = &gotd_session.notification_refs; gotd_session.num_notification_refs_needed = npaths; gotd_session.num_notification_refs_received = 0; break; case GOTD_IMSG_NOTIFICATION_REF_NAMESPACES: if (gotd_session.notification_refs_cur != NULL || gotd_session.num_notification_refs_needed != 0) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist(&npaths, &imsg); if (err) break; gotd_session.notification_refs_cur = &gotd_session.notification_ref_namespaces; gotd_session.num_notification_refs_needed = npaths; gotd_session.num_notification_refs_received = 0; break; case GOTD_IMSG_NOTIFICATION_REFS_ELEM: case GOTD_IMSG_NOTIFICATION_REF_NAMESPACES_ELEM: if (gotd_session.notification_refs_cur == NULL || gotd_session.num_notification_refs_needed == 0 || gotd_session.num_notification_refs_received >= gotd_session.num_notification_refs_needed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } err = gotd_imsg_recv_pathlist_elem(&imsg, gotd_session.notification_refs_cur); if (err) break; if (++gotd_session.num_notification_refs_received >= gotd_session.num_notification_refs_needed) { gotd_session.notification_refs_cur = NULL; gotd_session.num_notification_refs_needed = 0; } break; case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: { struct gotd_notification_target *target; err = gotd_imsg_recv_notification_target_email(NULL, &target, &imsg); if (err) break; STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry); break; } case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: { struct gotd_notification_target *target; err = gotd_imsg_recv_notification_target_http(NULL, &target, &imsg); if (err) break; STAILQ_INSERT_TAIL(&gotd_session.notification_targets, target, entry); break; } case GOTD_IMSG_REQUEST_TIMEOUT: if (imsg_get_data(&imsg, &gotd_session.request_timeout, sizeof(gotd_session.request_timeout)) == -1) err = got_error_from_errno("imsg_get_data"); break; case GOTD_IMSG_CONNECT_NOTIFIER: err = recv_notifier(&imsg); break; case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_repo_child(&imsg); if (err) break; do_list_refs = 1; break; case GOTD_IMSG_NOTIFY: send_notifications = 1; break; case GOTD_IMSG_PACKFILE_VERIFIED: if (gotd_session.state != GOTD_STATE_EXPECT_PACKFILE) { err = got_error(GOT_ERR_PRIVSEP_MSG); do_disconnect = 1; break; } if (repo_child_iev->ibuf.fd == -1) { err = got_error(GOT_ERR_PRIVSEP_MSG); do_disconnect = 1; break; } if (gotd_imsg_forward(repo_child_iev, &imsg, -1) == -1) { err = got_error_from_errno("imsg compose " " PACKFILE_VERIFIED"); do_disconnect = 1; } break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (do_disconnect) { if (err) disconnect_on_error(client, err); else disconnect(client); } else if (do_list_refs) err = list_refs_request(); else if (send_notifications) { struct gotd_session_notif *notif; err = send_refs_updated(&client->iev); if (err) { log_warnx("uid %d: %s", client->euid, err->msg); err = NULL; } notif = STAILQ_FIRST(¬ifications); if (notif) { gotd_session.state = GOTD_STATE_NOTIFY; err = request_notification(notif); if (err) { log_warn("could not send notification: " "%s", err->msg); client->flush_disconnect = 1; } } else client->flush_disconnect = 1; } if (err) log_warnx("uid %d: %s", client->euid, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void session_write_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds, int content_fd) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; STAILQ_INIT(¬ifications); gotd_session.title = title; gotd_session.pid = getpid(); gotd_session.pack_fds = pack_fds; gotd_session.temp_fds = temp_fds; gotd_session.content_fd = content_fd; gotd_session.request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd_session.request_timeout.tv_usec = 0; RB_INIT(&gotd_session.notification_refs); RB_INIT(&gotd_session.notification_ref_namespaces); STAILQ_INIT(&gotd_session.notification_targets); gotd_session.repo_child_packfd = -1; if (imsgbuf_init(&gotd_session.notifier_iev.ibuf, -1) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&gotd_session.notifier_iev.ibuf); err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(gotd_session.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } if (got_repo_get_object_format(gotd_session.repo) != GOT_HASH_SHA1) { err = got_error_msg(GOT_ERR_NOT_IMPL, "sha256 object IDs unsupported in network protocol"); goto done; } got_repo_temp_fds_set(gotd_session.repo, temp_fds); signal_set(&evsigint, SIGINT, session_write_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, session_write_sighdlr, NULL); signal_set(&evsighup, SIGHUP, session_write_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, session_write_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); gotd_session.state = GOTD_STATE_EXPECT_LIST_REFS; gotd_session_client.fd = -1; gotd_session_client.nref_updates = -1; gotd_session_client.delta_cache_fd = -1; gotd_session_client.accept_flush_pkt = 1; gotd_session.repo_child_iev.ibuf.fd = -1; if (imsgbuf_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&gotd_session.parent_iev.ibuf); gotd_session.parent_iev.handler = session_dispatch; gotd_session.parent_iev.events = EV_READ; gotd_session.parent_iev.handler_arg = NULL; event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd, EV_READ, session_dispatch, &gotd_session.parent_iev); if (gotd_imsg_compose_event(&gotd_session.parent_iev, GOTD_IMSG_CLIENT_SESSION_READY, GOTD_PROC_SESSION_WRITE, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose CLIENT_SESSION_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); session_write_shutdown(); } static void session_write_shutdown(void) { struct gotd_session_notif *notif; log_debug("%s: shutting down", gotd_session.title); while (!STAILQ_EMPTY(¬ifications)) { notif = STAILQ_FIRST(¬ifications); STAILQ_REMOVE_HEAD(¬ifications, entry); if (notif->fd != -1) close(notif->fd); free(notif->refname); free(notif); } if (gotd_session.repo) got_repo_close(gotd_session.repo); got_repo_pack_fds_close(gotd_session.pack_fds); got_repo_temp_fds_close(gotd_session.temp_fds); free(gotd_session_client.username); exit(0); } got-portable-0.119/gotd/Makefile.am0000664000175000017500000000466715066536113012622 sbin_PROGRAMS = gotd SUBDIRS=libexec include $(top_builddir)/Makefile.common AM_CPPFLAGS += -DGOTD_EMPTY_PATH='"@GOTD_EMPTY_PATHC@"' gotd_SOURCES = gotd.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotd_imsg.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ auth.c \ imsg.c \ listen.c \ notify.c \ parse.y \ privsep_stub.c \ repo_imsg.c \ repo_read.c \ repo_write.c \ secrets.c \ session_read.c \ session_write.c if !HOST_OPENBSD gotd_SOURCES += chroot-notobsd.c else gotd_SOURCES += chroot-openbsd.c endif gotd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotd.8 gotd.conf.5 gotd-secrets.conf.5 *.h man5_MANS = gotd.conf.5 gotd-secrets.conf.5 man8_MANS = gotd.8 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm LDADD += $(libuuid_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ $(libevent_LIBS) \ $(libutil_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libuuid_CFLAGS) \ $(zlib_CFLAGS) \ $(libbsd_CFLAGS) \ $(libevent_CFLAGS) got-portable-0.119/gotd/notify.c0000664000175000017500000003773115066536113012240 /* * Copyright (c) 2024 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "gotd.h" #include "log.h" #include "notify.h" #include "secrets.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct gotd_secrets secrets; static struct gotd_notify { pid_t pid; const char *title; struct gotd_imsgev parent_iev; struct gotd_repolist repos; } gotd_notify; struct gotd_notify_session { STAILQ_ENTRY(gotd_notify_session) entry; uint32_t id; struct gotd_imsgev iev; }; STAILQ_HEAD(gotd_notify_sessions, gotd_notify_session); static struct gotd_notify_sessions gotd_notify_sessions[GOTD_CLIENT_TABLE_SIZE]; static SIPHASH_KEY sessions_hash_key; static void gotd_notify_shutdown(void); static void sessions_init(void) { uint64_t slot; arc4random_buf(&sessions_hash_key, sizeof(sessions_hash_key)); for (slot = 0; slot < nitems(gotd_notify_sessions); slot++) STAILQ_INIT(&gotd_notify_sessions[slot]); } static uint64_t session_hash(uint32_t session_id) { return SipHash24(&sessions_hash_key, &session_id, sizeof(session_id)); } static void add_session(struct gotd_notify_session *session) { uint64_t slot; slot = session_hash(session->id) % nitems(gotd_notify_sessions); STAILQ_INSERT_HEAD(&gotd_notify_sessions[slot], session, entry); } static struct gotd_notify_session * find_session(uint32_t session_id) { uint64_t slot; struct gotd_notify_session *s; slot = session_hash(session_id) % nitems(gotd_notify_sessions); STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) { if (s->id == session_id) return s; } return NULL; } static struct gotd_notify_session * find_session_by_fd(int fd) { uint64_t slot; struct gotd_notify_session *s; for (slot = 0; slot < nitems(gotd_notify_sessions); slot++) { STAILQ_FOREACH(s, &gotd_notify_sessions[slot], entry) { if (s->iev.ibuf.fd == fd) return s; } } return NULL; } static void remove_session(struct gotd_notify_session *session) { uint64_t slot; slot = session_hash(session->id) % nitems(gotd_notify_sessions); STAILQ_REMOVE(&gotd_notify_sessions[slot], session, gotd_notify_session, entry); close(session->iev.ibuf.fd); free(session); } static uint32_t get_session_id(void) { int duplicate = 0; uint32_t id; do { id = arc4random(); duplicate = (find_session(id) != NULL); } while (duplicate || id == 0); return id; } static void gotd_notify_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: gotd_notify_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static void run_notification_helper(const char *prog, const char **argv, int fd, const char *user, const char *pass, const char *hmac_secret) { const struct got_error *err = NULL; pid_t pid; int child_status; pid = fork(); if (pid == -1) { err = got_error_from_errno("fork"); log_warn("%s", err->msg); return; } else if (pid == 0) { signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGCHLD, SIG_DFL); if (dup2(fd, STDIN_FILENO) == -1) { fprintf(stderr, "%s: dup2: %s\n", getprogname(), strerror(errno)); _exit(1); } closefrom(STDERR_FILENO + 1); if (user != NULL && pass != NULL) { setenv("GOT_NOTIFY_HTTP_USER", user, 1); setenv("GOT_NOTIFY_HTTP_PASS", pass, 1); } else { unsetenv("GOTD_NOTIFY_HTTP_USER"); unsetenv("GOTD_NOTIFY_HTTP_PASS"); } if (hmac_secret) setenv("GOT_NOTIFY_HTTP_HMAC_SECRET", hmac_secret, 1); else unsetenv("GOT_NOTIFY_HTTP_HMAC_SECRET"); if (execv(prog, (char *const *)argv) == -1) { fprintf(stderr, "%s: exec %s: %s\n", getprogname(), prog, strerror(errno)); _exit(1); } /* not reached */ } if (waitpid(pid, &child_status, 0) == -1) { err = got_error_from_errno("waitpid"); goto done; } if (!WIFEXITED(child_status)) { err = got_error(GOT_ERR_PRIVSEP_DIED); goto done; } if (WEXITSTATUS(child_status) != 0) err = got_error(GOT_ERR_PRIVSEP_EXIT); done: if (err) log_warnx("%s: child %s pid %d: %s", gotd_notify.title, prog, pid, err->msg); } static void notify_email(struct gotd_notification_target *target, const char *subject_line, int fd) { const char *argv[13]; int i = 0; argv[i++] = GOTD_PATH_PROG_NOTIFY_EMAIL; argv[i++] = "-f"; argv[i++] = target->conf.email.sender; if (target->conf.email.responder) { argv[i++] = "-r"; argv[i++] = target->conf.email.responder; } if (target->conf.email.hostname) { argv[i++] = "-h"; argv[i++] = target->conf.email.hostname; } if (target->conf.email.port) { argv[i++] = "-p"; argv[i++] = target->conf.email.port; } argv[i++] = "-s"; argv[i++] = subject_line; argv[i++] = target->conf.email.recipient; argv[i] = NULL; run_notification_helper(GOTD_PATH_PROG_NOTIFY_EMAIL, argv, fd, NULL, NULL, NULL); } static void notify_http(struct gotd_notification_target *target, const char *repo, const char *username, int fd) { struct gotd_secret *secret; const char *http_user = NULL, *http_pass = NULL, *hmac = NULL; const char *argv[12]; int argc = 0; argv[argc++] = GOTD_PATH_PROG_NOTIFY_HTTP; if (target->conf.http.tls) argv[argc++] = "-c"; argv[argc++] = "-r"; argv[argc++] = repo; argv[argc++] = "-h"; argv[argc++] = target->conf.http.hostname; argv[argc++] = "-p"; argv[argc++] = target->conf.http.port; argv[argc++] = "-u"; argv[argc++] = username; argv[argc++] = target->conf.http.path; argv[argc] = NULL; if (target->conf.http.auth) { secret = gotd_secrets_get(&secrets, GOTD_SECRET_AUTH, target->conf.http.auth); http_user = secret->user; http_pass = secret->pass; } if (target->conf.http.hmac) { secret = gotd_secrets_get(&secrets, GOTD_SECRET_HMAC, target->conf.http.hmac); hmac = secret->hmac; } run_notification_helper(GOTD_PATH_PROG_NOTIFY_HTTP, argv, fd, http_user, http_pass, hmac); } static const struct got_error * send_notification(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct gotd_imsg_notify inotify; size_t datalen; struct gotd_repo *repo; struct gotd_notification_target *target; int fd; char *username = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(inotify)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&inotify, imsg->data, sizeof(inotify)); if (datalen != sizeof(inotify) + inotify.username_len) return got_error(GOT_ERR_PRIVSEP_LEN); repo = gotd_find_repo_by_name(inotify.repo_name, &gotd_notify.repos); if (repo == NULL) return got_error(GOT_ERR_PRIVSEP_MSG); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); username = strndup(imsg->data + sizeof(inotify), inotify.username_len); if (username == NULL) return got_error_from_errno("strndup"); STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (lseek(fd, 0, SEEK_SET) == -1) { err = got_error_from_errno("lseek"); goto done; } switch (target->type) { case GOTD_NOTIFICATION_VIA_EMAIL: notify_email(target, inotify.subject_line, fd); break; case GOTD_NOTIFICATION_VIA_HTTP: notify_http(target, repo->name, username, fd); break; } } if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFICATION_SENT, GOTD_PROC_NOTIFY, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose NOTIFY"); goto done; } done: close(fd); free(username); return err; } static void notify_dispatch_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) { if (err->code != GOT_ERR_ERRNO || errno != EPIPE) fatalx("%s", err->msg); shut = 1; goto done; } } for (;;) { const struct got_error *err = NULL; if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFY: err = send_notification(&imsg, iev); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (err) log_warnx("%s: %s", __func__, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { struct gotd_notify_session *session; /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); imsgbuf_clear(&iev->ibuf); session = find_session_by_fd(fd); if (session) remove_session(session); } } static const struct got_error * recv_session(struct imsg *imsg) { struct gotd_notify_session *session; size_t datalen; int fd; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); session = calloc(1, sizeof(*session)); if (session == NULL) { close(fd); return got_error_from_errno("calloc"); } session->id = get_session_id(); if (imsgbuf_init(&session->iev.ibuf, fd) == -1) { close(fd); return got_error_from_errno("imsgbuf_init"); } imsgbuf_allow_fdpass(&session->iev.ibuf); session->iev.handler = notify_dispatch_session; session->iev.events = EV_READ; session->iev.handler_arg = NULL; event_set(&session->iev.ev, session->iev.ibuf.fd, EV_READ, notify_dispatch_session, &session->iev); gotd_imsg_event_add(&session->iev); add_session(session); return NULL; } static const struct got_error * notify_ibuf_get_str(char **ret, struct ibuf *ibuf) { const char *str, *end; size_t len; *ret = NULL; str = ibuf_data(ibuf); len = ibuf_size(ibuf); end = memchr(str, '\0', len); if (end == NULL) return got_error(GOT_ERR_PRIVSEP_LEN); *ret = strdup(str); if (*ret == NULL) return got_error_from_errno("strdup"); if (ibuf_skip(ibuf, end - str + 1) == -1) { free(*ret); *ret = NULL; return got_error(GOT_ERR_PRIVSEP_LEN); } return NULL; } static const struct got_error * add_notification_target(const char *repo_name, struct gotd_notification_target *target) { const struct got_error *err = NULL; struct gotd_repo *repo; repo = gotd_find_repo_by_name(repo_name, &gotd_notify.repos); if (repo == NULL) { err = gotd_conf_new_repo(&repo, repo_name); if (err) return err; TAILQ_INSERT_TAIL(&gotd_notify.repos, repo, entry); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); return NULL; } static void notify_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *imsgbuf = &iev->ibuf; ssize_t n; int shut = 0; struct imsg imsg; struct ibuf ibuf; struct gotd_secret *s; if (event & EV_READ) { if ((n = imsgbuf_read(imsgbuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) { /* Connection closed. */ shut = 1; goto done; } } if (event & EV_WRITE) { err = gotd_imsg_flush(imsgbuf); if (err) fatalx("%s", err->msg); } for (;;) { const struct got_error *err = NULL; if ((n = imsg_get(imsgbuf, &imsg)) == -1) fatal("%s: imsg_get error", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_NOTIFICATION_TARGET_EMAIL: { struct gotd_notification_target *target; char *repo_name; err = gotd_imsg_recv_notification_target_email( &repo_name, &target, &imsg); if (err) break; err = add_notification_target(repo_name, target); if (err) gotd_free_notification_target(target); break; } case GOTD_IMSG_NOTIFICATION_TARGET_HTTP: { struct gotd_notification_target *target; char *repo_name; err = gotd_imsg_recv_notification_target_http( &repo_name, &target, &imsg); if (err) break; err = add_notification_target(repo_name, target); if (err) gotd_free_notification_target(target); break; } case GOTD_IMSG_CONNECT_SESSION: err = recv_session(&imsg); break; case GOTD_IMSG_SECRETS: if (secrets.cap != 0) fatal("unexpected GOTD_IMSG_SECRETS"); if (imsg_get_data(&imsg, &secrets.cap, sizeof(secrets.cap)) == -1) fatalx("corrupted GOTD_IMSG_SECRETS"); if (secrets.cap == 0) break; secrets.secrets = calloc(secrets.cap, sizeof(*secrets.secrets)); if (secrets.secrets == NULL) fatal("calloc"); break; case GOTD_IMSG_SECRET: if (secrets.len == secrets.cap) fatalx("unexpected GOTD_SECRET_AUTH"); s = &secrets.secrets[secrets.len++]; if (imsg_get_ibuf(&imsg, &ibuf) == -1) fatal("imsg_get_ibuf"); if (ibuf_get(&ibuf, &s->type, sizeof(s->type)) == -1) fatalx("corrupted GOTD_IMSG_SECRET"); err = notify_ibuf_get_str(&s->label, &ibuf); if (err) break; if (s->type == GOTD_SECRET_AUTH) { err = notify_ibuf_get_str(&s->user, &ibuf); if (err) break; err = notify_ibuf_get_str(&s->pass, &ibuf); if (err) break; } else { err = notify_ibuf_get_str(&s->hmac, &ibuf); if (err) break; } if (ibuf_size(&ibuf) != 0) fatalx("unexpected extra data in " "GOTD_IMSG_SECRET"); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); if (err) log_warnx("%s: %s", __func__, err->msg); } done: if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void notify_main(const char *title) { const struct got_error *err = NULL; struct event evsigint, evsigterm, evsighup, evsigusr1; sessions_init(); gotd_notify.title = title; gotd_notify.pid = getpid(); TAILQ_INIT(&gotd_notify.repos); signal_set(&evsigint, SIGINT, gotd_notify_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, gotd_notify_sighdlr, NULL); signal_set(&evsighup, SIGHUP, gotd_notify_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, gotd_notify_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); if (imsgbuf_init(&gotd_notify.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&gotd_notify.parent_iev.ibuf); gotd_notify.parent_iev.handler = notify_dispatch; gotd_notify.parent_iev.events = EV_READ; gotd_notify.parent_iev.handler_arg = NULL; event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd, EV_READ, notify_dispatch, &gotd_notify.parent_iev); if (gotd_imsg_compose_event(&gotd_notify.parent_iev, GOTD_IMSG_NOTIFIER_READY, GOTD_PROC_NOTIFY, -1, NULL, 0) == -1) fatal("imsg compose NOTIFIER_READY"); event_dispatch(); if (err) log_warnx("%s: %s", title, err->msg); gotd_notify_shutdown(); } void gotd_notify_shutdown(void) { log_debug("%s: shutting down", gotd_notify.title); exit(0); } got-portable-0.119/gotd/parse.y0000664000175000017500000011666515066536113012074 /* * Copyright (c) 2022 Stefan Sperling * Copyright (c) 2016-2019, 2020-2021 Tracey Emery * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_reference.h" #include "log.h" #include "gotd.h" #include "auth.h" #include "listen.h" #include "secrets.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int, int, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); static char *port_sprintf(int); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotd *gotd; static struct gotd_repo *new_repo; static int conf_limit_user_connections(const char *, int); static struct gotd_repo *conf_new_repo(const char *); static void conf_new_access_rule(struct gotd_repo *, enum gotd_access, int, char *); static int conf_protect_ref_namespace(char **, struct got_pathlist_head *, char *); static int conf_protect_tag_namespace(struct gotd_repo *, char *); static int conf_protect_branch_namespace( struct gotd_repo *, char *); static int conf_protect_branch(struct gotd_repo *, char *); static int conf_notify_branch(struct gotd_repo *, char *); static int conf_notify_ref_namespace(struct gotd_repo *, char *); static int conf_notify_email(struct gotd_repo *, char *, char *, char *, char *, char *); static int conf_notify_http(struct gotd_repo *, char *, char *, char *, int); static enum gotd_procid gotd_proc_id; typedef struct { union { long long number; char *string; struct timeval tv; } v; int lineno; } YYSTYPE; %} %token PATH ERROR LISTEN ON USER REPOSITORY PERMIT DENY %token RO RW CONNECTION LIMIT REQUEST TIMEOUT %token PROTECT NAMESPACE BRANCH TAG REFERENCE RELAY PORT %token NOTIFY EMAIL FROM REPLY TO URL INSECURE HMAC AUTH %token STRING %token NUMBER %type timeout %type numberstring %% grammar : | grammar '\n' | grammar varset '\n' | grammar main '\n' | grammar repository '\n' ; varset : STRING '=' STRING { char *s = $1; while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free($1); free($3); YYERROR; } } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); free($3); } ; numberstring : STRING | NUMBER { if (asprintf(&$$, "%lld", (long long)$1) == -1) { yyerror("asprintf: %s", strerror(errno)); YYERROR; } } ; timeout : NUMBER { if ($1 < 0) { yyerror("invalid timeout: %lld", $1); YYERROR; } $$.tv_sec = $1; $$.tv_usec = 0; } | STRING { const char *errstr; const char *type = "seconds"; size_t len; int mul = 1; if (*$1 == '\0') { yyerror("invalid number of seconds: %s", $1); free($1); YYERROR; } len = strlen($1); switch ($1[len - 1]) { case 'S': case 's': $1[len - 1] = '\0'; break; case 'M': case 'm': type = "minutes"; mul = 60; $1[len - 1] = '\0'; break; case 'H': case 'h': type = "hours"; mul = 60 * 60; $1[len - 1] = '\0'; break; } $$.tv_usec = 0; $$.tv_sec = strtonum($1, 0, INT_MAX / mul, &errstr); if (errstr) { yyerror("number of %s is %s: %s", type, errstr, $1); free($1); YYERROR; } $$.tv_sec *= mul; free($1); } ; main : LISTEN ON STRING { if (!got_path_is_absolute($3)) yyerror("bad unix socket path \"%s\": " "must be an absolute path", $3); if (gotd_proc_id == GOTD_PROC_GOTD) { if (strlcpy(gotd->unix_socket_path, $3, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { yyerror("%s: unix socket path too long", __func__); free($3); YYERROR; } } free($3); } | USER numberstring { if (strlcpy(gotd->user_name, $2, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { yyerror("%s: user name too long", __func__); free($2); YYERROR; } free($2); } | connection ; connection : CONNECTION '{' optnl conflags_l '}' | CONNECTION conflags conflags_l : conflags optnl conflags_l | conflags optnl ; conflags : REQUEST TIMEOUT timeout { if ($3.tv_sec <= 0) { yyerror("invalid timeout: %lld", (long long)$3.tv_sec); YYERROR; } memcpy(&gotd->request_timeout, &$3, sizeof(gotd->request_timeout)); } | LIMIT USER STRING NUMBER { if (gotd_proc_id == GOTD_PROC_GOTD && conf_limit_user_connections($3, $4) == -1) { free($3); YYERROR; } free($3); } ; protect : PROTECT '{' optnl protectflags_l '}' | PROTECT protectflags protectflags_l : protectflags optnl protectflags_l | protectflags optnl ; protectflags : TAG NAMESPACE STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_tag_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | BRANCH NAMESPACE STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | BRANCH STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_protect_branch(new_repo, $2)) { free($2); YYERROR; } } free($2); } ; notify : NOTIFY '{' optnl notifyflags_l '}' | NOTIFY notifyflags notifyflags_l : notifyflags optnl notifyflags_l | notifyflags optnl ; notifyflags : BRANCH STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_branch(new_repo, $2)) { free($2); YYERROR; } } free($2); } | REFERENCE NAMESPACE STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_ref_namespace(new_repo, $3)) { free($3); YYERROR; } } free($3); } | EMAIL TO STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, NULL, NULL)) { free($3); YYERROR; } } free($3); } | EMAIL FROM STRING TO STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, NULL, NULL)) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL TO STRING REPLY TO STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, NULL, NULL)) { free($3); free($6); YYERROR; } } free($3); free($6); } | EMAIL FROM STRING TO STRING REPLY TO STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, NULL, NULL)) { free($3); free($5); free($8); YYERROR; } } free($3); free($5); free($8); } | EMAIL TO STRING RELAY STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, NULL)) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL FROM STRING TO STRING RELAY STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, NULL)) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, NULL)) { free($3); free($6); free($8); YYERROR; } } free($3); free($6); free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, NULL)) { free($3); free($5); free($8); free($10); YYERROR; } } free($3); free($5); free($8); free($10); } | EMAIL TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, $7)) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL FROM STRING TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, $9)) { free($3); free($5); free($7); free($9); YYERROR; } } free($3); free($5); free($7); free($9); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, $10)) { free($3); free($6); free($8); free($10); YYERROR; } } free($3); free($6); free($8); free($10); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, $12)) { free($3); free($5); free($8); free($10); free($12); YYERROR; } } free($3); free($5); free($8); free($10); free($12); } | EMAIL TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, NULL, $5, port_sprintf($7))) { free($3); free($5); YYERROR; } } free($3); free($5); } | EMAIL FROM STRING TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, NULL, $7, port_sprintf($9))) { free($3); free($5); free($7); YYERROR; } } free($3); free($5); free($7); } | EMAIL TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, NULL, $3, $6, $8, port_sprintf($10))) { free($3); free($6); free($8); YYERROR; } } free($3); free($6); free($8); } | EMAIL FROM STRING TO STRING REPLY TO STRING RELAY STRING PORT NUMBER { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_email(new_repo, $3, $5, $8, $10, port_sprintf($12))) { free($3); free($5); free($8); free($10); YYERROR; } } free($3); free($5); free($8); free($10); } | URL STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, NULL, NULL, 0)) { free($2); YYERROR; } } free($2); } | URL STRING AUTH STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, NULL, 0)) { free($2); free($4); YYERROR; } } free($2); free($4); } | URL STRING AUTH STRING INSECURE { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, NULL, 1)) { free($2); free($4); YYERROR; } } free($2); free($4); } | URL STRING HMAC STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, NULL, $4, 0)) { free($2); free($4); YYERROR; } } free($2); free($4); } | URL STRING AUTH STRING HMAC STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, $6, 0)) { free($2); free($4); free($6); YYERROR; } } free($2); free($4); free($6); } | URL STRING AUTH STRING INSECURE HMAC STRING { if (gotd_proc_id == GOTD_PROC_GOTD) { if (conf_notify_http(new_repo, $2, $4, $7, 1)) { free($2); free($4); free($7); YYERROR; } } free($2); free($4); free($7); } ; repository : REPOSITORY STRING { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->name, $2) == 0) { yyerror("duplicate repository '%s'", $2); free($2); YYERROR; } } if (gotd_proc_id == GOTD_PROC_GOTD || gotd_proc_id == GOTD_PROC_GITWRAPPER) { new_repo = conf_new_repo($2); } free($2); } '{' optnl repoopts2 '}' { } ; repoopts1 : PATH STRING { if (gotd_proc_id == GOTD_PROC_GOTD || gotd_proc_id == GOTD_PROC_GITWRAPPER) { if (!got_path_is_absolute($2)) { yyerror("%s: path %s is not absolute", __func__, $2); free($2); YYERROR; } if (realpath($2, new_repo->path) == NULL) { /* * To give admins a chance to create * missing repositories at run-time * we only warn about ENOENT here. * * And ignore 'permission denied' when * running in gitwrapper. Users may be * able to access this repository via * gotd regardless. */ if (errno == ENOENT) { log_warn("%s", $2); } else if (errno != EACCES || gotd_proc_id != GOTD_PROC_GITWRAPPER) { yyerror("realpath %s: %s", $2, strerror(errno)); free($2); YYERROR; } if (strlcpy(new_repo->path, $2, sizeof(new_repo->path)) >= sizeof(new_repo->path)) yyerror("path too long"); } } free($2); } | PERMIT RO numberstring { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ, $3); } else free($3); } | PERMIT RW numberstring { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_PERMITTED, GOTD_AUTH_READ | GOTD_AUTH_WRITE, $3); } else free($3); } | DENY numberstring { if (gotd_proc_id == GOTD_PROC_GOTD) { conf_new_access_rule(new_repo, GOTD_ACCESS_DENIED, 0, $2); } else free($2); } | protect | notify ; repoopts2 : repoopts2 repoopts1 nl | repoopts1 optnl ; nl : '\n' optnl ; optnl : '\n' optnl /* zero or more newlines */ | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "auth", AUTH }, { "branch", BRANCH }, { "connection", CONNECTION }, { "deny", DENY }, { "email", EMAIL }, { "from", FROM }, { "hmac", HMAC }, { "insecure", INSECURE }, { "limit", LIMIT }, { "listen", LISTEN }, { "namespace", NAMESPACE }, { "notify", NOTIFY }, { "on", ON }, { "path", PATH }, { "permit", PERMIT }, { "port", PORT }, { "protect", PROTECT }, { "reference", REFERENCE }, { "relay", RELAY }, { "reply", REPLY }, { "repository", REPOSITORY }, { "request", REQUEST }, { "ro", RO }, { "rw", RW }, { "tag", TAG }, { "timeout", TIMEOUT }, { "to", TO }, { "url", URL }, { "user", USER }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int conf_fd, int secret, int required) { struct file *nfile; int fd = -1; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } fd = dup(conf_fd); if (fd == -1) return NULL; nfile->stream = fdopen(fd, "r"); if (nfile->stream == NULL) { if (required) log_warn("open %s", nfile->name); free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } int gotd_parse_config(const char *filename, int conf_fd, enum gotd_procid proc_id, struct gotd_secrets *secrets, struct gotd *env) { struct sym *sym, *next; struct gotd_repo *repo; int require_config_file = (proc_id != GOTD_PROC_GITWRAPPER); memset(env, 0, sizeof(*env)); gotd = env; gotd_proc_id = proc_id; gotd->secrets = secrets; TAILQ_INIT(&gotd->repos); /* Apply default values. */ if (strlcpy(gotd->unix_socket_path, GOTD_UNIX_SOCKET, sizeof(gotd->unix_socket_path)) >= sizeof(gotd->unix_socket_path)) { fprintf(stderr, "%s: unix socket path too long", __func__); return -1; } if (strlcpy(gotd->user_name, GOTD_USER, sizeof(gotd->user_name)) >= sizeof(gotd->user_name)) { fprintf(stderr, "%s: user name too long", __func__); return -1; } gotd->request_timeout.tv_sec = GOTD_DEFAULT_REQUEST_TIMEOUT; gotd->request_timeout.tv_usec = 0; if (conf_fd == -1 && !require_config_file) return 0; file = newfile(filename, conf_fd, 0, require_config_file); if (file == NULL) return require_config_file ? -1 : 0; yyparse(); errors = file->errors; closefile(file); /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotd->verbosity > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } if (errors) return (-1); TAILQ_FOREACH(repo, &gotd->repos, entry) { if (repo->path[0] == '\0') { log_warnx("repository \"%s\": no path provided in " "configuration file", repo->name); return (-1); } } if (proc_id == GOTD_PROC_GOTD && TAILQ_EMPTY(&gotd->repos)) { log_warnx("no repository defined in configuration file"); return (-1); } return (0); } static int uid_connection_limit_cmp(const void *pa, const void *pb) { const struct gotd_uid_connection_limit *a = pa, *b = pb; if (a->uid < b->uid) return -1; else if (a->uid > b->uid); return 1; return 0; } static int conf_limit_user_connections(const char *user, int maximum) { uid_t uid; struct gotd_uid_connection_limit *limit; size_t nlimits; if (maximum < 1) { yyerror("max connections cannot be smaller 1"); return -1; } if (maximum > GOTD_MAXCLIENTS) { yyerror("max connections must be <= %d", GOTD_MAXCLIENTS); return -1; } if (gotd_parseuid(user, &uid) == -1) { yyerror("%s: no such user", user); return -1; } limit = gotd_find_uid_connection_limit(gotd->connection_limits, gotd->nconnection_limits, uid); if (limit) { limit->max_connections = maximum; return 0; } limit = gotd->connection_limits; nlimits = gotd->nconnection_limits + 1; limit = reallocarray(limit, nlimits, sizeof(*limit)); if (limit == NULL) fatal("reallocarray"); limit[nlimits - 1].uid = uid; limit[nlimits - 1].max_connections = maximum; gotd->connection_limits = limit; gotd->nconnection_limits = nlimits; qsort(gotd->connection_limits, gotd->nconnection_limits, sizeof(gotd->connection_limits[0]), uid_connection_limit_cmp); return 0; } const struct got_error * gotd_conf_new_repo(struct gotd_repo **new_repo, const char *name) { struct gotd_repo *repo; repo = calloc(1, sizeof(*repo)); if (repo == NULL) return got_error_from_errno("calloc"); STAILQ_INIT(&repo->rules); RB_INIT(&repo->protected_tag_namespaces); RB_INIT(&repo->protected_branch_namespaces); RB_INIT(&repo->protected_branches); RB_INIT(&repo->protected_branches); RB_INIT(&repo->notification_refs); RB_INIT(&repo->notification_ref_namespaces); STAILQ_INIT(&repo->notification_targets); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) { free(repo); return got_error_msg(GOT_ERR_NO_SPACE, "repository name too long"); } *new_repo = repo; return NULL; } static struct gotd_repo * conf_new_repo(const char *name) { const struct got_error *err; struct gotd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); err = gotd_conf_new_repo(&repo, name); if (err) fatalx("%s", err->msg); TAILQ_INSERT_TAIL(&gotd->repos, repo, entry); gotd->nrepos++; return repo; }; static void conf_new_access_rule(struct gotd_repo *repo, enum gotd_access access, int authorization, char *identifier) { struct gotd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; rule->authorization = authorization; rule->identifier = identifier; STAILQ_INSERT_TAIL(&repo->rules, rule, entry); } static int refname_is_valid(char *refname) { if (strncmp(refname, "refs/", 5) != 0) { yyerror("reference name must begin with \"refs/\": %s", refname); return 0; } if (!got_ref_name_is_valid(refname)) { yyerror("invalid reference name: %s", refname); return 0; } return 1; } static int conf_protect_ref_namespace(char **new, struct got_pathlist_head *refs, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; *new = NULL; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, refs, s, NULL); if (error || pe == NULL) { free(s); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protected namespace %s", namespace); return -1; } *new = s; return 0; } static int conf_protect_tag_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_tag_namespaces, namespace) == -1) return -1; repo->nprotected_tag_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_branch_namespaces) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch_namespace(struct gotd_repo *repo, char *namespace) { struct got_pathlist_entry *pe; char *new; if (conf_protect_ref_namespace(&new, &repo->protected_branch_namespaces, namespace) == -1) return -1; repo->nprotected_branch_namespaces++; RB_FOREACH(pe, got_pathlist_head, &repo->protected_tag_namespaces) { if (strcmp(pe->path, new) == 0) { yyerror("duplicate protected namespace %s", namespace); return -1; } } return 0; } static int conf_protect_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *new; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&new, &repo->protected_branches, refname, NULL); if (error || new == NULL) { free(refname); if (error) yyerror("got_pathlist_insert: %s", error->msg); else yyerror("duplicate protect branch %s", branchname); return -1; } repo->nprotected_branches++; return 0; } static int conf_notify_branch(struct gotd_repo *repo, char *branchname) { const struct got_error *error; struct got_pathlist_entry *pe; char *refname; if (strncmp(branchname, "refs/heads/", 11) != 0) { if (asprintf(&refname, "refs/heads/%s", branchname) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } } else { refname = strdup(branchname); if (refname == NULL) { yyerror("strdup: %s", strerror(errno)); return -1; } } if (!refname_is_valid(refname)) { free(refname); return -1; } error = got_pathlist_insert(&pe, &repo->notification_refs, refname, NULL); if (error) { free(refname); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(refname); else repo->num_notification_refs++; return 0; } static int conf_notify_ref_namespace(struct gotd_repo *repo, char *namespace) { const struct got_error *error; struct got_pathlist_entry *pe; char *s; got_path_strip_trailing_slashes(namespace); if (!refname_is_valid(namespace)) return -1; if (asprintf(&s, "%s/", namespace) == -1) { yyerror("asprintf: %s", strerror(errno)); return -1; } error = got_pathlist_insert(&pe, &repo->notification_ref_namespaces, s, NULL); if (error) { free(s); yyerror("got_pathlist_insert: %s", error->msg); return -1; } if (pe == NULL) free(s); else repo->num_notification_ref_namespaces++; return 0; } static int conf_notify_email(struct gotd_repo *repo, char *sender, char *recipient, char *responder, char *hostname, char *port) { struct gotd_notification_target *target; STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_EMAIL) continue; if (strcmp(target->conf.email.recipient, recipient) == 0) { yyerror("duplicate email notification for '%s' in " "repository '%s'", recipient, repo->name); return -1; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_EMAIL; if (sender) { target->conf.email.sender = strdup(sender); if (target->conf.email.sender == NULL) fatal("strdup"); } target->conf.email.recipient = strdup(recipient); if (target->conf.email.recipient == NULL) fatal("strdup"); if (responder) { target->conf.email.responder = strdup(responder); if (target->conf.email.responder == NULL) fatal("strdup"); } if (hostname) { target->conf.email.hostname = strdup(hostname); if (target->conf.email.hostname == NULL) fatal("strdup"); } if (port) { target->conf.email.port = strdup(port); if (target->conf.email.port == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); return 0; } static int conf_notify_http(struct gotd_repo *repo, char *url, char *auth, char *hmac, int insecure) { const struct got_error *error; struct gotd_notification_target *target; char *proto, *hostname, *port, *path; int tls = 0, ret = 0; error = gotd_parse_url(&proto, &hostname, &port, &path, url); if (error) { yyerror("invalid HTTP notification URL '%s' in " "repository '%s': %s", url, repo->name, error->msg); return -1; } tls = !strcmp(proto, "https"); if (strcmp(proto, "http") != 0 && strcmp(proto, "https") != 0) { yyerror("invalid protocol '%s' in notification URL '%s' in " "repository '%s", proto, url, repo->name); ret = -1; goto done; } if (port == NULL) { if (strcmp(proto, "http") == 0) port = strdup("80"); if (strcmp(proto, "https") == 0) port = strdup("443"); if (port == NULL) { error = got_error_from_errno("strdup"); ret = -1; goto done; } } if (auth != NULL && gotd_proc_id == GOTD_PROC_GOTD && (gotd->secrets == NULL || gotd_secrets_get(gotd->secrets, GOTD_SECRET_AUTH, auth) == NULL)) { yyerror("no auth secret `%s' defined", auth); ret = -1; goto done; } if (hmac != NULL && gotd_proc_id == GOTD_PROC_GOTD && (gotd->secrets == NULL && gotd_secrets_get(gotd->secrets, GOTD_SECRET_HMAC, hmac) == NULL)) { yyerror("no hmac secret `%s' defined", hmac); ret = -1; goto done; } if (!insecure && strcmp(proto, "http") == 0 && auth) { yyerror("%s: HTTP notifications with basic authentication " "over plaintext HTTP will leak credentials; add the " "'insecure' config keyword if this is intentional", url); ret = -1; goto done; } STAILQ_FOREACH(target, &repo->notification_targets, entry) { if (target->type != GOTD_NOTIFICATION_VIA_HTTP) continue; if (target->conf.http.tls == tls && !strcmp(target->conf.http.hostname, hostname) && !strcmp(target->conf.http.port, port) && !strcmp(target->conf.http.path, path)) { yyerror("duplicate notification for URL '%s' in " "repository '%s'", url, repo->name); ret = -1; goto done; } } target = calloc(1, sizeof(*target)); if (target == NULL) fatal("calloc"); target->type = GOTD_NOTIFICATION_VIA_HTTP; target->conf.http.tls = tls; target->conf.http.hostname = hostname; target->conf.http.port = port; target->conf.http.path = path; hostname = port = path = NULL; if (auth) { target->conf.http.auth = strdup(auth); if (target->conf.http.auth == NULL) fatal("strdup"); } if (hmac) { target->conf.http.hmac = strdup(hmac); if (target->conf.http.hmac == NULL) fatal("strdup"); } STAILQ_INSERT_TAIL(&repo->notification_targets, target, entry); done: free(proto); free(hostname); free(port); free(path); return ret; } int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } struct gotd_repo * gotd_find_repo_by_name(const char *repo_name, struct gotd_repolist *repos) { struct gotd_repo *repo; size_t namelen; TAILQ_FOREACH(repo, repos, entry) { namelen = strlen(repo->name); if (strncmp(repo->name, repo_name, namelen) != 0) continue; if (repo_name[namelen] == '\0' || strcmp(&repo_name[namelen], ".git") == 0) return repo; } return NULL; } struct gotd_repo * gotd_find_repo_by_path(const char *repo_path, struct gotd *gotd) { struct gotd_repo *repo; TAILQ_FOREACH(repo, &gotd->repos, entry) { if (strcmp(repo->path, repo_path) == 0) return repo; } return NULL; } struct gotd_uid_connection_limit * gotd_find_uid_connection_limit(struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid) { /* This array is always sorted to allow for binary search. */ int i, left = 0, right = nlimits - 1; while (left <= right) { i = ((left + right) / 2); if (limits[i].uid == uid) return &limits[i]; if (limits[i].uid > uid) left = i + 1; else right = i - 1; } return NULL; } int gotd_parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } const struct got_error * gotd_parse_url(char **proto, char **host, char **port, char **request_path, const char *url) { const struct got_error *err = NULL; char *s, *p, *q; *proto = *host = *port = *request_path = NULL; p = strstr(url, "://"); if (!p) return got_error(GOT_ERR_PARSE_URI); *proto = strndup(url, p - url); if (*proto == NULL) { err = got_error_from_errno("strndup"); goto done; } s = p + 3; p = strstr(s, "/"); if (p == NULL) { err = got_error(GOT_ERR_PARSE_URI); goto done; } q = memchr(s, ':', p - s); if (q) { *host = strndup(s, q - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } *port = strndup(q + 1, p - (q + 1)); if (*port == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*port)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } else { *host = strndup(s, p - s); if (*host == NULL) { err = got_error_from_errno("strndup"); goto done; } if ((*host)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } } while (p[0] == '/' && p[1] == '/') p++; *request_path = strdup(p); if (*request_path == NULL) { err = got_error_from_errno("strdup"); goto done; } if ((*request_path)[0] == '\0') { err = got_error(GOT_ERR_PARSE_URI); goto done; } done: if (err) { free(*proto); *proto = NULL; free(*host); *host = NULL; free(*port); *port = NULL; free(*request_path); *request_path = NULL; } return err; } static char * port_sprintf(int p) { static char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)p); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)p); return portno; } got-portable-0.119/gotd/repo_read.c0000664000175000017500000005740615066536113012671 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_cancel.h" #include "got_object.h" #include "got_repository.h" #include "got_reference.h" #include "got_repository_admin.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_object.h" #include "got_lib_object_idset.h" #include "got_lib_hash.h" #include "got_lib_pack.h" #include "got_lib_ratelimit.h" #include "got_lib_pack_create.h" #include "got_lib_poll.h" #include "log.h" #include "gotd.h" #include "repo_read.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif static struct repo_read { pid_t pid; const char *title; struct got_repository *repo; int *pack_fds; int *temp_fds; int session_fd; struct gotd_imsgev session_iev; int refs_listed; } repo_read; static struct repo_read_client { uint32_t id; int fd; int delta_cache_fd; int report_progress; int pack_pipe; struct got_object_idset *want_ids; struct got_object_idset *have_ids; } repo_read_client; static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigterm_received; static void catch_sigint(int signo) { sigint_received = 1; } static void catch_sigterm(int signo) { sigterm_received = 1; } static const struct got_error * check_cancelled(void *arg) { if (sigint_received || sigterm_received) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * send_symref(struct got_reference *symref, struct got_object_id *target_id, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct gotd_imsg_symref isymref; const char *refname = got_ref_get_name(symref); const char *target = got_ref_get_symref_target(symref); size_t len; struct ibuf *wbuf; memset(&isymref, 0, sizeof(isymref)); isymref.name_len = strlen(refname); isymref.target_len = strlen(target); memcpy(isymref.target_id, target_id->hash, sizeof(isymref.target_id)); len = sizeof(isymref) + isymref.name_len + isymref.target_len; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_SYMREF, 0, 0, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create SYMREF"); goto done; } if (imsg_add(wbuf, &isymref, sizeof(isymref)) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } if (imsg_add(wbuf, refname, isymref.name_len) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } if (imsg_add(wbuf, target, isymref.target_len) == -1) { err = got_error_from_errno("imsg_add SYMREF"); goto done; } imsg_close(ibuf, wbuf); done: free(target_id); return err; } static const struct got_error * send_peeled_tag_ref(struct got_reference *ref, struct got_object *obj, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct got_tag_object *tag; size_t namelen, len; char *peeled_refname = NULL; struct got_object_id *id; struct ibuf *wbuf; err = got_object_tag_open(&tag, repo_read.repo, obj); if (err) return err; if (asprintf(&peeled_refname, "%s^{}", got_ref_get_name(ref)) == -1) { err = got_error_from_errno("asprintf"); goto done; } id = got_object_tag_get_object_id(tag); namelen = strlen(peeled_refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { err = got_error(GOT_ERR_NO_SPACE); goto done; } wbuf = imsg_create(ibuf, GOTD_IMSG_REF, GOTD_PROC_REPO_READ, repo_read.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create MREF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } if (imsg_add(wbuf, peeled_refname, namelen) == -1) { err = got_error_from_errno("imsg_add REF"); goto done; } imsg_close(ibuf, wbuf); done: got_object_tag_close(tag); return err; } static const struct got_error * send_ref(struct got_reference *ref, struct imsgbuf *ibuf) { const struct got_error *err; const char *refname = got_ref_get_name(ref); size_t namelen; struct got_object_id *id = NULL; struct got_object *obj = NULL; size_t len; struct ibuf *wbuf; namelen = strlen(refname); len = sizeof(struct gotd_imsg_ref) + namelen; if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return got_error(GOT_ERR_NO_SPACE); err = got_ref_resolve(&id, repo_read.repo, ref); if (err) return err; wbuf = imsg_create(ibuf, GOTD_IMSG_REF, GOTD_PROC_REPO_READ, repo_read.pid, len); if (wbuf == NULL) { err = got_error_from_errno("imsg_create REF"); goto done; } /* Keep in sync with struct gotd_imsg_ref definition. */ if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) return got_error_from_errno("imsg_add REF"); if (imsg_add(wbuf, refname, namelen) == -1) return got_error_from_errno("imsg_add REF"); imsg_close(ibuf, wbuf); err = got_object_open(&obj, repo_read.repo, id); if (err) goto done; if (obj->type == GOT_OBJ_TYPE_TAG) err = send_peeled_tag_ref(ref, obj, ibuf); done: if (obj) got_object_close(obj); free(id); return err; } static const struct got_error * list_refs(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct got_reflist_head refs; struct got_reflist_entry *re; size_t datalen; struct gotd_imsg_reflist irefs; struct imsgbuf ibuf; struct got_object_id *head_target_id = NULL; TAILQ_INIT(&refs); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_read.refs_listed) { return got_error_msg(GOT_ERR_CLIENT_ID, "duplicate list-refs request"); } repo_read.refs_listed = 1; client->fd = imsg_get_fd(imsg); if (client->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (imsgbuf_init(&ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); err = got_ref_list(&refs, repo_read.repo, "", got_ref_cmp_by_name, NULL); if (err) return err; memset(&irefs, 0, sizeof(irefs)); TAILQ_FOREACH(re, &refs, entry) { struct got_object_id *id; int obj_type; if (got_ref_is_symbolic(re->ref)) { const char *refname = got_ref_get_name(re->ref); if (strcmp(refname, GOT_REF_HEAD) != 0) continue; err = got_ref_resolve(&head_target_id, repo_read.repo, re->ref); if (err) { if (err->code != GOT_ERR_NOT_REF) return err; /* * HEAD points to a non-existent branch. * Do not advertise it. * Matches git-daemon's behaviour. */ head_target_id = NULL; err = NULL; } else irefs.nrefs++; continue; } irefs.nrefs++; /* Account for a peeled tag refs. */ err = got_ref_resolve(&id, repo_read.repo, re->ref); if (err) goto done; err = got_object_get_type(&obj_type, repo_read.repo, id); free(id); if (err) goto done; if (obj_type == GOT_OBJ_TYPE_TAG) irefs.nrefs++; } if (imsg_compose(&ibuf, GOTD_IMSG_REFLIST, GOTD_PROC_REPO_READ, repo_read.pid, -1, &irefs, sizeof(irefs)) == -1) { err = got_error_from_errno("imsg_compose REFLIST"); goto done; } /* * Send the HEAD symref first. In Git-protocol versions < 2 * the HEAD symref must be announced on the initial line of * the server's ref advertisement. * For now, we do not advertise symrefs other than HEAD. */ TAILQ_FOREACH(re, &refs, entry) { if (!got_ref_is_symbolic(re->ref) || strcmp(got_ref_get_name(re->ref), GOT_REF_HEAD) != 0 || head_target_id == NULL) continue; err = send_symref(re->ref, head_target_id, &ibuf); if (err) goto done; break; } TAILQ_FOREACH(re, &refs, entry) { if (got_ref_is_symbolic(re->ref)) continue; err = send_ref(re->ref, &ibuf); if (err) goto done; } err = gotd_imsg_flush(&ibuf); done: got_ref_list_free(&refs); imsgbuf_clear(&ibuf); return err; } static const struct got_error * append_object_id(struct got_object_id *id, void *data, void *arg) { struct gotd_object_id_array *array = arg; const size_t alloc_chunksz = 256; if (array->ids == NULL) { array->ids = reallocarray(NULL, alloc_chunksz, sizeof(*array->ids)); if (array->ids == NULL) return got_error_from_errno("reallocarray"); array->nalloc = alloc_chunksz; array->nids = 0; } else if (array->nalloc <= array->nids) { struct got_object_id **new; new = recallocarray(array->ids, array->nalloc, array->nalloc + alloc_chunksz, sizeof(*new)); if (new == NULL) return got_error_from_errno("recallocarray"); array->ids = new; array->nalloc += alloc_chunksz; } array->ids[array->nids] = id; array->nids++; return NULL; } static const struct got_error * recv_want(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct gotd_imsg_want iwant; size_t datalen; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id id; int obj_type; struct imsgbuf ibuf; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iwant)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iwant, imsg->data, sizeof(iwant)); memset(&id, 0, sizeof(id)); memcpy(id.hash, iwant.object_id, SHA1_DIGEST_LENGTH); if (log_getverbose() > 0 && got_object_id_hex(&id, hex, sizeof(hex))) log_debug("client wants %s", hex); if (imsgbuf_init(&ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); err = got_object_get_type(&obj_type, repo_read.repo, &id); if (err) return err; if (obj_type != GOT_OBJ_TYPE_COMMIT && obj_type != GOT_OBJ_TYPE_TAG) return got_error(GOT_ERR_OBJ_TYPE); if (!got_object_idset_contains(client->want_ids, &id)) { err = got_object_idset_add(client->want_ids, &id, NULL); if (err) return err; } gotd_imsg_send_ack(&id, &ibuf, GOTD_PROC_REPO_READ, repo_read.pid); imsgbuf_clear(&ibuf); return err; } static const struct got_error * recv_have(struct imsg *imsg) { const struct got_error *err; struct repo_read_client *client = &repo_read_client; struct gotd_imsg_have ihave; size_t datalen; char hex[SHA1_DIGEST_STRING_LENGTH]; struct got_object_id id; int obj_type; struct imsgbuf ibuf; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ihave)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ihave, imsg->data, sizeof(ihave)); memset(&id, 0, sizeof(id)); memcpy(id.hash, ihave.object_id, SHA1_DIGEST_LENGTH); if (log_getverbose() > 0 && got_object_id_hex(&id, hex, sizeof(hex))) log_debug("client has %s", hex); if (imsgbuf_init(&ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); err = got_object_get_type(&obj_type, repo_read.repo, &id); if (err) { if (err->code == GOT_ERR_NO_OBJ) { gotd_imsg_send_nak(&id, &ibuf, GOTD_PROC_REPO_READ, repo_read.pid); err = NULL; } goto done; } if (obj_type != GOT_OBJ_TYPE_COMMIT && obj_type != GOT_OBJ_TYPE_TAG) { gotd_imsg_send_nak(&id, &ibuf, GOTD_PROC_REPO_READ, repo_read.pid); err = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (!got_object_idset_contains(client->have_ids, &id)) { err = got_object_idset_add(client->have_ids, &id, NULL); if (err) goto done; } gotd_imsg_send_ack(&id, &ibuf, GOTD_PROC_REPO_READ, repo_read.pid); done: imsgbuf_clear(&ibuf); return err; } struct repo_read_pack_progress_arg { int report_progress; struct imsgbuf *ibuf; int sent_ready; }; static const struct got_error * pack_progress(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, int pack_done) { struct repo_read_pack_progress_arg *a = arg; struct gotd_imsg_packfile_progress iprog; int ret; if (!a->report_progress) return NULL; if (packfile_size > 0 && a->sent_ready) return NULL; memset(&iprog, 0, sizeof(iprog)); iprog.ncolored = ncolored; iprog.nfound = nfound; iprog.ntrees = ntrees; iprog.packfile_size = packfile_size; iprog.ncommits = ncommits; iprog.nobj_total = nobj_total; iprog.nobj_deltify = nobj_deltify; iprog.nobj_written = nobj_written; /* Using synchronous writes since we are blocking the event loop. */ if (packfile_size == 0) { ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_PROGRESS, GOTD_PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog)); if (ret == -1) { return got_error_from_errno("imsg compose " "PACKFILE_PROGRESS"); } } else { a->sent_ready = 1; ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_READY, GOTD_PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog)); if (ret == -1) { return got_error_from_errno("imsg compose " "PACKFILE_READY"); } } return gotd_imsg_flush(a->ibuf); } static const struct got_error * receive_delta_cache_fd(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_read_client *client = &repo_read_client; struct gotd_imsg_send_packfile ireq; size_t datalen; log_debug("receiving delta cache file"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ireq)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ireq, imsg->data, sizeof(ireq)); if (client->delta_cache_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->delta_cache_fd = imsg_get_fd(imsg); if (client->delta_cache_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); client->report_progress = ireq.report_progress; return NULL; } static const struct got_error * receive_pack_pipe(struct imsg *imsg, struct gotd_imsgev *iev) { struct repo_read_client *client = &repo_read_client; size_t datalen; log_debug("receiving pack pipe descriptor"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (client->pack_pipe != -1) return got_error(GOT_ERR_PRIVSEP_MSG); client->pack_pipe = imsg_get_fd(imsg); if (client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); return NULL; } static const struct got_error * send_packfile(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err = NULL; struct repo_read_client *client = &repo_read_client; struct got_object_id packhash; char hex[GOT_HASH_DIGEST_STRING_MAXLEN]; FILE *delta_cache = NULL; struct imsgbuf ibuf; struct repo_read_pack_progress_arg pa; struct got_ratelimit rl; struct gotd_object_id_array want_ids; struct gotd_object_id_array have_ids; log_debug("packfile request received"); memset(&want_ids, 0, sizeof(want_ids)); memset(&have_ids, 0, sizeof(have_ids)); got_ratelimit_init(&rl, 2, 0); if (client->delta_cache_fd == -1 || client->pack_pipe == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (imsgbuf_init(&ibuf, client->fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&ibuf); delta_cache = fdopen(client->delta_cache_fd, "w+"); if (delta_cache == NULL) { err = got_error_from_errno("fdopen"); goto done; } client->delta_cache_fd = -1; memset(&pa, 0, sizeof(pa)); pa.ibuf = &ibuf; pa.report_progress = client->report_progress; err = got_object_idset_for_each(client->want_ids, append_object_id, &want_ids); if (err) goto done; err = got_object_idset_for_each(client->have_ids, append_object_id, &have_ids); if (err) goto done; err = got_pack_create(&packhash, client->pack_pipe, delta_cache, have_ids.ids, have_ids.nids, want_ids.ids, want_ids.nids, repo_read.repo, 0, 1, 0, pack_progress, &pa, &rl, check_cancelled, NULL); if (err) goto done; if (log_getverbose() > 0 && got_hash_digest_to_str(packhash.hash, hex, sizeof(hex), packhash.algo)) log_debug("sent pack-%s.pack", hex); if (gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_DONE, GOTD_PROC_REPO_READ, -1, NULL, 0) == -1) err = got_error_from_errno("imsg compose PACKFILE_DONE"); done: if (client->delta_cache_fd != -1 && close(client->delta_cache_fd) == -1 && err == NULL) err = got_error_from_errno("close"); client->delta_cache_fd = -1; if (delta_cache != NULL && fclose(delta_cache) == EOF && err == NULL) err = got_error_from_errno("fclose"); imsgbuf_clear(&ibuf); free(want_ids.ids); free(have_ids.ids); return err; } static void repo_read_dispatch_session(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_read_client *client = &repo_read_client; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } while (err == NULL && check_cancelled(NULL) == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; if (imsg.hdr.type != GOTD_IMSG_LIST_REFS_INTERNAL && !repo_read.refs_listed) { err = got_error(GOT_ERR_PRIVSEP_MSG); break; } switch (imsg.hdr.type) { case GOTD_IMSG_LIST_REFS_INTERNAL: err = list_refs(&imsg); if (err) log_warnx("ls-refs: %s", err->msg); break; case GOTD_IMSG_WANT: err = recv_want(&imsg); if (err) log_warnx("want-line: %s", err->msg); break; case GOTD_IMSG_HAVE: err = recv_have(&imsg); if (err) log_warnx("have-line: %s", err->msg); break; case GOTD_IMSG_SEND_PACKFILE: err = receive_delta_cache_fd(&imsg, iev); if (err) log_warnx("receiving delta cache: %s", err->msg); break; case GOTD_IMSG_PACKFILE_PIPE: err = receive_pack_pipe(&imsg, iev); if (err) { log_warnx("receiving pack pipe: %s", err->msg); break; } err = send_packfile(&imsg, iev); if (err) log_warnx("sending packfile: %s", err->msg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, GOTD_PROC_REPO_READ, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static const struct got_error * recv_connect(struct imsg *imsg) { struct gotd_imsgev *iev = &repo_read.session_iev; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) return got_error(GOT_ERR_PRIVSEP_LEN); if (repo_read.session_fd != -1) return got_error(GOT_ERR_PRIVSEP_MSG); repo_read.session_fd = imsg_get_fd(imsg); if (repo_read.session_fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (imsgbuf_init(&iev->ibuf, repo_read.session_fd) == -1) return got_error_from_errno("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = repo_read_dispatch_session; iev->events = EV_READ; iev->handler_arg = NULL; event_set(&iev->ev, iev->ibuf.fd, EV_READ, repo_read_dispatch_session, iev); gotd_imsg_event_add(iev); return NULL; } static void repo_read_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; struct repo_read_client *client = &repo_read_client; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } while (err == NULL && check_cancelled(NULL) == NULL) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_CONNECT_REPO_CHILD: err = recv_connect(&imsg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut && check_cancelled(NULL) == NULL) { if (err && gotd_imsg_send_error_event(iev, GOTD_PROC_REPO_READ, client->id, err) == -1) { log_warnx("could not send error to parent: %s", err->msg); } gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void repo_read_main(const char *title, const char *repo_path, int *pack_fds, int *temp_fds) { const struct got_error *err = NULL; struct repo_read_client *client = &repo_read_client; struct gotd_imsgev iev; client->fd = -1; client->delta_cache_fd = -1; client->pack_pipe = -1; client->have_ids = got_object_idset_alloc(); if (client->have_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } client->want_ids = got_object_idset_alloc(); if (client->want_ids == NULL) { err = got_error_from_errno("got_object_idset_alloc"); goto done; } repo_read.title = title; repo_read.pid = getpid(); repo_read.pack_fds = pack_fds; repo_read.temp_fds = temp_fds; repo_read.session_fd = -1; repo_read.session_iev.ibuf.fd = -1; err = got_repo_open(&repo_read.repo, repo_path, NULL, pack_fds); if (err) goto done; if (!got_repo_is_bare(repo_read.repo)) { err = got_error_msg(GOT_ERR_NOT_GIT_REPO, "bare git repository required"); goto done; } if (got_repo_get_object_format(repo_read.repo) != GOT_HASH_SHA1) { err = got_error_msg(GOT_ERR_NOT_IMPL, "sha256 object IDs unsupported in network protocol"); goto done; } got_repo_temp_fds_set(repo_read.repo, temp_fds); signal(SIGINT, catch_sigint); signal(SIGTERM, catch_sigterm); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); if (imsgbuf_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) { err = got_error_from_errno("imsgbuf_init"); goto done; } imsgbuf_allow_fdpass(&iev.ibuf); iev.handler = repo_read_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, repo_read_dispatch, &iev); if (gotd_imsg_compose_event(&iev, GOTD_IMSG_REPO_CHILD_READY, GOTD_PROC_REPO_READ, -1, NULL, 0) == -1) { err = got_error_from_errno("imsg compose REPO_CHILD_READY"); goto done; } event_dispatch(); done: if (err) log_warnx("%s: %s", title, err->msg); repo_read_shutdown(); } void repo_read_shutdown(void) { struct repo_read_client *client = &repo_read_client; log_debug("%s: shutting down", repo_read.title); if (client->have_ids) got_object_idset_free(client->have_ids); if (client->want_ids) got_object_idset_free(client->want_ids); if (client->fd != -1) close(client->fd); if (client->delta_cache_fd != -1) close(client->delta_cache_fd); if (client->pack_pipe != -1) close(client->pack_pipe); if (repo_read.repo) got_repo_close(repo_read.repo); got_repo_pack_fds_close(repo_read.pack_fds); got_repo_temp_fds_close(repo_read.temp_fds); if (repo_read.session_fd != -1) close(repo_read.session_fd); exit(0); } got-portable-0.119/gotd/listen.h0000664000175000017500000000147715066535721012235 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void listen_main(const char *title); got-portable-0.119/gotd/secrets.c0000664000175000017500000001454315066536113012374 /* * Copyright (c) 2024 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include "got_error.h" #include "log.h" #include "secrets.h" static const struct got_error * push(struct gotd_secrets *s, enum gotd_secret_type type, const char *label, const char *user, const char *pass, const char *hmac) { size_t newcap, i; void *t; if (s->len == s->cap) { newcap = s->cap + 16; t = reallocarray(s->secrets, newcap, sizeof(*s->secrets)); if (t == NULL) return got_error_from_errno("reallocarray"); s->secrets = t; s->cap = newcap; } i = s->len; memset(&s->secrets[i], 0, sizeof(s->secrets[i])); s->secrets[i].type = type; s->secrets[i].label = strdup(label); if (s->secrets[i].label == NULL) return got_error_from_errno("strdup"); if (type == GOTD_SECRET_AUTH) { s->secrets[i].user = strdup(user); if (s->secrets[i].user == NULL) return got_error_from_errno("strdup"); s->secrets[i].pass = strdup(pass); if (s->secrets[i].pass == NULL) return got_error_from_errno("strdup"); } else { s->secrets[i].hmac = strdup(hmac); if (s->secrets[i].hmac == NULL) return got_error_from_errno("strdup"); } s->len++; return NULL; } static char * read_word(char **word, const char *path, int lineno, char *s) { char *p, quote = 0; int escape = 0; s += strspn(s, " \t"); if (*s == '\0') { log_warnx("%s:%d syntax error", path, lineno); return NULL; } *word = s; p = s; while (*s) { if (escape) { escape = 0; *p++ = *s++; continue; } if (*s == '\\') { escape = 1; s++; continue; } if (*s == quote) { quote = 0; s++; continue; } if (*s == '\'' || *s == '\"') { quote = *s; s++; continue; } if (!quote && (*s == ' ' || *s == '\t')) { *p = '\0'; return s + 1; } *p++ = *s++; } if (quote) { log_warnx("%s:%d no closing quote", path, lineno); return NULL; } if (escape) { log_warnx("%s:%d unterminated escape at end of line", path, lineno); return NULL; } *p = '\0'; return s; } static char * read_keyword(char **kw, const char *path, int lineno, char *s) { s += strspn(s, " \t"); if (*s == '\0') { log_warnx("%s:%d syntax error", path, lineno); return NULL; } *kw = s; s += strcspn(s, " \t"); if (*s != '\0') *s++ = '\0'; return s; } static const struct got_error * parse_line(struct gotd_secrets *secrets, const char *path, int lineno, char *line) { char *kw, *label; char *user = NULL, *pass = NULL, *hmac = NULL; enum gotd_secret_type type; line = read_keyword(&kw, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); if (!strcmp(kw, "auth")) type = GOTD_SECRET_AUTH; else if (!strcmp(kw, "hmac")) type = GOTD_SECRET_HMAC; else { log_warnx("%s:%d syntax error", path, lineno); return got_error(GOT_ERR_PARSE_CONFIG); } line = read_word(&label, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); if (type == GOTD_SECRET_AUTH) { line = read_keyword(&kw, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); if (strcmp(kw, "user") != 0) { log_warnx("%s:%d syntax error", path, lineno); return got_error(GOT_ERR_PARSE_CONFIG); } line = read_word(&user, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); line = read_keyword(&kw, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); if (strcmp(kw, "password") != 0) { log_warnx("%s:%d syntax error", path, lineno); return got_error(GOT_ERR_PARSE_CONFIG); } line = read_word(&pass, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); } else { line = read_word(&hmac, path, lineno, line); if (line == NULL) return got_error(GOT_ERR_PARSE_CONFIG); } line += strspn(line, " \t"); if (*line != '\0') { log_warnx("%s:%d syntax error", path, lineno); return got_error(GOT_ERR_PARSE_CONFIG); } if (gotd_secrets_get(secrets, type, label) != NULL) { log_warnx("%s:%d duplicate %s entry %s", path, lineno, type == GOTD_SECRET_AUTH ? "auth" : "hmac", label); return got_error(GOT_ERR_PARSE_CONFIG); } return push(secrets, type, label, user, pass, hmac); } const struct got_error * gotd_secrets_parse(const char *path, FILE *fp, struct gotd_secrets **s) { const struct got_error *err = NULL; int lineno = 0; char *line = NULL; size_t linesize = 0; ssize_t linelen; char *t; struct gotd_secrets *secrets; *s = NULL; secrets = calloc(1, sizeof(*secrets)); if (secrets == NULL) return got_error_from_errno("calloc"); while ((linelen = getline(&line, &linesize, fp)) != -1) { lineno++; if (line[linelen - 1] == '\n') line[--linelen] = '\0'; for (t = line; *t == ' ' || *t == '\t'; ++t) /* nop */ ; if (*t == '\0' || *t == '#') continue; err = parse_line(secrets, path, lineno, t); if (err) break; } free(line); if (ferror(fp) && err == NULL) err = got_error_from_errno("getline"); if (err) { gotd_secrets_free(secrets); secrets = NULL; } *s = secrets; return err; } struct gotd_secret * gotd_secrets_get(struct gotd_secrets *s, enum gotd_secret_type type, const char *label) { size_t i; for (i = 0; i < s->len; ++i) { if (s->secrets[i].type != type) continue; if (strcmp(s->secrets[i].label, label) != 0) continue; return &s->secrets[i]; } return NULL; } void gotd_secrets_free(struct gotd_secrets *s) { size_t i; if (s == NULL) return; for (i = 0; i < s->len; ++i) { free(s->secrets[i].label); free(s->secrets[i].user); free(s->secrets[i].pass); free(s->secrets[i].hmac); } free(s); } got-portable-0.119/gotd/gotd.conf.50000664000175000017500000003606615066535721012537 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTD.CONF 5 .Os .Sh NAME .Nm gotd.conf .Nd gotd configuration file .Sh DESCRIPTION .Nm is the run-time configuration file for .Xr gotd 8 . .Pp The file format is line-based, with one configuration directive per line. Comments can be put anywhere in the file using a hash mark .Pq Sq # , and extend to the end of the current line. Arguments names not beginning with a letter, digit or underscore, as well as reserved words .Pq such as Ic listen , Ic repository No or Ic user , must be quoted. Arguments containing whitespace should be surrounded by double quotes .Pq \&" . .Pp Macros can be defined that are later expanded in context. Macro names must start with a letter, digit, or underscore, and may contain any of those characters, but may not be reserved words. Macros are not expanded inside quotes. For example: .Bd -literal -offset indent path = "/var/run/gotd.sock" listen on $path .Ed .Sh GLOBAL CONFIGURATION The available global configuration directives are as follows: .Bl -tag -width Ds .It Ic connection Ar option Set the specified options and limits for connections to the .Xr gotd 8 unix socket. .Pp The .Ic connection directive may be specified multiple times, and multiple .Ar option arguments may be specified within curly braces: .Pp .Ic connection Brq Ar ... .Pp Each option should only be specified once. If a given option is listed multiple times, the last line which sets this option wins. .Pp Valid connection options are: .Bl -tag -width Ds .It Ic request timeout Ar seconds Specify the inactivity timeout for operations between client and server. If this timeout is exceeded while a Git protocol request is being processed, the request will be aborted and the connection will be terminated. .Pp The timeout value may also have a suffix indicating its unit of measure. Supported suffixes are: .Pp .Bl -tag -compact -width tenletters .It Ar s No or Ar S seconds .It Ar m No or Ar M minutes .It Ar h No or Ar H hours .El .Pp The default timeout is 1h (3600 seconds, one hour). This should only be changed if legitimate requests are exceeding the default timeout for some reason, such as the server spending an extraordinary amount of time generating a pack file. .It Ic limit Ic user Ar identity Ar number Limit the maximum amount of concurrent connections by the user with the username .Ar identity to .Ar number . Numeric user IDs are also accepted. .Pp The default per-user limit is 4. This should only be changed if concurrent connections from a given user are expected to exceed the default limit, for example if an anonymous user is granted read access and many concurrent connections will share this anonymous user identity. .El .It Ic listen on Ar path Set the path to the unix socket which .Xr gotd 8 should listen on. If not specified, the path .Pa /var/run/gotd.sock will be used. .It Ic user Ar user Set the .Ar user which will run .Xr gotd 8 . Initially, .Xr gotd 8 requires root privileges in order to create its unix socket. Afterwards, .Xr gotd 8 drops privileges to the specified .Ar user . If not specified, the user _gotd will be used. Numeric user IDs are also accepted. .El .Sh REPOSITORY CONFIGURATION At least one repository context must exist for .Xr gotd 8 to function. For each repository, access rules must be configured using the .Ic permit and .Ic deny configuration directives. Multiple access rules can be specified, and the last matching rule determines the action taken. If no rule matches, access to the repository is denied. .Pp A repository context is declared with a unique .Ar name , followed by repository-specific configuration directives inside curly braces: .Pp .Ic repository Ar name Brq ... .Pp .Xr got 1 and .Xr git 1 clients can connect to a repository by including the repository's unique .Ar name in the request URL. Clients appending the string .Dq .git to the .Ar name will also be accepted. .Pp If desired, the .Ar name may contain path-separators, .Dq / , to expose repositories as part of a virtual client-visible directory hierarchy. .Pp The available repository configuration directives are as follows: .Bl -tag -width Ds .It Ic deny Ar identity Deny repository access to users with the username .Ar identity . Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic path Ar path Set the path to the Git repository. Must be specified. .It Ic permit Ar mode Ar identity Permit repository access to users with the username .Ar identity . The .Ar mode argument must be set to either .Ic ro for read-only access, or .Ic rw for read-write access. Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic protect Brq Ar ... The .Cm protect directive may be used to protect branches and tags in a repository from being overwritten by potentially destructive client-side commands, such as when .Cm got send -f and .Cm git push -f are used to change the history of a branch. .Pp To build a set of protected branches and tags, multiple .Ic protect directives may be specified per repository and multiple .Ic protect directive parameters may be specified within curly braces. .Pp The available .Cm protect parameters are as follows: .Bl -tag -width Ds .It Ic branch Ar name Protect the named branch. The branch may be created if it does not exist yet. Attempts to delete the branch or change its history will be denied. .Pp If the .Ar name does not already begin with .Dq refs/heads/ it will be looked up in the .Dq refs/heads/ reference namespace. .It Ic branch Ic namespace Ar namespace Protect the given reference namespace, assuming that references in this namespace represent branches. New branches may be created in the namespace. Attempts to change the history of branches or delete them will be denied. .Pp The .Ar namespace argument must be absolute, starting with .Dq refs/ . .It Ic tag Ic namespace Ar namespace Protect the given reference namespace, assuming that references in this namespace represent tags. New tags may be created in the namespace. Attempts to change or delete existing tags will be denied. .Pp The .Ar namespace argument must be absolute, starting with .Dq refs/ . .El .Pp The special reference namespaces .Dq refs/got/ and .Dq refs/remotes/ do not need to be listed in .Nm . These namespaces are always protected and even attempts to create new references in these namespaces will always be denied. .It Ic notify Brq Ar ... The .Ic notify directive enables notifications about new commits or tags added to the repository. .Pp Notifications via email require an SMTP daemon which accepts mail for forwarding without requiring client authentication or encryption. On .Ox the .Xr smtpd 8 daemon can be used for this purpose. The default content of email notifications looks similar to the output of the .Cm got log -d command. .Pp Notifications via HTTP require a HTTP or HTTPS server which is accepting POST requests with or without HTTP Basic authentication. Depending on the use case a custom server-side CGI script may be required for the processing of notifications. HTTP notifications can achieve functionality similar to Git's server-side post-receive hook script with .Xr gotd 8 by triggering arbitrary post-commit actions via the HTTP server. .Pp The .Ic notify directive expects parameters which must be enclosed in curly braces. The available parameters are as follows: .Bl -tag -width Ds .It Ic branch Ar name Send notifications about commits to the named branch. The .Ar name will be looked up in the .Dq refs/heads/ reference namespace. This directive may be specified multiple times to build a list of branches to send notifications for. If neither a .Ic branch nor a .Ic reference namespace are specified then changes to any reference will trigger notifications. .It Ic reference Ic namespace Ar namespace Send notifications about commits or tags within a reference namespace. This directive may be specified multiple times to build a list of namespaces to send notifications for. If neither a .Ic branch nor a .Ic reference namespace are specified then changes to any reference will trigger notifications. .It Ic email Oo Ic from Ar sender Oc Ic to Ar recipient Oo Ic reply to Ar responder Oc Oo Ic relay Ar hostname Oo Ic port Ar port Oc Oc Send notifications via email to the specified .Ar recipient . This directive may be specified multiple times to build a list of recipients to send notifications to. .Pp The .Ar recipient must be an email addresses that accepts mail. The .Ar sender will be used as the From address. If not specified, the sender defaults to an email address composed of the user account running .Xr gotd 8 and the local hostname. .Pp If a .Ar responder is specified via the .Ic reply to directive, the .Ar responder will be used as the Reply-to address. Setting the Reply-to header can be useful if replies should go to a mailing list instead of the .Ar sender , for example. .Pp By default, mail will be sent to the SMTP server listening on the loopback address 127.0.0.1 on port 25. The .Ic relay and .Ic port directives can be used to specify a different SMTP server address and port. .It Ic url Ar URL Oo Ic auth Ar label Oo Ic insecure Oc Oc Oo Ic hmac Ar label Oc Send notifications via HTTP. This directive may be specified multiple times to build a list of HTTP servers to send notifications to. .Pp The notification will be sent as a POST request to the given .Ar URL , which must be a valid HTTP URL and begin with either .Dq http:// or .Dq https:// . If HTTPS is used, sending of notifications will only succeed if no TLS errors occur. .Pp The optional .Ic auth directive enables HTTP Basic authentication. Authentication credentials must be specified in the separate .Xr gotd-secrets.conf 5 file, using the .Ar label as identifier. Unless the .Ic insecure option is specified the notification target .Ar URL must be a .Dq https:// URL to avoid leaking of authentication credentials. .Pp If a .Ic hmac secret is provided, the request body will be signed using HMAC, allowing the receiver to verify the notification message's authenticity and integrity. The HMAC secret to use must be specified in the separate .Xr gotd-secrets.conf 5 file, using the .Ar label as identifier. The signature uses HMAC-SHA256 and will be sent in the HTTP header .Dq X-Gotd-Signature . .Pp The request body contains a JSON object with a .Dq notifications property containing an array of notification objects. The following notification object properties are always present: .Bl -tag -width authenticated_user .It Dv repo The repository name as a string. .It Dv authenticated_user The committer's user account as authenticated by .Xr gotd 8 as a string. .It Dv type The notification object type as a string. .El .Pp Each notification object carries additional type-specific properties. The types and their type-specific properties are: .Bl -tag -width Ds .It Dv commit The commit notification object has the following fields. Except where noted, all are optional. .Bl -tag -width Ds .It Dv short Boolean, indicates whether the object has all the fields set. When several commits are batched in a single send operation, not all of the fields are available for each commit object. .It Dv id The commit ID as string, may be abbreviated. .It Dv committer An object with the committer information with the following fields: .Pp .Bl -tag -compact -width Ds .It Dv full Committer's full name. .It Dv name Committer's name. .It Dv mail Committer's mail address. .It Dv user Committer's username. This is the only field guaranteed to be set. .El .It Dv author An object with the author information. Has the same fields as the .Sq committer but may be unset. .It Dv date Number, representing the number of seconds since the Epoch in UTC. .It Dv short_message The first line of the commit message. This field is always set. .It Dv message The complete commit message, may be unset. .It Dv diffstat An object with the summarized changes, may be unset. Contains a .Sq files field with an array of objects describing the changes per-file and a .Sq total field with the cumulative changes. The changes per-file contains the following fields: .Pp .Bl -tag -compact -width removed .It Dv action A string describing the action, can be .Dq added , .Dq deleted , .Dq modified , .Dq mode changed , or .Dq unknown . .It Dv file The file path. .It Dv added The number of lines added. .It Dv removed The number of lines removed. .El .Pp The .Sq total object contains two fields: .Sq added and .Sq removed which are the number of added and removed lines respectively. .El .It Dv branch-deleted The branch deleted notifications has the following fields, all guaranteed to be set: .Bl -tag -width Ds .It Dv ref The removed branch reference. .It Dv id The hash of the commit pointed by the deleted branch. .El .It Dv tag The tag notification has the following fields, all guaranteed to be set: .Bl -tag -width Ds .It tag The tag reference. .It tagger The user information, with the same format of the .Sq committer field for the .Sq commit notification but with all the field guaranteed to be set. .It Dv date Number, representing the number of seconds since the Epoch in UTC. .It Dv object The object being tagged. It contains the fields .Sq type with the object type and .Sq id with the object id being tagged. .It Dv message The tag message. .El .El .El .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotd.conf Location of the .Nm configuration file. .El .Sh EXAMPLES .Bd -literal -offset indent # Run as the default user: user _gotd # Listen on the default socket: listen on "/var/run/gotd.sock" # This repository can be accessed via ssh://user@example.com/src repository "src" { path "/var/git/src.git" permit rw flan_hacker permit rw :developers permit ro anonymous protect branch "main" protect tag namespace "refs/tags/" } # This repository can be accessed via # ssh://user@example.com/openbsd/ports repository "openbsd/ports" { path "/var/git/ports.git" permit rw :porters permit ro anonymous deny flan_hacker protect { branch "main" tag namespace "refs/tags/" } notify { branch "main" reference namespace "refs/tags/" email to openbsd-ports-changes@example.com .\" url https://example.com/notify/ user "flan_announcer" password "secret" } } # Use a larger request timeout value: connection request timeout 2h # Some users are granted a higher concurrent connection limit: connection { limit user flan_hacker 16 limit user anonymous 32 } .Ed .Sh SEE ALSO .Xr got 1 , .Xr gotsh 1 , .Xr gotd-secrets.conf 5 , .Xr gotd 8 got-portable-0.119/gotd/repo_imsg.c0000664000175000017500000000464115066536113012706 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_hash.h" #include "gotd.h" #include "log.h" void gotd_imsg_send_ack(struct got_object_id *id, struct imsgbuf *ibuf, uint32_t peerid, pid_t pid) { const struct got_error *err = NULL; struct gotd_imsg_ack iack; char hex[SHA1_DIGEST_STRING_LENGTH]; if (log_getverbose() > 0 && got_object_id_hex(id, hex, sizeof(hex))) log_debug("sending ACK for %s", hex); memset(&iack, 0, sizeof(iack)); memcpy(iack.object_id, id->hash, SHA1_DIGEST_LENGTH); if (imsg_compose(ibuf, GOTD_IMSG_ACK, peerid, pid, -1, &iack, sizeof(iack)) == -1) { err = got_error_from_errno("imsg_compose ACK"); goto done; } err = gotd_imsg_flush(ibuf); done: if (err) log_warnx("sending ACK: %s", err->msg); } void gotd_imsg_send_nak(struct got_object_id *id, struct imsgbuf *ibuf, uint32_t peerid, pid_t pid) { const struct got_error *err = NULL; struct gotd_imsg_nak inak; char hex[SHA1_DIGEST_STRING_LENGTH]; if (log_getverbose() > 0 && got_object_id_hex(id, hex, sizeof(hex))) log_debug("sending NAK for %s", hex); memset(&inak, 0, sizeof(inak)); memcpy(inak.object_id, id->hash, SHA1_DIGEST_LENGTH); if (imsg_compose(ibuf, GOTD_IMSG_NAK, peerid, pid, -1, &inak, sizeof(inak)) == -1) { err = got_error_from_errno("imsg_compose NAK"); goto done; } err = gotd_imsg_flush(ibuf); done: if (err) log_warnx("sending NAK: %s", err->msg); } got-portable-0.119/gotd/imsg.c0000664000175000017500000002667015066536113011667 /* * Copyright (c) 2022, 2025 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_poll.h" #include "gotd.h" static const struct got_error * gotd_imsg_recv(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen) { ssize_t n; n = imsg_get(ibuf, imsg); if (n == -1) return got_error_from_errno("imsg_get"); if (n == 0) { n = imsgbuf_read(ibuf); if (n == -1) return got_error_from_errno("imsgbuf_read"); if (n == 0) return got_error(GOT_ERR_EOF); n = imsg_get(ibuf, imsg); if (n == -1) return got_error_from_errno("imsg_get"); if (n == 0) return got_error(GOT_ERR_PRIVSEP_READ); } if (imsg->hdr.len < IMSG_HEADER_SIZE + min_datalen) return got_error(GOT_ERR_PRIVSEP_LEN); return NULL; } const struct got_error * gotd_imsg_poll_recv(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen) { const struct got_error *err = NULL; for (;;) { err = gotd_imsg_recv(imsg, ibuf, min_datalen); if (err == NULL || err->code != GOT_ERR_PRIVSEP_READ) return err; err = got_poll_fd(ibuf->fd, POLLIN, INFTIM); if (err) break; } return err; } int gotd_imsg_send_error_event(struct gotd_imsgev *iev, uint32_t peerid, uint32_t client_id, const struct got_error *err) { struct gotd_imsg_error ierr; int ret; ierr.code = err->code; if (err->code == GOT_ERR_ERRNO) ierr.errno_code = errno; else ierr.errno_code = 0; ierr.client_id = client_id; strlcpy(ierr.msg, err->msg, sizeof(ierr.msg)); ret = gotd_imsg_compose_event(iev, GOTD_IMSG_ERROR, peerid, -1, &ierr, sizeof(ierr)); if (ret == -1) return -1; return 0; } int gotd_imsg_forward(struct gotd_imsgev *iev, struct imsg *imsg, int fd) { return gotd_imsg_compose_event(iev, imsg->hdr.type, imsg->hdr.peerid, fd, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); } const struct got_error * gotd_imsg_recv_pathlist(size_t *npaths, struct imsg *imsg) { struct gotd_imsg_pathlist ilist; size_t datalen; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(ilist)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ilist, imsg->data, sizeof(ilist)); if (ilist.nelem == 0) return got_error(GOT_ERR_PRIVSEP_LEN); *npaths = ilist.nelem; return NULL; } const struct got_error * gotd_imsg_recv_pathlist_elem(struct imsg *imsg, struct got_pathlist_head *paths) { const struct got_error *err = NULL; struct gotd_imsg_pathlist_elem ielem; size_t datalen; char *path; struct got_pathlist_entry *pe; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(ielem)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&ielem, imsg->data, sizeof(ielem)); if (datalen != sizeof(ielem) + ielem.path_len) return got_error(GOT_ERR_PRIVSEP_LEN); path = strndup(imsg->data + sizeof(ielem), ielem.path_len); if (path == NULL) return got_error_from_errno("strndup"); err = got_pathlist_insert(&pe, paths, path, NULL); if (err || pe == NULL) free(path); return err; } void gotd_free_notification_target(struct gotd_notification_target *target) { if (target == NULL) return; switch (target->type) { case GOTD_NOTIFICATION_VIA_EMAIL: free(target->conf.email.sender); free(target->conf.email.recipient); free(target->conf.email.responder); free(target->conf.email.hostname); free(target->conf.email.port); break; case GOTD_NOTIFICATION_VIA_HTTP: free(target->conf.http.hostname); free(target->conf.http.port); free(target->conf.http.path); free(target->conf.http.auth); free(target->conf.http.hmac); break; default: break; } free(target); } const struct got_error * gotd_imsg_recv_notification_target_email(char **repo_name, struct gotd_notification_target **new_target, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_notitfication_target_email itarget; struct gotd_notification_target *target; size_t datalen; if (repo_name) *repo_name = NULL; *new_target = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(itarget)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&itarget, imsg->data, sizeof(itarget)); if (datalen != sizeof(itarget) + itarget.sender_len + itarget.recipient_len + itarget.responder_len + itarget.hostname_len + itarget.port_len + itarget.repo_name_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (itarget.sender_len == 0 || itarget.recipient_len == 0 || itarget.repo_name_len == 0) return got_error(GOT_ERR_PRIVSEP_LEN); target = calloc(1, sizeof(*target)); if (target == NULL) return got_error_from_errno("calloc"); target->type = GOTD_NOTIFICATION_VIA_EMAIL; if (itarget.sender_len) { target->conf.email.sender = strndup(imsg->data + sizeof(itarget), itarget.sender_len); if (target->conf.email.sender == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.email.sender) != itarget.sender_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } target->conf.email.recipient = strndup(imsg->data + sizeof(itarget) + itarget.sender_len, itarget.recipient_len); if (target->conf.email.recipient == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.email.recipient) != itarget.recipient_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (itarget.responder_len) { target->conf.email.responder = strndup(imsg->data + sizeof(itarget) + itarget.sender_len + itarget.recipient_len, itarget.responder_len); if (target->conf.email.responder == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.email.responder) != itarget.responder_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } if (itarget.hostname_len) { target->conf.email.hostname = strndup(imsg->data + sizeof(itarget) + itarget.sender_len + itarget.recipient_len + itarget.responder_len, itarget.hostname_len); if (target->conf.email.hostname == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.email.hostname) != itarget.hostname_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } if (itarget.port_len) { target->conf.email.port = strndup(imsg->data + sizeof(itarget) + itarget.sender_len + itarget.recipient_len + itarget.responder_len + itarget.hostname_len, itarget.port_len); if (target->conf.email.port == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.email.port) != itarget.port_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } if (repo_name) { *repo_name = strndup(imsg->data + sizeof(itarget) + itarget.sender_len + itarget.recipient_len + itarget.responder_len + itarget.hostname_len + itarget.port_len, itarget.repo_name_len); if (*repo_name == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(*repo_name) != itarget.repo_name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); free(*repo_name); *repo_name = NULL; goto done; } } *new_target = target; done: if (err) gotd_free_notification_target(target); return err; } const struct got_error * gotd_imsg_recv_notification_target_http(char **repo_name, struct gotd_notification_target **new_target, struct imsg *imsg) { const struct got_error *err = NULL; struct gotd_imsg_notitfication_target_http itarget; struct gotd_notification_target *target; size_t datalen; if (repo_name) *repo_name = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(itarget)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&itarget, imsg->data, sizeof(itarget)); if (datalen != sizeof(itarget) + itarget.hostname_len + itarget.port_len + itarget.path_len + itarget.auth_len + itarget.hmac_len + itarget.repo_name_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (itarget.hostname_len == 0 || itarget.port_len == 0 || itarget.path_len == 0 || itarget.repo_name_len == 0) return got_error(GOT_ERR_PRIVSEP_LEN); target = calloc(1, sizeof(*target)); if (target == NULL) return got_error_from_errno("calloc"); target->type = GOTD_NOTIFICATION_VIA_HTTP; target->conf.http.tls = itarget.tls; target->conf.http.hostname = strndup(imsg->data + sizeof(itarget), itarget.hostname_len); if (target->conf.http.hostname == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.http.hostname) != itarget.hostname_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } target->conf.http.port = strndup(imsg->data + sizeof(itarget) + itarget.hostname_len, itarget.port_len); if (target->conf.http.port == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.http.port) != itarget.port_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } target->conf.http.path = strndup(imsg->data + sizeof(itarget) + itarget.hostname_len + itarget.port_len, itarget.path_len); if (target->conf.http.path == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.http.path) != itarget.path_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } if (itarget.auth_len) { target->conf.http.auth = strndup(imsg->data + sizeof(itarget) + itarget.hostname_len + itarget.port_len + itarget.path_len, itarget.auth_len); if (target->conf.http.auth == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.http.auth) != itarget.auth_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } if (itarget.hmac_len) { target->conf.http.hmac = strndup(imsg->data + sizeof(itarget) + itarget.hostname_len + itarget.port_len + itarget.path_len + itarget.auth_len, itarget.hmac_len); if (target->conf.http.hmac == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(target->conf.http.hmac) != itarget.hmac_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } } if (repo_name) { *repo_name = strndup(imsg->data + sizeof(itarget) + itarget.hostname_len + itarget.port_len + itarget.path_len + itarget.auth_len + itarget.hmac_len, itarget.repo_name_len); if (*repo_name == NULL) { err = got_error_from_errno("strndup"); goto done; } if (strlen(*repo_name) != itarget.repo_name_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); free(*repo_name); *repo_name = NULL; goto done; } } *new_target = target; done: if (err) gotd_free_notification_target(target); return err; } got-portable-0.119/gotd/privsep_stub.c0000664000175000017500000000375715066536113013456 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "got_lib_delta.h" #include "got_lib_hash.h" #include "got_lib_object.h" #include "got_lib_object_cache.h" #include "got_lib_pack.h" #include "got_lib_repository.h" #include "got_lib_privsep.h" const struct got_error * got_privsep_send_stop(int fd) { return got_error(GOT_ERR_NOT_IMPL); } const struct got_error * got_privsep_wait_for_child(pid_t pid) { return got_error(GOT_ERR_NOT_IMPL); } void got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path) { fprintf(stderr, "%s: cannot run libexec helpers\n", getprogname()); exit(1); } const struct got_error * got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack, struct got_packidx *packidx) { return got_error(GOT_ERR_NOT_IMPL); } const struct got_error * got_traverse_packed_commits(struct got_object_id_queue *traversed_commits, struct got_object_id *commit_id, const char *path, struct got_repository *repo) { return NULL; } got-portable-0.119/gotd/session_write.h0000664000175000017500000000155015066535721013624 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void session_write_main(const char *, const char *, int *, int *, int); got-portable-0.119/gotd/auth.c0000664000175000017500000002333115066536113011660 /* * Copyright (c) 2022 Stefan Sperling * Copyright (c) 2015 Ted Unangst * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_path.h" #include "gotd.h" #include "log.h" #include "auth.h" static struct gotd_auth { pid_t pid; const char *title; struct gotd_access_rule_list rules; } gotd_auth; static void auth_shutdown(void); static void auth_sighdlr(int sig, short event, void *arg) { /* * Normal signal handler rules don't apply because libevent * decouples for us. */ switch (sig) { case SIGHUP: break; case SIGUSR1: break; case SIGTERM: case SIGINT: auth_shutdown(); /* NOTREACHED */ break; default: fatalx("unexpected signal"); } } static int uidcheck(const char *s, uid_t desired) { uid_t uid; if (gotd_parseuid(s, &uid) != 0) return -1; if (uid != desired) return -1; return 0; } static int parsegid(const char *s, gid_t *gid) { struct group *gr; const char *errstr; if ((gr = getgrnam(s)) != NULL) { *gid = gr->gr_gid; if (*gid == GID_MAX) return -1; return 0; } *gid = strtonum(s, 0, GID_MAX - 1, &errstr); if (errstr) return -1; return 0; } static int match_identifier(const char *identifier, gid_t *groups, int ngroups, uid_t euid, gid_t egid) { int i; if (identifier[0] == ':') { gid_t rgid; if (parsegid(identifier + 1, &rgid) == -1) return 0; if (rgid == egid) return 1; for (i = 0; i < ngroups; i++) { if (rgid == groups[i]) break; } if (i == ngroups) return 0; } else if (uidcheck(identifier, euid) != 0) return 0; return 1; } static const struct got_error * auth_check(char **username, struct gotd_access_rule_list *rules, const char *repo_name, uid_t euid, gid_t egid, int required_auth) { struct gotd_access_rule *rule; enum gotd_access access = GOTD_ACCESS_DENIED; struct passwd *pw; gid_t groups[NGROUPS_MAX]; int ngroups = NGROUPS_MAX; int matched_user = 0; *username = NULL; pw = getpwuid(euid); if (pw == NULL) { if (errno) return got_error_from_errno("getpwuid"); else return got_error_set_errno(EACCES, repo_name); } *username = strdup(pw->pw_name); if (*username == NULL) return got_error_from_errno("strdup"); if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) log_warnx("group membership list truncated"); STAILQ_FOREACH(rule, rules, entry) { if (!match_identifier(rule->identifier, groups, ngroups, euid, egid)) continue; matched_user = 1; access = rule->access; if (rule->access == GOTD_ACCESS_PERMITTED && (rule->authorization & required_auth) != required_auth) access = GOTD_ACCESS_DENIED; } if (access == GOTD_ACCESS_DENIED) { /* * If a user has no explicit read or write access then * do not leak the existence of a repository to them. */ if (!matched_user) return got_error(GOT_ERR_NOT_GIT_REPO); else return got_error_set_errno(EACCES, repo_name); } if (access == GOTD_ACCESS_PERMITTED) return NULL; /* should not happen, this would be a bug */ return got_error_msg(GOT_ERR_NOT_IMPL, "bad access rule"); } static const struct got_error * recv_authreq(struct imsg *imsg, struct gotd_imsgev *iev) { const struct got_error *err; struct imsgbuf *ibuf = &iev->ibuf; struct gotd_imsg_auth iauth; size_t datalen; uid_t euid; gid_t egid; char *username = NULL; size_t len; const size_t maxlen = MAX_IMSGSIZE - IMSG_HEADER_SIZE; int fd = -1; log_debug("authentication request received"); datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != sizeof(iauth)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&iauth, imsg->data, datalen); fd = imsg_get_fd(imsg); if (fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); if (getpeereid(fd, &euid, &egid) == -1) return got_error_from_errno("getpeerid"); if (iauth.euid != euid) return got_error(GOT_ERR_UID); if (iauth.egid != egid) return got_error(GOT_ERR_GID); len = strnlen(iauth.repo_name, sizeof(iauth.repo_name)); if (len == 0 || len >= sizeof(iauth.repo_name)) return got_error(GOT_ERR_PRIVSEP_LEN); iauth.repo_name[len] = '\0'; log_debug("authenticating uid %d gid %d", euid, egid); err = auth_check(&username, &gotd_auth.rules, iauth.repo_name, iauth.euid, iauth.egid, iauth.required_auth); if (err) { gotd_imsg_send_error(ibuf, GOTD_PROC_AUTH, iauth.client_id, err); goto done; } len = strlen(username); if (len > maxlen) len = maxlen; if (gotd_imsg_compose_event(iev, GOTD_IMSG_ACCESS_GRANTED, GOTD_PROC_AUTH, -1, username, len) == -1) err = got_error_from_errno("imsg compose ACCESS_GRANTED"); done: free(username); return err; } static const struct got_error * recv_access_rule(struct imsg *imsg) { const struct got_error *err; struct gotd_imsg_auth_access_rule irule; enum gotd_access access; size_t datalen; char *identifier = NULL; struct gotd_access_rule *rule = NULL; datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen < sizeof(irule)) return got_error(GOT_ERR_PRIVSEP_LEN); memcpy(&irule, imsg->data, sizeof(irule)); if (datalen != sizeof(irule) + irule.identifier_len) return got_error(GOT_ERR_PRIVSEP_LEN); if (irule.identifier_len == 0) { return got_error_msg(GOT_ERR_PRIVSEP_LEN, "empty access rule identifier"); } if (irule.identifier_len > _PW_NAME_LEN) { return got_error_msg(GOT_ERR_PRIVSEP_LEN, "access rule identifier too long"); } switch (irule.access) { case GOTD_ACCESS_PERMITTED: if (irule.authorization == 0) { return got_error_msg(GOT_ERR_PRIVSEP_MSG, "permit access rule without read or write " "authorization"); } access = GOTD_ACCESS_PERMITTED; break; case GOTD_ACCESS_DENIED: if (irule.authorization != 0) { return got_error_msg(GOT_ERR_PRIVSEP_MSG, "deny access rule with read or write " "authorization"); } access = GOTD_ACCESS_DENIED; break; default: return got_error_msg(GOT_ERR_PRIVSEP_MSG, "invalid access rule"); } if (irule.authorization & ~(GOTD_AUTH_READ | GOTD_AUTH_WRITE)) { return got_error_msg(GOT_ERR_PRIVSEP_MSG, "invalid access rule authorization flags"); } identifier = strndup(imsg->data + sizeof(irule), irule.identifier_len); if (identifier == NULL) return got_error_from_errno("strndup"); if (strlen(identifier) != irule.identifier_len) { err = got_error(GOT_ERR_PRIVSEP_LEN); free(identifier); return err; } rule = calloc(1, sizeof(*rule)); if (rule == NULL) return got_error_from_errno("calloc"); rule->access = access; rule->authorization = irule.authorization; rule->identifier = identifier; STAILQ_INSERT_TAIL(&gotd_auth.rules, rule, entry); return NULL; } static void auth_dispatch(int fd, short event, void *arg) { const struct got_error *err = NULL; struct gotd_imsgev *iev = arg; struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed. */ shut = 1; } if (event & EV_WRITE) { err = gotd_imsg_flush(ibuf); if (err) fatalx("%s", err->msg); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("%s: imsg_get", __func__); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTD_IMSG_AUTH_ACCESS_RULE: err = recv_access_rule(&imsg); break; case GOTD_IMSG_AUTHENTICATE: err = recv_authreq(&imsg, iev); if (err) log_warnx("%s", err->msg); break; default: log_debug("unexpected imsg %d", imsg.hdr.type); break; } imsg_free(&imsg); } if (!shut) { gotd_imsg_event_add(iev); } else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void auth_main(const char *title) { struct gotd_imsgev iev; struct event evsigint, evsigterm, evsighup, evsigusr1; gotd_auth.title = title; gotd_auth.pid = getpid(); STAILQ_INIT(&gotd_auth.rules); signal_set(&evsigint, SIGINT, auth_sighdlr, NULL); signal_set(&evsigterm, SIGTERM, auth_sighdlr, NULL); signal_set(&evsighup, SIGHUP, auth_sighdlr, NULL); signal_set(&evsigusr1, SIGUSR1, auth_sighdlr, NULL); signal(SIGPIPE, SIG_IGN); signal_add(&evsigint, NULL); signal_add(&evsigterm, NULL); signal_add(&evsighup, NULL); signal_add(&evsigusr1, NULL); if (imsgbuf_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev.ibuf); iev.handler = auth_dispatch; iev.events = EV_READ; iev.handler_arg = NULL; event_set(&iev.ev, iev.ibuf.fd, EV_READ, auth_dispatch, &iev); if (gotd_imsg_compose_event(&iev, GOTD_IMSG_AUTH_READY, GOTD_PROC_AUTH, -1, NULL, 0) == -1) fatal("imsg compose AUTH_READY"); event_dispatch(); auth_shutdown(); } static void auth_shutdown(void) { log_debug("%s: shutting down", gotd_auth.title); exit(0); } got-portable-0.119/gotd/session_read.h0000664000175000017500000000154215066535721013406 /* * Copyright (c) 2022, 2023 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void session_read_main(const char *, const char *, int *, int *); got-portable-0.119/gotd/gotd.h0000664000175000017500000004457415066536113011675 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #define GOTD_UNIX_SOCKET "/var/run/gotd.sock" #define GOTD_UNIX_SOCKET_BACKLOG 10 #define GOTD_USER "_gotd" #define GOTD_CONF_PATH "/etc/gotd.conf" #define GOTD_SECRETS_PATH "/etc/gotd-secrets.conf" #ifndef GOTD_EMPTY_PATH #define GOTD_EMPTY_PATH "/var/empty" #endif #ifndef GOT_LIBEXECDIR #define GOT_LIBEXECDIR /usr/libexec #endif #define GOTD_STRINGIFY(x) #x #define GOTD_STRINGVAL(x) GOTD_STRINGIFY(x) #define GOTD_PROG_NOTIFY_EMAIL got-notify-email #define GOTD_PROG_NOTIFY_HTTP got-notify-http #define GOTD_PROG_GOTSYS_CHECK gotsys-check #define GOTD_PROG_GOTSYS_APPLY gotsys-apply #define GOTD_PATH_PROG_NOTIFY_EMAIL \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_NOTIFY_EMAIL) #define GOTD_PATH_PROG_NOTIFY_HTTP \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_NOTIFY_HTTP) #define GOTD_PATH_PROG_GOTSYS_CHECK \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_GOTSYS_CHECK) #define GOTD_PATH_PROG_GOTSYS_APPLY \ GOTD_STRINGVAL(GOT_LIBEXECDIR) "/" \ GOTD_STRINGVAL(GOTD_PROG_GOTSYS_APPLY) #define GOTD_MAXCLIENTS 1024 #define GOTD_MAX_CONN_PER_UID 4 #define GOTD_FD_RESERVE 5 #define GOTD_FD_NEEDED 6 #define GOTD_FILENO_MSG_PIPE 3 #define GOTD_DEFAULT_REQUEST_TIMEOUT 3600 /* Client hash tables need some extra room. */ #define GOTD_CLIENT_TABLE_SIZE (GOTD_MAXCLIENTS * 4) enum gotd_procid { GOTD_PROC_GOTD = 0, GOTD_PROC_LISTEN, GOTD_PROC_AUTH, GOTD_PROC_SESSION_READ, GOTD_PROC_SESSION_WRITE, GOTD_PROC_REPO_READ, GOTD_PROC_REPO_WRITE, GOTD_PROC_GITWRAPPER, GOTD_PROC_NOTIFY, GOTD_PROC_GOTSYS_CHECK, GOTD_PROC_GOTSYS_APPLY, GOTD_PROC_RELOAD, GOTD_PROC_GOTCTL, GOTD_PROC_MAX, }; struct gotd_imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); void *handler_arg; struct event ev; short events; }; enum gotd_access { GOTD_ACCESS_DENIED = -1, GOTD_ACCESS_PERMITTED = 1 }; struct gotd_access_rule { STAILQ_ENTRY(gotd_access_rule) entry; enum gotd_access access; int authorization; #define GOTD_AUTH_READ 0x1 #define GOTD_AUTH_WRITE 0x2 char *identifier; }; STAILQ_HEAD(gotd_access_rule_list, gotd_access_rule); enum gotd_notification_target_type { GOTD_NOTIFICATION_VIA_EMAIL, GOTD_NOTIFICATION_VIA_HTTP }; struct gotd_notification_target { STAILQ_ENTRY(gotd_notification_target) entry; enum gotd_notification_target_type type; union { struct { char *sender; char *recipient; char *responder; char *hostname; char *port; } email; struct { int tls; char *hostname; char *port; char *path; char *auth; char *hmac; } http; } conf; }; STAILQ_HEAD(gotd_notification_targets, gotd_notification_target); struct gotd_repo { TAILQ_ENTRY(gotd_repo) entry; char name[NAME_MAX]; char path[PATH_MAX]; struct gotd_access_rule_list rules; struct got_pathlist_head protected_tag_namespaces; size_t nprotected_tag_namespaces; struct got_pathlist_head protected_branch_namespaces; size_t nprotected_branch_namespaces; struct got_pathlist_head protected_branches; size_t nprotected_branches; struct got_pathlist_head notification_refs; size_t num_notification_refs; struct got_pathlist_head notification_ref_namespaces; size_t num_notification_ref_namespaces; struct gotd_notification_targets notification_targets; }; TAILQ_HEAD(gotd_repolist, gotd_repo); struct gotd_client_capability { char *key; char *value; }; struct gotd_object_id_array { struct got_object_id **ids; size_t nalloc; size_t nids; }; struct gotd_uid_connection_limit { uid_t uid; int max_connections; }; struct gotd_child_proc; struct gotd_secrets; struct gotd { pid_t pid; char unix_socket_path[PATH_MAX]; char user_name[32]; struct gotd_repolist repos; int nrepos; struct gotd_child_proc *listen_proc; struct gotd_child_proc *notify_proc; struct gotd_child_proc *reload_proc; int notifications_enabled; struct timeval request_timeout; struct timeval auth_timeout; struct gotd_uid_connection_limit *connection_limits; size_t nconnection_limits; struct gotd_secrets *secrets; char *default_sender; char *argv0; const char *confpath; int daemonize; int verbosity; }; enum gotd_imsg_type { /* An error occurred while processing a request. */ GOTD_IMSG_ERROR, /* Commands used by gotctl(8). */ GOTD_IMSG_INFO, GOTD_IMSG_INFO_REPO, GOTD_IMSG_INFO_CLIENT, GOTD_IMSG_STOP, GOTD_IMSG_RELOAD, /* Request a list of references. */ GOTD_IMSG_LIST_REFS, GOTD_IMSG_LIST_REFS_INTERNAL, /* References. */ GOTD_IMSG_REFLIST, GOTD_IMSG_REF, GOTD_IMSG_SYMREF, /* Git protocol capabilities. */ GOTD_IMSG_CAPABILITIES, GOTD_IMSG_CAPABILITY, /* Git protocol chatter. */ GOTD_IMSG_WANT, /* The client wants an object. */ GOTD_IMSG_HAVE, /* The client has an object. */ GOTD_IMSG_ACK, /* The server has an object or a reference. */ GOTD_IMSG_NAK, /* The server does not have an object/ref. */ GOTD_IMSG_REF_UPDATE, /* The client wants to update a reference. */ GOTD_IMSG_REF_DELETE, /* The client wants to delete a reference. */ GOTD_IMSG_FLUSH, /* The client sent a flush packet. */ GOTD_IMSG_DONE, /* The client is done chatting. */ /* Sending or receiving a pack file. */ GOTD_IMSG_SEND_PACKFILE, /* The server is sending a pack file. */ GOTD_IMSG_RECV_PACKFILE, /* The server is receiving a pack file. */ GOTD_IMSG_PACKFILE_RECEIVED, GOTD_IMSG_PACKIDX_FILE, /* Temporary file handle for new pack index. */ GOTD_IMSG_PACKFILE_PIPE, /* Pipe to send/receive a pack file stream. */ GOTD_IMSG_PACKFILE_PROGRESS, /* Progress reporting. */ GOTD_IMSG_PACKFILE_READY, /* Pack file is ready to be sent. */ GOTD_IMSG_PACKFILE_STATUS, /* Received pack success/failure status. */ GOTD_IMSG_PACKFILE_INSTALL, /* Received pack file can be installed. */ GOTD_IMSG_PACKFILE_DONE, /* Pack file has been sent/received. */ /* Pack file content verification. */ GOTD_IMSG_PACKFILE_GET_CONTENT, GOTD_IMSG_PACKFILE_CONTENT_WRITTEN, GOTD_IMSG_RUN_GOTSYS_CHECK, GOTD_IMSG_PACKFILE_VERIFIED, /* Reference updates. */ GOTD_IMSG_REF_UPDATES_START, /* Ref updates starting. */ GOTD_IMSG_REF_UPDATE_OK, /* Update went OK. */ GOTD_IMSG_REF_UPDATE_NG, /* Update was not good. */ GOTD_IMSG_REFS_UPDATED, /* The server processed all ref updates. */ /* Client connections. */ GOTD_IMSG_LISTENER_READY, GOTD_IMSG_LISTEN_SOCKET, GOTD_IMSG_CONNECTION_LIMIT, GOTD_IMSG_REQUEST_TIMEOUT, GOTD_IMSG_DISCONNECT, GOTD_IMSG_CONNECT, /* Child process management. */ GOTD_IMSG_CLIENT_SESSION_READY, GOTD_IMSG_REPO_CHILD_READY, GOTD_IMSG_CONNECT_REPO_CHILD, /* Reloading. */ GOTD_IMSG_RELOAD_READY, GOTD_IMSG_RELOAD_SECRETS, GOTD_IMSG_GOTD_CONF, GOTD_IMSG_HALT, /* Auth child process. */ GOTD_IMSG_AUTH_READY, GOTD_IMSG_AUTH_ACCESS_RULE, GOTD_IMSG_AUTHENTICATE, GOTD_IMSG_ACCESS_GRANTED, /* Protected references. */ GOTD_IMSG_PROTECTED_TAG_NAMESPACES, GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM, GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES, GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM, GOTD_IMSG_PROTECTED_BRANCHES, GOTD_IMSG_PROTECTED_BRANCHES_ELEM, /* Notify child process. */ GOTD_IMSG_NOTIFIER_READY, GOTD_IMSG_NOTIFICATION_REFS, GOTD_IMSG_NOTIFICATION_REFS_ELEM, GOTD_IMSG_NOTIFICATION_REF_NAMESPACES, GOTD_IMSG_NOTIFICATION_REF_NAMESPACES_ELEM, GOTD_IMSG_NOTIFICATION_TARGET_EMAIL, GOTD_IMSG_NOTIFICATION_TARGET_HTTP, GOTD_IMSG_CONNECT_NOTIFIER, GOTD_IMSG_CONNECT_SESSION, GOTD_IMSG_NOTIFY, GOTD_IMSG_NOTIFICATION_SENT, /* Secrets. */ GOTD_IMSG_SECRETS, /* number of secrets */ GOTD_IMSG_SECRET, /* gotsys.conf */ GOTD_IMSG_GOTSYS_READY, GOTD_IMSG_GOTSYS_CHECK, GOTD_IMSG_GOTSYS_CFG_OK, GOTD_IMSG_GOTSYS_APPLY, GOTD_IMSG_SYSCONF_STARTED, }; /* Structure for GOTD_IMSG_ERROR. */ struct gotd_imsg_error { int code; /* an error code from got_error.h */ int errno_code; /* in case code equals GOT_ERR_ERRNO */ uint32_t client_id; char msg[GOT_ERR_MAX_MSG_SIZE]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_INFO. */ struct gotd_imsg_info { pid_t pid; int verbosity; int nrepos; int nclients; /* Followed by nrepos GOTD_IMSG_INFO_REPO messages. */ /* Followed by nclients GOTD_IMSG_INFO_CLIENT messages. */ }; /* Structure for GOTD_IMSG_INFO_REPO. */ struct gotd_imsg_info_repo { char repo_name[NAME_MAX]; char repo_path[PATH_MAX]; }; /* Structure for GOTD_IMSG_INFO_CLIENT */ struct gotd_imsg_info_client { uid_t euid; gid_t egid; char repo_name[NAME_MAX]; int is_writing; pid_t session_child_pid; pid_t repo_child_pid; time_t time_connected; }; /* Structure for GOTD_IMSG_LIST_REFS. */ struct gotd_imsg_list_refs { char repo_name[NAME_MAX]; int client_is_reading; /* 1 if reading, 0 if writing */ }; /* Structure for GOTD_IMSG_REFLIST. */ struct gotd_imsg_reflist { size_t nrefs; /* Followed by nrefs times of gotd_imsg_ref/gotd_imsg_symref data. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF data. */ struct gotd_imsg_ref { uint8_t id[SHA1_DIGEST_LENGTH]; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_SYMREF data. */ struct gotd_imsg_symref { size_t name_len; size_t target_len; uint8_t target_id[SHA1_DIGEST_LENGTH]; /* * Followed by name_len + target_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_CAPABILITIES data. */ struct gotd_imsg_capabilities { size_t ncapabilities; /* * Followed by ncapabilities * GOTD_IMSG_CAPABILITY. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_CAPABILITY data. */ struct gotd_imsg_capability { size_t key_len; size_t value_len; /* * Followed by key_len + value_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_WANT data. */ struct gotd_imsg_want { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_HAVE data. */ struct gotd_imsg_have { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_ACK data. */ struct gotd_imsg_ack { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_NAK data. */ struct gotd_imsg_nak { uint8_t object_id[SHA1_DIGEST_LENGTH]; } __attribute__((__packed__)); /* Structure for GOTD_IMSG_PACKFILE_STATUS data. */ struct gotd_imsg_packfile_status { size_t reason_len; /* Followed by reason_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF_UPDATE data. */ struct gotd_imsg_ref_update { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; int ref_is_new; int delete_ref; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_PACKFILE_GET_CONTENT. */ struct gotd_imsg_packfile_get_content { size_t refname_len; size_t path_len; /* Followed by refname_len + path_len data bytes. */ /* Content file descriptor is passed via imsg. */ }; /* Structure for GOTD_IMSG_PACKFILE_CONTENT_WRITTEN. */ struct gotd_imsg_packfile_content_written { /* If zero, the requested reference is not being updated. */ int ref_found; /* * If wrote_content is zero, nothing was found at the requested path. * * Else, content as it appears in the pack file was written to the * file descriptor. If this content is empty, the file will be empty. */ int wrote_content; }; /* Structure for GOTD_IMSG_REF_UPDATES_START data. */ struct gotd_imsg_ref_updates_start { int nref_updates; /* Followed by nref_updates GOT_IMSG_REF_UPDATE_OK/NG messages. */ }; /* Structure for GOTD_IMSG_REF_UPDATE_OK data. */ struct gotd_imsg_ref_update_ok { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; int ref_is_new; size_t name_len; /* Followed by name_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_REF_UPDATE_NG data. */ struct gotd_imsg_ref_update_ng { uint8_t old_id[SHA1_DIGEST_LENGTH]; uint8_t new_id[SHA1_DIGEST_LENGTH]; size_t name_len; size_t reason_len; /* Followed by name_len + reason_len data bytes. */ } __attribute__((__packed__)); /* Structure for GOTD_IMSG_SEND_PACKFILE data. */ struct gotd_imsg_send_packfile { int report_progress; /* delta cache file is sent as a file descriptor */ /* followed by two GOTD_IMSG_PACKFILE_PIPE messages */ }; /* Structure for GOTD_IMSG_RECV_PACKFILE data. */ struct gotd_imsg_recv_packfile { int report_status; /* pack destination temp file is sent as a file descriptor */ }; /* Structure for GOTD_IMSG_PACKFILE_RECEIVED data. */ struct gotd_imsg_packfile_received { int pack_empty; }; /* * Structure for GOTD_IMSG_PACKFILE_PROGRESS and * GOTD_IMSG_PACKFILE_READY data. */ struct gotd_imsg_packfile_progress { int ncolored; int nfound; int ntrees; off_t packfile_size; int ncommits; int nobj_total; int nobj_deltify; int nobj_written; }; /* Structure for GOTD_IMSG_PACKFILE_INSTALL. */ struct gotd_imsg_packfile_install { uint8_t pack_sha1[SHA1_DIGEST_LENGTH]; }; /* Structure for GOTD_IMSG_LISTEN_SOCKET data. */ struct gotd_imsg_listen_socket { size_t nconnection_limits; /* listen fd passed via imsg */ }; /* Structure for GOTD_IMSG_DISCONNECT data. */ struct gotd_imsg_disconnect { uint32_t client_id; }; /* Structure for GOTD_IMSG_CONNECT. */ struct gotd_imsg_connect { uint32_t client_id; uid_t euid; gid_t egid; size_t username_len; /* Followed by username_len data bytes. */ }; /* Structure for GOTD_IMSG_CONNECT_REPO_CHILD. */ struct gotd_imsg_connect_repo_child { char repo_name[NAME_MAX]; enum gotd_procid proc_id; /* repo child imsg pipe is passed via imsg fd */ }; /* Structure for GOTD_IMSG_AUTHENTICATE. */ struct gotd_imsg_auth { uid_t euid; gid_t egid; int required_auth; uint32_t client_id; char repo_name[NAME_MAX]; }; /* Structure for GOTD_IMSG_AUTH_ACCESS_RULE. */ struct gotd_imsg_auth_access_rule { enum gotd_access access; int authorization; size_t identifier_len; /* Followed by identifier_len bytes. */ }; /* * Structure for sending path lists over imsg. Used with: * GOTD_IMSG_PROTECTED_TAG_NAMESPACES * GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES * GOTD_IMSG_PROTECTED_BRANCHES * GOTD_IMSG_NOTIFY_BRANCHES * GOTD_IMSG_NOTIFY_REF_NAMESPACES */ struct gotd_imsg_pathlist { size_t nelem; /* Followed by nelem path list elements. */ }; /* * Structure for a path list element. Used with: * GOTD_IMSG_PROTECTED_TAG_NAMESPACES_ELEM * GOTD_IMSG_PROTECTED_BRANCH_NAMESPACES_ELEM * GOTD_IMSG_PROTECTED_BRANCHES_ELEM * GOTD_IMSG_NOTIFY_BRANCHES_ELEM * GOTD_IMSG_NOTIFY_REF_NAMESPACES_ELEM */ struct gotd_imsg_pathlist_elem { size_t path_len; size_t data_len; /* Followed by path_len bytes. */ /* Followed by data_len bytes. */ }; /* Structure for GOTD_IMSG_NOTIFICATION_TARGET_EMAIL. */ struct gotd_imsg_notitfication_target_email { size_t sender_len; size_t recipient_len; size_t responder_len; size_t hostname_len; size_t port_len; size_t repo_name_len; /* * Followed by sender_len + responder_len + responder_len + * hostname_len + port_len + repo_name_len bytes. */ }; /* Structure for GOTD_IMSG_NOTIFICATION_TARGET_HTTP. */ struct gotd_imsg_notitfication_target_http { int tls; size_t hostname_len; size_t port_len; size_t path_len; size_t auth_len; size_t hmac_len;; size_t repo_name_len; /* * Followed by hostname_len + port_len + path_len + auth_len + * hmac_len + repo_name_len bytes. */ }; /* Structures for GOTD_IMSG_NOTIFY. */ enum gotd_notification_action { GOTD_NOTIF_ACTION_CREATED, GOTD_NOTIF_ACTION_REMOVED, GOTD_NOTIF_ACTION_CHANGED }; /* IMSG_NOTIFY session <-> repo_write */ struct gotd_imsg_notification_content { enum gotd_notification_action action; struct got_object_id old_id; struct got_object_id new_id; size_t refname_len; /* Followed by refname_len data bytes. */ }; /* IMSG_NOTIFY session -> notify*/ struct gotd_imsg_notify { char repo_name[NAME_MAX]; char subject_line[64]; size_t username_len; /* Followed by username_len data bytes. */ }; int enter_chroot(const char *); int gotd_parse_config(const char *, int, enum gotd_procid, struct gotd_secrets *, struct gotd *); struct gotd_repo *gotd_find_repo_by_name(const char *, struct gotd_repolist *); struct gotd_repo *gotd_find_repo_by_path(const char *, struct gotd *); struct gotd_uid_connection_limit *gotd_find_uid_connection_limit( struct gotd_uid_connection_limit *limits, size_t nlimits, uid_t uid); int gotd_parseuid(const char *s, uid_t *uid); const struct got_error *gotd_parse_url(char **, char **, char **, char **, const char *); const struct got_error *gotd_conf_new_repo(struct gotd_repo **, const char *); /* imsg.c */ const struct got_error *gotd_imsg_flush(struct imsgbuf *); const struct got_error *gotd_imsg_poll_recv(struct imsg *, struct imsgbuf *, size_t); const struct got_error *gotd_imsg_recv_error(uint32_t *client_id, struct imsg *imsg); int gotd_imsg_send_error(struct imsgbuf *ibuf, uint32_t, uint32_t, const struct got_error *); int gotd_imsg_send_error_event(struct gotd_imsgev *, uint32_t, uint32_t, const struct got_error *); void gotd_imsg_event_add(struct gotd_imsgev *); int gotd_imsg_compose_event(struct gotd_imsgev *, uint16_t, uint32_t, int, void *, uint16_t); int gotd_imsg_forward(struct gotd_imsgev *, struct imsg *, int); void gotd_imsg_send_ack(struct got_object_id *, struct imsgbuf *, uint32_t, pid_t); void gotd_imsg_send_nak(struct got_object_id *, struct imsgbuf *, uint32_t, pid_t); const struct got_error *gotd_imsg_recv_pathlist(size_t *, struct imsg *); const struct got_error *gotd_imsg_recv_pathlist_elem(struct imsg *, struct got_pathlist_head *); void gotd_free_notification_target(struct gotd_notification_target *); const struct got_error *gotd_imsg_recv_notification_target_email(char **, struct gotd_notification_target **, struct imsg *); const struct got_error *gotd_imsg_recv_notification_target_http(char **, struct gotd_notification_target **, struct imsg *); got-portable-0.119/gotd/chroot-notobsd.c0000664000175000017500000000206015066536113013657 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include "log.h" int enter_chroot(const char *path) { log_info("chroot into %s", path); if (chroot(path) == -1) fatal("chroot"); if (chdir("/") == -1) fatal("chdir(\"/\")"); return 1; } got-portable-0.119/gotd/Makefile.in0000664000175000017500000015730115066537207012632 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = gotd$(EXEEXT) @HOST_OPENBSD_FALSE@am__append_1 = chroot-notobsd.c @HOST_OPENBSD_TRUE@am__append_2 = chroot-openbsd.c @HOST_FREEBSD_TRUE@am__append_3 = -lmd subdir = gotd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" PROGRAMS = $(sbin_PROGRAMS) am__gotd_SOURCES_DIST = gotd.c $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotd_imsg.c $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c $(top_srcdir)/lib/sigs.c auth.c \ imsg.c listen.c notify.c parse.y privsep_stub.c repo_imsg.c \ repo_read.c repo_write.c secrets.c session_read.c \ session_write.c chroot-notobsd.c chroot-openbsd.c am__dirstamp = $(am__leading_dot)dirstamp @HOST_OPENBSD_FALSE@am__objects_1 = chroot-notobsd.$(OBJEXT) @HOST_OPENBSD_TRUE@am__objects_2 = chroot-openbsd.$(OBJEXT) am_gotd_OBJECTS = gotd.$(OBJEXT) $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/deltify.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/gitconfig.$(OBJEXT) \ $(top_builddir)/lib/gotd_imsg.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_io.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/pack_create.$(OBJEXT) \ $(top_builddir)/lib/pack_create_io.$(OBJEXT) \ $(top_builddir)/lib/pack_index.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/ratelimit.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) auth.$(OBJEXT) \ imsg.$(OBJEXT) listen.$(OBJEXT) notify.$(OBJEXT) \ parse.$(OBJEXT) privsep_stub.$(OBJEXT) repo_imsg.$(OBJEXT) \ repo_read.$(OBJEXT) repo_write.$(OBJEXT) secrets.$(OBJEXT) \ session_read.$(OBJEXT) session_write.$(OBJEXT) \ $(am__objects_1) $(am__objects_2) gotd_OBJECTS = $(am_gotd_OBJECTS) gotd_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/deltify.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po \ $(top_builddir)/lib/$(DEPDIR)/pack_index.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po ./$(DEPDIR)/auth.Po \ ./$(DEPDIR)/chroot-notobsd.Po ./$(DEPDIR)/chroot-openbsd.Po \ ./$(DEPDIR)/gotd.Po ./$(DEPDIR)/imsg.Po ./$(DEPDIR)/listen.Po \ ./$(DEPDIR)/notify.Po ./$(DEPDIR)/parse.Po \ ./$(DEPDIR)/privsep_stub.Po ./$(DEPDIR)/repo_imsg.Po \ ./$(DEPDIR)/repo_read.Po ./$(DEPDIR)/repo_write.Po \ ./$(DEPDIR)/secrets.Po ./$(DEPDIR)/session_read.Po \ ./$(DEPDIR)/session_write.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gotd_SOURCES) DIST_SOURCES = $(am__gotd_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man5_MANS) $(man8_MANS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ -DGOTD_EMPTY_PATH='"@GOTD_EMPTY_PATHC@"' \ $(libuuid_CFLAGS) $(zlib_CFLAGS) $(libbsd_CFLAGS) \ $(libevent_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ SUBDIRS = libexec gotd_SOURCES = gotd.c $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c $(top_srcdir)/lib/gitconfig.c \ $(top_srcdir)/lib/gotd_imsg.c $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_io.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_io.c \ $(top_srcdir)/lib/pack_index.c $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig.c \ $(top_srcdir)/lib/read_gotconfig.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c $(top_srcdir)/lib/sigs.c auth.c \ imsg.c listen.c notify.c parse.y privsep_stub.c repo_imsg.c \ repo_read.c repo_write.c secrets.c session_read.c \ session_write.c $(am__append_1) $(am__append_2) gotd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotd.8 gotd.conf.5 gotd-secrets.conf.5 *.h man5_MANS = gotd.conf.5 gotd-secrets.conf.5 man8_MANS = gotd.8 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm $(libuuid_LIBS) \ $(zlib_LIBS) $(libbsd_LIBS) $(libevent_LIBS) $(libutil_LIBS) \ $(am__append_3) all: all-recursive .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && $(am__rm_f) $$files clean-sbinPROGRAMS: -$(am__rm_f) $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deltify.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotd_imsg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_io.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_create_io.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack_index.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/ratelimit.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) gotd$(EXEEXT): $(gotd_OBJECTS) $(gotd_DEPENDENCIES) $(EXTRA_gotd_DEPENDENCIES) @rm -f gotd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotd_OBJECTS) $(gotd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deltify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack_index.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/ratelimit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chroot-notobsd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chroot-openbsd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privsep_stub.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_imsg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_read.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repo_write.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/secrets.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_read.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_write.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man5: $(man5_MANS) @$(NORMAL_INSTALL) @list1='$(man5_MANS)'; \ list2=''; \ test -n "$(man5dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.5[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ done; } uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) $(MANS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -$(am__rm_f) parse.c clean: clean-recursive clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/chroot-notobsd.Po -rm -f ./$(DEPDIR)/chroot-openbsd.Po -rm -f ./$(DEPDIR)/gotd.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/listen.Po -rm -f ./$(DEPDIR)/notify.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/privsep_stub.Po -rm -f ./$(DEPDIR)/repo_imsg.Po -rm -f ./$(DEPDIR)/repo_read.Po -rm -f ./$(DEPDIR)/repo_write.Po -rm -f ./$(DEPDIR)/secrets.Po -rm -f ./$(DEPDIR)/session_read.Po -rm -f ./$(DEPDIR)/session_write.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-man install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-man5 install-man8 install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deltify.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotd_imsg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_create_io.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack_index.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/ratelimit.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/chroot-notobsd.Po -rm -f ./$(DEPDIR)/chroot-openbsd.Po -rm -f ./$(DEPDIR)/gotd.Po -rm -f ./$(DEPDIR)/imsg.Po -rm -f ./$(DEPDIR)/listen.Po -rm -f ./$(DEPDIR)/notify.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/privsep_stub.Po -rm -f ./$(DEPDIR)/repo_imsg.Po -rm -f ./$(DEPDIR)/repo_read.Po -rm -f ./$(DEPDIR)/repo_write.Po -rm -f ./$(DEPDIR)/secrets.Po -rm -f ./$(DEPDIR)/session_read.Po -rm -f ./$(DEPDIR)/session_write.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--depfiles check check-am clean clean-generic \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man5 \ install-man8 install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man5 uninstall-man8 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/gotd/gotd.80000664000175000017500000000661415066535721011612 .\" .\" Copyright (c) 2022 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTD 8 .Os .Sh NAME .Nm gotd .Nd Game of Trees Daemon .Sh SYNOPSIS .Nm .Op Fl dnv .Op Fl f Ar config-file .Op Fl s Ar secrets .Sh DESCRIPTION .Nm is a Git repository server which listens on a .Xr unix 4 socket and relies on its companion tool .Xr gotsh 1 to handle Git-protocol communication over the network, via .Xr ssh 1 . .Pp The Git repository format is described in .Xr git-repository 5 . .Pp .Nm requires a configuration file in order to run. The configuration file format is described in .Xr gotd.conf 5 . .Pp It is recommended to restrict .Xr ssh 1 features available to users of .Nm . See .Xr gotsh 1 for details. .Pp The options for .Nm are as follows: .Bl -tag -width Ds .It Fl d Do not daemonize. Send log output to stderr. .It Fl f Ar config-file Set the path to the configuration file. If not specified, the file .Pa /etc/gotd.conf will be used. .It Fl n Configtest mode. Only check the configuration file for validity. .It Fl s Ar secrets Set the path to the secrets file. If not specified, the file .Pa /etc/gotd-secrets.conf will be used if it exists. .It Fl v Verbose mode. Verbosity increases if this option is used multiple times. .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotd.conf Default location of the configuration file. .It Pa /var/run/gotd.sock Default location of the unix socket which .Nm is listening on. This path can be configured in .Xr gotd.conf 5 . .El .Sh EXAMPLES Create an empty repository to be served by .Nm , ensuring that it can only be accessed by the _gotd user: .Pp .Dl # mkdir -p /git/myrepo.git .Dl # chmod 700 /git/myrepo.git .Dl # chown _gotd /git/myrepo.git .Dl # su -m _gotd -c 'gotadmin init /git/myrepo.git' .Pp Add the new repository to .Xr gotd.conf 5 granting read-write access to the flan_hacker user account, and restart .Nm : .Pp .Dl # cat >> /etc/gotd.conf < inclusion * portable: portably wrap socket functions between BSDs/Linux * portable: improve homebrew support for MacOS # got-portable 0.74 (2022-07-14) * portable: made the 'date' command more portable in the test suite. * portable: improved error-handling for commands on BSD-systems without coreutils being installed. * portable: reworked how 'sed' is wrapped portably, so that it now doesn't use any bashisms, and will therefore run under strict POSIX-sh (dash on Ubuntu, for instance). # got-portable 0.73 (2022-07-04) * Changes as found in got-0.73. * portable: the libexec helpers now support Capsicum on FreeBSD, which is similar to OpenBSD's pledge() syscall. * Some portable work has taken place, but these have been merged upstream and hence will be in the got-0.73 changes file. # got-portable 0.71 (2022-06-23) * portable: fix cross-compilation, from Leah Neukirchen # got-portable 0.70 (2022-05-13) * Changes from got-0.70; no -portable specific changes worth mentioning. # got-portable 0.69 (2022-04-24) * portable: added Apline Linux to the core set of OSes when checking CI/CD - this therefore implies -portable can build on muscl as well as glibc. * portable: fixed compilation of -portable on Alpine Linux with respect to Landlock by using the correct header file. * portable: added SipHash as a -portable implementation. # got-portable 0.68.1 (2022-03-22) * portable: fix up a bad merge whereby a code block that should have been removed was left in-situ. # got-portable 0.68 (2022-03-22) * Changes from got-0.68 * portable: support for the following operating systems: - FreeBSD - NetBSD - DragonFlyBSD - MacOS # got-portable 0.67; (2022-02-20) * Changes from got-0.66 * Landlock support: portable now has support for the landlock API which is similar to unveil(), allowing restrictions to which part of the filesystem a process can access. # got-portable 0.66; (2022-01-12) * Changes from got-0.65 # got-portable 0.65; (2022-01-06) * Added timespec*() compat-wrappers for BSD-time functions. # got-portable 0.64; (2021-11-24) * regress: make tests POSIX-compliant by making them run under dash (Ubuntu) # got-portable 0.62; (2021-10-17) * Changes from got-0.62 # got-portable 0.61; (2021-10-09) * Port regress tests. * Improve FreeBSD compatibility. # got-portable 0.60; (2021-09-21) * First portable version released for Linux. got-portable-0.119/tog/0000775000175000017500000000000015066537276010500 5got-portable-0.119/tog/tog.c0000664000175000017500000106221615066536114011353 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__APPLE__) #define _XOPEN_SOURCE_EXTENDED /* for ncurses wide-character functions */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_version.h" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_gotconfig.h" #include "got_diff.h" #include "got_opentemp.h" #include "got_utf8.h" #include "got_cancel.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "got_path.h" #include "got_worktree.h" #include "got_keyword.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) #endif #ifndef MAX #define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) #endif #ifndef CTRL #define CTRL(x) ((x) & 0x1f) #endif #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif struct tog_cmd { const char *name; const struct got_error *(*cmd_main)(int, char *[]); void (*cmd_usage)(void); }; __dead static void usage(int, int); __dead static void usage_log(void); __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_ref(void); static const struct got_error* cmd_log(int, char *[]); static const struct got_error* cmd_diff(int, char *[]); static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_ref(int, char *[]); static const struct tog_cmd tog_commands[] = { { "log", cmd_log, usage_log }, { "diff", cmd_diff, usage_diff }, { "blame", cmd_blame, usage_blame }, { "tree", cmd_tree, usage_tree }, { "ref", cmd_ref, usage_ref }, }; enum tog_view_type { TOG_VIEW_DIFF, TOG_VIEW_LOG, TOG_VIEW_BLAME, TOG_VIEW_TREE, TOG_VIEW_REF, TOG_VIEW_HELP }; /* Match _DIFF to _HELP with enum tog_view_type TOG_VIEW_* counterparts. */ enum tog_keymap_type { TOG_KEYMAP_KEYS = -2, TOG_KEYMAP_GLOBAL, TOG_KEYMAP_DIFF, TOG_KEYMAP_LOG, TOG_KEYMAP_BLAME, TOG_KEYMAP_TREE, TOG_KEYMAP_REF, TOG_KEYMAP_HELP }; enum tog_view_mode { TOG_VIEW_SPLIT_NONE, TOG_VIEW_SPLIT_VERT, TOG_VIEW_SPLIT_HRZN }; #define HSPLIT_SCALE 0.3f /* default horizontal split scale */ #define TOG_EOF_STRING "(END)" struct commit_queue_entry { TAILQ_ENTRY(commit_queue_entry) entry; struct got_object_id *id; struct got_commit_object *commit; int worktree_entry; int idx; }; TAILQ_HEAD(commit_queue_head, commit_queue_entry); struct commit_queue { int ncommits; struct commit_queue_head head; }; struct tog_color { STAILQ_ENTRY(tog_color) entry; regex_t regex; short colorpair; }; STAILQ_HEAD(tog_colors, tog_color); static struct got_reflist_head tog_refs = TAILQ_HEAD_INITIALIZER(tog_refs); static struct got_reflist_object_id_map *tog_refs_idmap; static struct { struct got_object_id *id; int idx; char marker; } tog_base_commit; static enum got_diff_algorithm tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; static const struct got_error * tog_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1, struct got_reference* re2) { const char *name1 = got_ref_get_name(re1); const char *name2 = got_ref_get_name(re2); int isbackup1, isbackup2; /* Sort backup refs towards the bottom of the list. */ isbackup1 = strncmp(name1, "refs/got/backup/", 16) == 0; isbackup2 = strncmp(name2, "refs/got/backup/", 16) == 0; if (!isbackup1 && isbackup2) { *cmp = -1; return NULL; } else if (isbackup1 && !isbackup2) { *cmp = 1; return NULL; } *cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2)); return NULL; } static const struct got_error * tog_load_refs(struct got_repository *repo, int sort_by_date) { const struct got_error *err; err = got_ref_list(&tog_refs, repo, NULL, sort_by_date ? got_ref_cmp_by_commit_timestamp_descending : tog_ref_cmp_by_name, repo); if (err) return err; return got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs, repo); } static void tog_free_refs(void) { if (tog_refs_idmap) { got_reflist_object_id_map_free(tog_refs_idmap); tog_refs_idmap = NULL; } got_ref_list_free(&tog_refs); } static const struct got_error * add_color(struct tog_colors *colors, const char *pattern, int idx, short color) { const struct got_error *err = NULL; struct tog_color *tc; int regerr = 0; if (idx < 1 || idx > COLOR_PAIRS - 1) return NULL; init_pair(idx, color, -1); tc = calloc(1, sizeof(*tc)); if (tc == NULL) return got_error_from_errno("calloc"); regerr = regcomp(&tc->regex, pattern, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); if (regerr) { static char regerr_msg[512]; static char err_msg[512]; regerror(regerr, &tc->regex, regerr_msg, sizeof(regerr_msg)); snprintf(err_msg, sizeof(err_msg), "regcomp: %s", regerr_msg); err = got_error_msg(GOT_ERR_REGEX, err_msg); free(tc); return err; } tc->colorpair = idx; STAILQ_INSERT_HEAD(colors, tc, entry); return NULL; } static void free_colors(struct tog_colors *colors) { struct tog_color *tc; while (!STAILQ_EMPTY(colors)) { tc = STAILQ_FIRST(colors); STAILQ_REMOVE_HEAD(colors, entry); regfree(&tc->regex); free(tc); } } static struct tog_color * get_color(struct tog_colors *colors, int colorpair) { struct tog_color *tc = NULL; STAILQ_FOREACH(tc, colors, entry) { if (tc->colorpair == colorpair) return tc; } return NULL; } static int default_color_value(const char *envvar) { if (strcmp(envvar, "TOG_COLOR_DIFF_MINUS") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_DIFF_PLUS") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_DIFF_CHUNK_HEADER") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_DIFF_META") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_TREE_SUBMODULE") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_TREE_SYMLINK") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_TREE_DIRECTORY") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_TREE_EXECUTABLE") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_COMMIT") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_AUTHOR") == 0) return COLOR_CYAN; if (strcmp(envvar, "TOG_COLOR_DATE") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_REFS_HEADS") == 0) return COLOR_GREEN; if (strcmp(envvar, "TOG_COLOR_REFS_TAGS") == 0) return COLOR_MAGENTA; if (strcmp(envvar, "TOG_COLOR_REFS_REMOTES") == 0) return COLOR_YELLOW; if (strcmp(envvar, "TOG_COLOR_REFS_BACKUP") == 0) return COLOR_CYAN; return -1; } static int get_color_value(const char *envvar) { const char *val = getenv(envvar); if (val == NULL) return default_color_value(envvar); if (strcasecmp(val, "black") == 0) return COLOR_BLACK; if (strcasecmp(val, "red") == 0) return COLOR_RED; if (strcasecmp(val, "green") == 0) return COLOR_GREEN; if (strcasecmp(val, "yellow") == 0) return COLOR_YELLOW; if (strcasecmp(val, "blue") == 0) return COLOR_BLUE; if (strcasecmp(val, "magenta") == 0) return COLOR_MAGENTA; if (strcasecmp(val, "cyan") == 0) return COLOR_CYAN; if (strcasecmp(val, "white") == 0) return COLOR_WHITE; if (strcasecmp(val, "default") == 0) return -1; return default_color_value(envvar); } struct diff_worktree_arg { struct got_repository *repo; struct got_worktree *worktree; struct got_diff_line **lines; struct got_diffstat_cb_arg *diffstat; FILE *outfile; FILE *f1; FILE *f2; const char *id_str; size_t *nlines; int diff_context; int header_shown; int diff_staged; int ignore_whitespace; int force_text_diff; enum got_diff_algorithm diff_algo; }; struct tog_diff_view_state { struct got_object_id *id1, *id2; const char *label1, *label2; const char *worktree_root; char *action; FILE *f, *f1, *f2; int fd1, fd2; int lineno; int first_displayed_line; int last_displayed_line; int eof; int diff_context; int ignore_whitespace; int force_text_diff; int diff_worktree; int diff_staged; struct got_repository *repo; struct got_pathlist_head *paths; struct got_diff_line *lines; size_t nlines; int matched_line; int selected_line; /* passed from log or blame view; may be NULL */ struct tog_view *parent_view; }; #define TOG_WORKTREE_CHANGES_LOCAL_MSG "work tree changes" #define TOG_WORKTREE_CHANGES_STAGED_MSG "staged work tree changes" #define TOG_WORKTREE_CHANGES_LOCAL (1 << 0) #define TOG_WORKTREE_CHANGES_STAGED (1 << 1) #define TOG_WORKTREE_CHANGES_ALL \ (TOG_WORKTREE_CHANGES_LOCAL | TOG_WORKTREE_CHANGES_STAGED) struct tog_worktree_ctx { char *wt_ref; char *wt_author; char *wt_root; int wt_state; int active; }; pthread_mutex_t tog_mutex = PTHREAD_MUTEX_INITIALIZER; static volatile sig_atomic_t tog_thread_error; struct tog_log_thread_args { pthread_cond_t need_commits; pthread_cond_t commit_loaded; int commits_needed; int load_all; struct got_commit_graph *graph; struct commit_queue *real_commits; struct tog_worktree_ctx wctx; const char *in_repo_path; struct got_object_id *start_id; struct got_repository *repo; int *pack_fds; int log_complete; pthread_cond_t log_loaded; sig_atomic_t *quit; struct commit_queue_entry **first_displayed_entry; struct commit_queue_entry **last_displayed_entry; struct commit_queue_entry **selected_entry; int *selected; int *searching; int *search_next_done; regex_t *regex; int *limiting; int limit_match; regex_t *limit_regex; struct commit_queue *limit_commits; struct got_worktree *worktree; int need_commit_marker; int need_wt_status; int *view_nlines; }; struct tog_log_view_state { struct commit_queue *commits; struct commit_queue_entry *first_displayed_entry; struct commit_queue_entry *last_displayed_entry; struct commit_queue_entry *selected_entry; struct commit_queue_entry *marked_entry; struct commit_queue real_commits; int selected; char *in_repo_path; char *head_ref_name; int log_branches; struct got_repository *repo; struct got_object_id *start_id; sig_atomic_t quit; pthread_t thread; struct tog_log_thread_args thread_args; struct commit_queue_entry *matched_entry; struct commit_queue_entry *search_entry; struct tog_colors colors; int use_committer; int limit_view; regex_t limit_regex; struct commit_queue limit_commits; }; #define TOG_COLOR_DIFF_MINUS 1 #define TOG_COLOR_DIFF_PLUS 2 #define TOG_COLOR_DIFF_CHUNK_HEADER 3 #define TOG_COLOR_DIFF_META 4 #define TOG_COLOR_TREE_SUBMODULE 5 #define TOG_COLOR_TREE_SYMLINK 6 #define TOG_COLOR_TREE_DIRECTORY 7 #define TOG_COLOR_TREE_EXECUTABLE 8 #define TOG_COLOR_COMMIT 9 #define TOG_COLOR_AUTHOR 10 #define TOG_COLOR_DATE 11 #define TOG_COLOR_REFS_HEADS 12 #define TOG_COLOR_REFS_TAGS 13 #define TOG_COLOR_REFS_REMOTES 14 #define TOG_COLOR_REFS_BACKUP 15 struct tog_blame_cb_args { struct tog_blame_line *lines; /* one per line */ int nlines; struct tog_view *view; struct got_object_id *commit_id; int *quit; }; struct tog_blame_thread_args { const char *path; struct got_repository *repo; struct tog_blame_cb_args *cb_args; int *complete; got_cancel_cb cancel_cb; void *cancel_arg; pthread_cond_t blame_complete; }; struct tog_blame { FILE *f; off_t filesize; struct tog_blame_line *lines; int nlines; off_t *line_offsets; pthread_t thread; struct tog_blame_thread_args thread_args; struct tog_blame_cb_args cb_args; const char *path; int *pack_fds; }; struct tog_blame_view_state { int first_displayed_line; int last_displayed_line; int selected_line; int last_diffed_line; int blame_complete; int eof; int done; struct got_object_id_queue blamed_commits; struct got_object_qid *blamed_commit; char *path; struct got_repository *repo; struct got_object_id *commit_id; struct got_object_id *id_to_log; struct tog_blame blame; int matched_line; struct tog_colors colors; }; struct tog_parent_tree { TAILQ_ENTRY(tog_parent_tree) entry; struct got_tree_object *tree; struct got_tree_entry *first_displayed_entry; struct got_tree_entry *selected_entry; int selected; }; TAILQ_HEAD(tog_parent_trees, tog_parent_tree); struct tog_tree_view_state { char *tree_label; struct got_object_id *commit_id;/* commit which this tree belongs to */ struct got_tree_object *root; /* the commit's root tree entry */ struct got_tree_object *tree; /* currently displayed (sub-)tree */ struct got_tree_entry *first_displayed_entry; struct got_tree_entry *last_displayed_entry; struct got_tree_entry *selected_entry; int ndisplayed, selected, show_ids; struct tog_parent_trees parents; /* parent trees of current sub-tree */ char *head_ref_name; struct got_repository *repo; struct got_tree_entry *matched_entry; struct tog_colors colors; }; struct tog_reflist_entry { TAILQ_ENTRY(tog_reflist_entry) entry; struct got_reference *ref; int idx; }; TAILQ_HEAD(tog_reflist_head, tog_reflist_entry); struct tog_ref_view_state { struct tog_reflist_head refs; struct tog_reflist_entry *first_displayed_entry; struct tog_reflist_entry *last_displayed_entry; struct tog_reflist_entry *selected_entry; int nrefs, ndisplayed, selected, show_date, show_ids, sort_by_date; struct got_repository *repo; struct tog_reflist_entry *matched_entry; struct tog_colors colors; }; struct tog_help_view_state { FILE *f; off_t *line_offsets; size_t nlines; int lineno; int first_displayed_line; int last_displayed_line; int eof; int matched_line; int selected_line; int all; enum tog_keymap_type type; }; #define GENERATE_HELP \ KEYMAP_("Global", TOG_KEYMAP_GLOBAL), \ KEY_("H F1", "Open view-specific help (double tap for all help)"), \ KEY_("k C-p Up", "Move cursor or page up one line"), \ KEY_("j C-n Down", "Move cursor or page down one line"), \ KEY_("C-b b PgUp", "Scroll the view up one page"), \ KEY_("C-f f PgDn Space", "Scroll the view down one page"), \ KEY_("C-u u", "Scroll the view up one half page"), \ KEY_("C-d d", "Scroll the view down one half page"), \ KEY_("g", "Go to line N (default: first line)"), \ KEY_("Home =", "Go to the first line"), \ KEY_("G", "Go to line N (default: last line)"), \ KEY_("End *", "Go to the last line"), \ KEY_("l Right", "Scroll the view right"), \ KEY_("h Left", "Scroll the view left"), \ KEY_("$", "Scroll view to the rightmost position"), \ KEY_("0", "Scroll view to the leftmost position"), \ KEY_("-", "Decrease size of the focussed split"), \ KEY_("+", "Increase size of the focussed split"), \ KEY_("Tab", "Switch focus between views"), \ KEY_("F", "Toggle fullscreen mode"), \ KEY_("S", "Switch split-screen layout"), \ KEY_("/", "Open prompt to enter search term"), \ KEY_("n", "Find next line/token matching the current search term"), \ KEY_("N", "Find previous line/token matching the current search term"),\ KEY_("q", "Quit the focussed view; Quit help screen"), \ KEY_("Q", "Quit tog"), \ \ KEYMAP_("Log view", TOG_KEYMAP_LOG), \ KEY_("< ,", "Move cursor up one commit"), \ KEY_("> .", "Move cursor down one commit"), \ KEY_("Enter", "Open diff view of the selected commit"), \ KEY_("B", "Reload the log view and toggle display of merged commits"), \ KEY_("R", "Open ref view of all repository references"), \ KEY_("T", "Display tree view of the repository from the selected" \ " commit"), \ KEY_("m", "Mark or unmark the selected entry for diffing with the " \ "next selected commit"), \ KEY_("@", "Toggle between displaying author and committer name"), \ KEY_("&", "Open prompt to enter term to limit commits displayed"), \ KEY_("C-g Backspace", "Cancel current search or log operation"), \ KEY_("C-l", "Reload the log view with new repository commits or " \ "work tree changes"), \ \ KEYMAP_("Diff view", TOG_KEYMAP_DIFF), \ KEY_("K < ,", "Display diff of next line in the file/log entry"), \ KEY_("J > .", "Display diff of previous line in the file/log entry"), \ KEY_("A", "Toggle between Myers and Patience diff algorithm"), \ KEY_("a", "Toggle treatment of file as ASCII irrespective of binary" \ " data"), \ KEY_("p", "Write diff to a patch file in /tmp"), \ KEY_("(", "Go to the previous file in the diff"), \ KEY_(")", "Go to the next file in the diff"), \ KEY_("{", "Go to the previous hunk in the diff"), \ KEY_("}", "Go to the next hunk in the diff"), \ KEY_("[", "Decrease the number of context lines"), \ KEY_("]", "Increase the number of context lines"), \ KEY_("w", "Toggle ignore whitespace-only changes in the diff"), \ \ KEYMAP_("Blame view", TOG_KEYMAP_BLAME), \ KEY_("Enter", "Display diff view of the selected line's commit"), \ KEY_("A", "Toggle diff algorithm between Myers and Patience"), \ KEY_("L", "Open log view for the currently selected annotated line"), \ KEY_("C", "Reload view with the previously blamed commit"), \ KEY_("c", "Reload view with the version of the file found in the" \ " selected line's commit"), \ KEY_("p", "Reload view with the version of the file found in the" \ " selected line's parent commit"), \ \ KEYMAP_("Tree view", TOG_KEYMAP_TREE), \ KEY_("Enter", "Enter selected directory or open blame view of the" \ " selected file"), \ KEY_("L", "Open log view for the selected entry"), \ KEY_("R", "Open ref view of all repository references"), \ KEY_("i", "Show object IDs for all tree entries"), \ KEY_("Backspace", "Return to the parent directory"), \ \ KEYMAP_("Ref view", TOG_KEYMAP_REF), \ KEY_("Enter", "Display log view of the selected reference"), \ KEY_("T", "Display tree view of the selected reference"), \ KEY_("i", "Toggle display of IDs for all non-symbolic references"), \ KEY_("m", "Toggle display of last modified date for each reference"), \ KEY_("o", "Toggle reference sort order (name -> timestamp)"), \ KEY_("C-l", "Reload view with all repository references") struct tog_key_map { const char *keys; const char *info; enum tog_keymap_type type; }; /* curses io for tog regress */ struct tog_io { FILE *cin; FILE *cout; FILE *f; FILE *sdump; char *input_str; int wait_for_ui; } tog_io; static int using_mock_io; #define TOG_KEY_SCRDUMP SHRT_MIN /* * We implement two types of views: parent views and child views. * * The 'Tab' key switches focus between a parent view and its child view. * Child views are shown side-by-side to their parent view, provided * there is enough screen estate. * * When a new view is opened from within a parent view, this new view * becomes a child view of the parent view, replacing any existing child. * * When a new view is opened from within a child view, this new view * becomes a parent view which will obscure the views below until the * user quits the new parent view by typing 'q'. * * This list of views contains parent views only. * Child views are only pointed to by their parent view. */ TAILQ_HEAD(tog_view_list_head, tog_view); struct tog_view { TAILQ_ENTRY(tog_view) entry; WINDOW *window; PANEL *panel; int nlines, ncols, begin_y, begin_x; /* based on split height/width */ int resized_y, resized_x; /* begin_y/x based on user resizing */ int maxx, x; /* max column and current start column */ int lines, cols; /* copies of LINES and COLS */ int nscrolled, offset; /* lines scrolled and hsplit line offset */ int gline, hiline; /* navigate to and highlight this nG line */ int ch, count; /* current keymap and count prefix */ int resized; /* set when in a resize event */ int focussed; /* Only set on one parent or child view at a time. */ int dying; struct tog_view *parent; struct tog_view *child; /* * This flag is initially set on parent views when a new child view * is created. It gets toggled when the 'Tab' key switches focus * between parent and child. * The flag indicates whether focus should be passed on to our child * view if this parent view gets picked for focus after another parent * view was closed. This prevents child views from losing focus in such * situations. */ int focus_child; enum tog_view_mode mode; /* type-specific state */ enum tog_view_type type; union { struct tog_diff_view_state diff; struct tog_log_view_state log; struct tog_blame_view_state blame; struct tog_tree_view_state tree; struct tog_ref_view_state ref; struct tog_help_view_state help; } state; const struct got_error *(*show)(struct tog_view *); const struct got_error *(*input)(struct tog_view **, struct tog_view *, int); const struct got_error *(*reset)(struct tog_view *); const struct got_error *(*resize)(struct tog_view *, int); const struct got_error *(*close)(struct tog_view *); const struct got_error *(*search_start)(struct tog_view *); const struct got_error *(*search_next)(struct tog_view *); void (*search_setup)(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); int search_started; int searching; #define TOG_SEARCH_FORWARD 1 #define TOG_SEARCH_BACKWARD 2 int search_next_done; #define TOG_SEARCH_HAVE_MORE 1 #define TOG_SEARCH_NO_MORE 2 #define TOG_SEARCH_HAVE_NONE 3 regex_t regex; regmatch_t regmatch; const char *action; }; static const struct got_error *open_diff_view(struct tog_view *, struct got_object_id *, struct got_object_id *, const char *, const char *, int, int, int, int, int, const char *, struct tog_view *, struct got_repository *, struct got_pathlist_head *); static const struct got_error *show_diff_view(struct tog_view *); static const struct got_error *input_diff_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_diff_view(struct tog_view *); static const struct got_error* close_diff_view(struct tog_view *); static const struct got_error *search_start_diff_view(struct tog_view *); static void search_setup_diff_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static const struct got_error *search_next_view_match(struct tog_view *); static const struct got_error *open_log_view(struct tog_view *, struct got_object_id *, struct got_repository *, const char *, const char *, int, struct got_worktree *); static const struct got_error * show_log_view(struct tog_view *); static const struct got_error *input_log_view(struct tog_view **, struct tog_view *, int); static const struct got_error *resize_log_view(struct tog_view *, int); static const struct got_error *close_log_view(struct tog_view *); static const struct got_error *search_start_log_view(struct tog_view *); static const struct got_error *search_next_log_view(struct tog_view *); static const struct got_error *open_blame_view(struct tog_view *, char *, struct got_object_id *, struct got_repository *); static const struct got_error *show_blame_view(struct tog_view *); static const struct got_error *input_blame_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_blame_view(struct tog_view *); static const struct got_error *close_blame_view(struct tog_view *); static const struct got_error *search_start_blame_view(struct tog_view *); static void search_setup_blame_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static const struct got_error *open_tree_view(struct tog_view *, struct got_object_id *, const char *, struct got_repository *); static const struct got_error *show_tree_view(struct tog_view *); static const struct got_error *input_tree_view(struct tog_view **, struct tog_view *, int); static const struct got_error *close_tree_view(struct tog_view *); static const struct got_error *search_start_tree_view(struct tog_view *); static const struct got_error *search_next_tree_view(struct tog_view *); static const struct got_error *open_ref_view(struct tog_view *, struct got_repository *); static const struct got_error *show_ref_view(struct tog_view *); static const struct got_error *input_ref_view(struct tog_view **, struct tog_view *, int); static const struct got_error *close_ref_view(struct tog_view *); static const struct got_error *search_start_ref_view(struct tog_view *); static const struct got_error *search_next_ref_view(struct tog_view *); static const struct got_error *open_help_view(struct tog_view *, struct tog_view *); static const struct got_error *show_help_view(struct tog_view *); static const struct got_error *input_help_view(struct tog_view **, struct tog_view *, int); static const struct got_error *reset_help_view(struct tog_view *); static const struct got_error* close_help_view(struct tog_view *); static const struct got_error *search_start_help_view(struct tog_view *); static void search_setup_help_view(struct tog_view *, FILE **, off_t **, size_t *, int **, int **, int **, int **); static volatile sig_atomic_t tog_sigwinch_received; static volatile sig_atomic_t tog_sigpipe_received; static volatile sig_atomic_t tog_sigcont_received; static volatile sig_atomic_t tog_sigint_received; static volatile sig_atomic_t tog_sigterm_received; static void tog_sigwinch(int signo) { tog_sigwinch_received = 1; } static void tog_sigpipe(int signo) { tog_sigpipe_received = 1; } static void tog_sigcont(int signo) { tog_sigcont_received = 1; } static void tog_sigint(int signo) { tog_sigint_received = 1; } static void tog_sigterm(int signo) { tog_sigterm_received = 1; } static int tog_fatal_signal_received(void) { return (tog_sigpipe_received || tog_sigint_received || tog_sigterm_received); } static const struct got_error * view_close(struct tog_view *view) { const struct got_error *err = NULL, *child_err = NULL; if (view->child) { child_err = view_close(view->child); view->child = NULL; } if (view->close) err = view->close(view); if (view->panel) { del_panel(view->panel); view->panel = NULL; } if (view->window) { delwin(view->window); view->window = NULL; } free(view); return err ? err : child_err; } static struct tog_view * view_open(int nlines, int ncols, int begin_y, int begin_x, enum tog_view_type type) { struct tog_view *view = calloc(1, sizeof(*view)); if (view == NULL) return NULL; view->type = type; view->lines = LINES; view->cols = COLS; view->nlines = nlines ? nlines : LINES - begin_y; view->ncols = ncols ? ncols : COLS - begin_x; view->begin_y = begin_y; view->begin_x = begin_x; view->window = newwin(nlines, ncols, begin_y, begin_x); if (view->window == NULL) { view_close(view); return NULL; } view->panel = new_panel(view->window); if (view->panel == NULL || set_panel_userptr(view->panel, view) != OK) { view_close(view); return NULL; } keypad(view->window, TRUE); return view; } static int view_split_begin_x(int begin_x) { if (begin_x > 0 || COLS < 120) return 0; return (COLS - MAX(COLS / 2, 80)); } /* XXX Stub till we decide what to do. */ static int view_split_begin_y(int lines) { return lines * HSPLIT_SCALE; } static const struct got_error *view_resize(struct tog_view *); static const struct got_error * view_splitscreen(struct tog_view *view) { const struct got_error *err = NULL; if (!view->resized && view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->resized_y && view->resized_y < view->lines) view->begin_y = view->resized_y; else view->begin_y = view_split_begin_y(view->nlines); view->begin_x = 0; } else if (!view->resized) { if (view->resized_x && view->resized_x < view->cols - 1 && view->cols > 119) view->begin_x = view->resized_x; else view->begin_x = view_split_begin_x(0); view->begin_y = 0; } view->nlines = LINES - view->begin_y; view->ncols = COLS - view->begin_x; view->lines = LINES; view->cols = COLS; err = view_resize(view); if (err) return err; if (view->parent && view->mode == TOG_VIEW_SPLIT_HRZN) view->parent->nlines = view->begin_y; if (mvwin(view->window, view->begin_y, view->begin_x) == ERR) return got_error_from_errno("mvwin"); return NULL; } static const struct got_error * view_fullscreen(struct tog_view *view) { const struct got_error *err = NULL; view->begin_x = 0; view->begin_y = view->resized ? view->begin_y : 0; view->nlines = view->resized ? view->nlines : LINES; view->ncols = COLS; view->lines = LINES; view->cols = COLS; err = view_resize(view); if (err) return err; if (mvwin(view->window, view->begin_y, view->begin_x) == ERR) return got_error_from_errno("mvwin"); return NULL; } static int view_is_parent_view(struct tog_view *view) { return view->parent == NULL; } static int view_is_splitscreen(struct tog_view *view) { return view->begin_x > 0 || view->begin_y > 0; } static int view_is_fullscreen(struct tog_view *view) { return view->nlines == LINES && view->ncols == COLS; } static int view_is_hsplit_top(struct tog_view *view) { return view->mode == TOG_VIEW_SPLIT_HRZN && view->child && view_is_splitscreen(view->child); } static void view_border(struct tog_view *view) { PANEL *panel; const struct tog_view *view_above; if (view->parent) return view_border(view->parent); panel = panel_above(view->panel); if (panel == NULL) return; view_above = panel_userptr(panel); if (view->mode == TOG_VIEW_SPLIT_HRZN) mvwhline(view->window, view_above->begin_y - 1, view->begin_x, ACS_HLINE, view->ncols); else mvwvline(view->window, view->begin_y, view_above->begin_x - 1, ACS_VLINE, view->nlines); } static const struct got_error *view_init_hsplit(struct tog_view *, int); static const struct got_error *request_log_commits(struct tog_view *); static const struct got_error *offset_selection_down(struct tog_view *); static void offset_selection_up(struct tog_view *); static void view_get_split(struct tog_view *, int *, int *); static const struct got_error * view_resize(struct tog_view *view) { const struct got_error *err = NULL; int dif, nlines, ncols; dif = LINES - view->lines; /* line difference */ if (view->lines > LINES) nlines = view->nlines - (view->lines - LINES); else nlines = view->nlines + (LINES - view->lines); if (view->cols > COLS) ncols = view->ncols - (view->cols - COLS); else ncols = view->ncols + (COLS - view->cols); if (view->child) { int hs = view->child->begin_y; if (!view_is_fullscreen(view)) view->child->begin_x = view_split_begin_x(view->begin_x); if (view->mode == TOG_VIEW_SPLIT_HRZN || view->child->begin_x == 0) { ncols = COLS; view_fullscreen(view->child); if (view->child->focussed) show_panel(view->child->panel); else show_panel(view->panel); } else { ncols = view->child->begin_x; view_splitscreen(view->child); show_panel(view->child->panel); } /* * XXX This is ugly and needs to be moved into the above * logic but "works" for now and my attempts at moving it * break either 'tab' or 'F' key maps in horizontal splits. */ if (hs) { err = view_splitscreen(view->child); if (err) return err; if (dif < 0) { /* top split decreased */ err = offset_selection_down(view); if (err) return err; } view_border(view); update_panels(); doupdate(); show_panel(view->child->panel); nlines = view->nlines; } } else if (view->parent == NULL) ncols = COLS; if (view->resize && dif > 0) { err = view->resize(view, dif); if (err) return err; } if (wresize(view->window, nlines, ncols) == ERR) return got_error_from_errno("wresize"); if (replace_panel(view->panel, view->window) == ERR) return got_error_from_errno("replace_panel"); wclear(view->window); view->nlines = nlines; view->ncols = ncols; view->lines = LINES; view->cols = COLS; return NULL; } static const struct got_error * resize_log_view(struct tog_view *view, int increase) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; int n = 0; if (s->selected_entry) n = s->selected_entry->idx + view->lines - s->selected; /* * Request commits to account for the increased * height so we have enough to populate the view. */ if (s->commits->ncommits < n) { view->nscrolled = n - s->commits->ncommits + increase + 1; err = request_log_commits(view); } return err; } static void view_adjust_offset(struct tog_view *view, int n) { if (n == 0) return; if (view->parent && view->parent->offset) { if (view->parent->offset + n >= 0) view->parent->offset += n; else view->parent->offset = 0; } else if (view->offset) { if (view->offset - n >= 0) view->offset -= n; else view->offset = 0; } } static const struct got_error * view_resize_split(struct tog_view *view, int resize) { const struct got_error *err = NULL; struct tog_view *v = NULL; if (view->parent) v = view->parent; else v = view; if (!v->child || !view_is_splitscreen(v->child)) return NULL; v->resized = v->child->resized = resize; /* lock for resize event */ if (view->mode == TOG_VIEW_SPLIT_HRZN) { if (v->child->resized_y) v->child->begin_y = v->child->resized_y; if (view->parent) v->child->begin_y -= resize; else v->child->begin_y += resize; if (v->child->begin_y < 3) { view->count = 0; v->child->begin_y = 3; } else if (v->child->begin_y > LINES - 1) { view->count = 0; v->child->begin_y = LINES - 1; } v->ncols = COLS; v->child->ncols = COLS; view_adjust_offset(view, resize); err = view_init_hsplit(v, v->child->begin_y); if (err) return err; v->child->resized_y = v->child->begin_y; } else { if (v->child->resized_x) v->child->begin_x = v->child->resized_x; if (view->parent) v->child->begin_x -= resize; else v->child->begin_x += resize; if (v->child->begin_x < 11) { view->count = 0; v->child->begin_x = 11; } else if (v->child->begin_x > COLS - 1) { view->count = 0; v->child->begin_x = COLS - 1; } v->child->resized_x = v->child->begin_x; } v->child->mode = v->mode; v->child->nlines = v->lines - v->child->begin_y; v->child->ncols = v->cols - v->child->begin_x; v->focus_child = 1; err = view_fullscreen(v); if (err) return err; err = view_splitscreen(v->child); if (err) return err; if (v->mode == TOG_VIEW_SPLIT_HRZN) { err = offset_selection_down(v->child); if (err) return err; } if (v->resize) err = v->resize(v, 0); else if (v->child->resize) err = v->child->resize(v->child, 0); v->resized = v->child->resized = 0; return err; } static void view_transfer_size(struct tog_view *dst, struct tog_view *src) { struct tog_view *v = src->child ? src->child : src; dst->resized_x = v->resized_x; dst->resized_y = v->resized_y; } static const struct got_error * view_close_child(struct tog_view *view) { const struct got_error *err = NULL; if (view->child == NULL) return NULL; err = view_close(view->child); view->child = NULL; return err; } static const struct got_error * view_set_child(struct tog_view *view, struct tog_view *child) { const struct got_error *err = NULL; view->child = child; child->parent = view; err = view_resize(view); if (err) return err; if (view->child->resized_x || view->child->resized_y) err = view_resize_split(view, 0); return err; } static const struct got_error *view_dispatch_request(struct tog_view **, struct tog_view *, enum tog_view_type, int, int); static const struct got_error * view_request_new(struct tog_view **requested, struct tog_view *view, enum tog_view_type request) { struct tog_view *new_view = NULL; const struct got_error *err; int y = 0, x = 0; *requested = NULL; if (view_is_parent_view(view) && request != TOG_VIEW_HELP) view_get_split(view, &y, &x); err = view_dispatch_request(&new_view, view, request, y, x); if (err) { /* * The ref view expects its selected entry to resolve to * a commit object id to open either a log or tree view. */ if (err->code != GOT_ERR_OBJ_TYPE) return err; view->action = "commit reference required"; return NULL; } if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN && request != TOG_VIEW_HELP) { err = view_init_hsplit(view, y); if (err) return err; } view->focussed = 0; new_view->focussed = 1; new_view->mode = view->mode; new_view->nlines = request == TOG_VIEW_HELP ? view->lines : view->lines - y; if (view_is_parent_view(view) && request != TOG_VIEW_HELP) { view_transfer_size(new_view, view); err = view_close_child(view); if (err) return err; err = view_set_child(view, new_view); if (err) return err; view->focus_child = 1; } else *requested = new_view; return NULL; } static void tog_resizeterm(void) { int cols, lines; struct winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) < 0) { cols = 80; /* Default */ lines = 24; } else { cols = size.ws_col; lines = size.ws_row; } resize_term(lines, cols); } static const struct got_error * view_search_start(struct tog_view *view, int fast_refresh) { const struct got_error *err = NULL; struct tog_view *v = view; char pattern[1024]; int ret; if (view->search_started) { regfree(&view->regex); view->searching = 0; memset(&view->regmatch, 0, sizeof(view->regmatch)); } view->search_started = 0; if (view->nlines < 1) return NULL; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; if (tog_io.input_str != NULL) { if (strlcpy(pattern, tog_io.input_str, sizeof(pattern)) >= sizeof(pattern)) return got_error(GOT_ERR_NO_SPACE); } else { mvwaddstr(v->window, v->nlines - 1, 0, "/"); wclrtoeol(v->window); nodelay(v->window, FALSE); /* block for search term input */ nocbreak(); echo(); ret = wgetnstr(v->window, pattern, sizeof(pattern)); wrefresh(v->window); cbreak(); noecho(); nodelay(v->window, TRUE); if (!fast_refresh && !using_mock_io) halfdelay(10); if (ret == ERR) return NULL; } if (regcomp(&view->regex, pattern, REG_EXTENDED | REG_NEWLINE) == 0) { err = view->search_start(view); if (err) { regfree(&view->regex); return err; } view->search_started = 1; view->searching = TOG_SEARCH_FORWARD; view->search_next_done = 0; view->search_next(view); } return NULL; } /* Switch split mode. If view is a parent or child, draw the new splitscreen. */ static const struct got_error * switch_split(struct tog_view *view) { const struct got_error *err = NULL; struct tog_view *v = NULL; if (view->parent) v = view->parent; else v = view; if (v->mode == TOG_VIEW_SPLIT_HRZN) v->mode = TOG_VIEW_SPLIT_VERT; else v->mode = TOG_VIEW_SPLIT_HRZN; if (!v->child) return NULL; else if (v->mode == TOG_VIEW_SPLIT_VERT && v->cols < 120) v->mode = TOG_VIEW_SPLIT_NONE; view_get_split(v, &v->child->begin_y, &v->child->begin_x); if (v->mode == TOG_VIEW_SPLIT_HRZN && v->child->resized_y) v->child->begin_y = v->child->resized_y; else if (v->mode == TOG_VIEW_SPLIT_VERT && v->child->resized_x) v->child->begin_x = v->child->resized_x; if (v->mode == TOG_VIEW_SPLIT_HRZN) { v->ncols = COLS; v->child->ncols = COLS; v->child->nscrolled = LINES - v->child->nlines; err = view_init_hsplit(v, v->child->begin_y); if (err) return err; } v->child->mode = v->mode; v->child->nlines = v->lines - v->child->begin_y; v->focus_child = 1; err = view_fullscreen(v); if (err) return err; err = view_splitscreen(v->child); if (err) return err; if (v->mode == TOG_VIEW_SPLIT_NONE) v->mode = TOG_VIEW_SPLIT_VERT; if (v->mode == TOG_VIEW_SPLIT_HRZN) { err = offset_selection_down(v); if (err) return err; err = offset_selection_down(v->child); if (err) return err; } else { offset_selection_up(v); offset_selection_up(v->child); } if (v->resize) err = v->resize(v, 0); else if (v->child->resize) err = v->child->resize(v->child, 0); return err; } /* * Strip trailing whitespace from str starting at byte *n; * if *n < 0, use strlen(str). Return new str length in *n. */ static void strip_trailing_ws(char *str, int *n) { size_t x = *n; if (str == NULL || *str == '\0') return; if (x < 0) x = strlen(str); while (x-- > 0 && isspace((unsigned char)str[x])) str[x] = '\0'; *n = x + 1; } /* * Extract visible substring of line y from the curses screen * and strip trailing whitespace. If vline is set, overwrite * line[vline] with '|' because the ACS_VLINE character is * written out as 'x'. Write the line to file f. */ static const struct got_error * view_write_line(FILE *f, int y, int vline) { char line[COLS * MB_LEN_MAX]; /* allow for multibyte chars */ int r, w; r = mvwinnstr(curscr, y, 0, line, sizeof(line)); if (r == ERR) return got_error_fmt(GOT_ERR_RANGE, "failed to extract line %d", y); /* * In some views, lines are padded with blanks to COLS width. * Strip them so we can diff without the -b flag when testing. */ strip_trailing_ws(line, &r); if (vline > 0) line[vline] = '|'; w = fprintf(f, "%s\n", line); if (w != r + 1) /* \n */ return got_ferror(f, GOT_ERR_IO); return NULL; } /* * Capture the visible curses screen by writing each line to the * file at the path set via the TOG_SCR_DUMP environment variable. */ static const struct got_error * screendump(struct tog_view *view) { const struct got_error *err; int i; err = got_opentemp_truncate(tog_io.sdump); if (err) return err; if ((view->child && view->child->begin_x) || (view->parent && view->begin_x)) { int ncols = view->child ? view->ncols : view->parent->ncols; /* vertical splitscreen */ for (i = 0; i < view->nlines; ++i) { err = view_write_line(tog_io.sdump, i, ncols - 1); if (err) goto done; } } else { int hline = 0; /* fullscreen or horizontal splitscreen */ if ((view->child && view->child->begin_y) || (view->parent && view->begin_y)) /* hsplit */ hline = view->child ? view->child->begin_y : view->begin_y; for (i = 0; i < view->lines; i++) { if (hline && i == hline - 1) { int c; /* ACS_HLINE writes out as 'q', overwrite it */ for (c = 0; c < view->cols; ++c) fputc('-', tog_io.sdump); fputc('\n', tog_io.sdump); continue; } err = view_write_line(tog_io.sdump, i, 0); if (err) goto done; } } done: return err; } /* * Compute view->count from numeric input. Assign total to view->count and * return first non-numeric key entered. */ static int get_compound_key(struct tog_view *view, int c) { struct tog_view *v = view; int x, n = 0; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; view->count = 0; cbreak(); /* block for input */ nodelay(view->window, FALSE); wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); waddch(v->window, ':'); do { x = getcurx(v->window); if (x != ERR && x < view->ncols) { waddch(v->window, c); wrefresh(v->window); } /* * Don't overflow. Max valid request should be the greatest * between the longest and total lines; cap at 10 million. */ if (n >= 9999999) n = 9999999; else n = n * 10 + (c - '0'); } while (((c = wgetch(view->window))) >= '0' && c <= '9' && c != ERR); if (c == 'G' || c == 'g') { /* nG key map */ view->gline = view->hiline = n; n = 0; c = 0; } /* Massage excessive or inapplicable values at the input handler. */ view->count = n; return c; } static void action_report(struct tog_view *view) { struct tog_view *v = view; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); wprintw(v->window, ":%s", view->action); wrefresh(v->window); /* * Clear action status report. Only clear in blame view * once annotating is complete, otherwise it's too fast. * In diff view, let its state control view->action lifetime. */ if (view->type == TOG_VIEW_BLAME) { if (view->state.blame.blame_complete) view->action = NULL; } else if (view->type == TOG_VIEW_DIFF) { view->action = view->state.diff.action; } else view->action = NULL; } /* * Read the next line from the test script and assign * key instruction to *ch. If at EOF, set the *done flag. */ static const struct got_error * tog_read_script_key(FILE *script, struct tog_view *view, int *ch, int *done) { const struct got_error *err = NULL; char *line = NULL; size_t linesz = 0; ssize_t n; if (view->count && --view->count) { *ch = view->ch; return NULL; } else *ch = -1; if ((n = getline(&line, &linesz, script)) == -1) { if (feof(script)) { *done = 1; goto done; } else { err = got_ferror(script, GOT_ERR_IO); goto done; } } if (strncasecmp(line, "WAIT_FOR_UI", 11) == 0) tog_io.wait_for_ui = 1; else if (strncasecmp(line, "KEY_ENTER", 9) == 0) *ch = KEY_ENTER; else if (strncasecmp(line, "KEY_RIGHT", 9) == 0) *ch = KEY_RIGHT; else if (strncasecmp(line, "KEY_LEFT", 8) == 0) *ch = KEY_LEFT; else if (strncasecmp(line, "KEY_DOWN", 8) == 0) *ch = KEY_DOWN; else if (strncasecmp(line, "KEY_UP", 6) == 0) *ch = KEY_UP; else if (strncasecmp(line, "TAB", 3) == 0) *ch = '\t'; else if (strncasecmp(line, "SCREENDUMP", 10) == 0) *ch = TOG_KEY_SCRDUMP; else if (isdigit((unsigned char)*line)) { char *t = line; while (isdigit((unsigned char)*t)) ++t; view->ch = *ch = *t; *t = '\0'; /* ignore error, view->count is 0 if instruction is invalid */ view->count = strtonum(line, 0, INT_MAX, NULL); } else { *ch = *line; if (n > 2 && (*ch == '/' || *ch == '&')) { /* skip leading keymap and trim trailing newline */ tog_io.input_str = strndup(line + 1, n - 2); if (tog_io.input_str == NULL) { err = got_error_from_errno("strndup"); goto done; } } } done: free(line); return err; } static void log_mark_clear(struct tog_log_view_state *s) { s->marked_entry = NULL; } static const struct got_error * view_input(struct tog_view **new, int *done, struct tog_view *view, struct tog_view_list_head *views, int fast_refresh) { const struct got_error *err = NULL; struct tog_view *v; int ch, errcode; *new = NULL; if (view->action) action_report(view); /* Clear "no matches" indicator. */ if (view->search_next_done == TOG_SEARCH_NO_MORE || view->search_next_done == TOG_SEARCH_HAVE_NONE) { view->search_next_done = TOG_SEARCH_HAVE_MORE; view->count = 0; } if (view->searching && !view->search_next_done) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); sched_yield(); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); view->search_next(view); return NULL; } /* Allow threads to make progress while we are waiting for input. */ errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); if (using_mock_io) { err = tog_read_script_key(tog_io.f, view, &ch, done); if (err) { errcode = pthread_mutex_lock(&tog_mutex); return err; } } else if (view->count && --view->count) { cbreak(); nodelay(view->window, TRUE); ch = wgetch(view->window); /* let C-g or backspace abort unfinished count */ if (ch == CTRL('g') || ch == KEY_BACKSPACE) view->count = 0; else ch = view->ch; } else { ch = wgetch(view->window); if (ch >= '1' && ch <= '9') view->ch = ch = get_compound_key(view, ch); } if (view->hiline && ch != ERR && ch != 0) view->hiline = 0; /* key pressed, clear line highlight */ wtimeout(view->window, fast_refresh ? 100 : 1000); /* milliseconds */ errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (tog_sigwinch_received || tog_sigcont_received) { tog_resizeterm(); tog_sigwinch_received = 0; tog_sigcont_received = 0; TAILQ_FOREACH(v, views, entry) { err = view_resize(v); if (err) return err; err = v->input(new, v, KEY_RESIZE); if (err) return err; if (v->child) { err = view_resize(v->child); if (err) return err; err = v->child->input(new, v->child, KEY_RESIZE); if (err) return err; if (v->child->resized_x || v->child->resized_y) { err = view_resize_split(v, 0); if (err) return err; } } } } switch (ch) { case '?': case 'H': case KEY_F(1): view->count = 0; if (view->type == TOG_VIEW_HELP) err = view->reset(view); else err = view_request_new(new, view, TOG_VIEW_HELP); break; case '\t': view->count = 0; if (view->child) { view->focussed = 0; view->child->focussed = 1; view->focus_child = 1; } else if (view->parent) { view->focussed = 0; view->parent->focussed = 1; view->parent->focus_child = 0; if (!view_is_splitscreen(view)) { if (view->parent->resize) { err = view->parent->resize(view->parent, 0); if (err) return err; } offset_selection_up(view->parent); err = view_fullscreen(view->parent); if (err) return err; } } break; case 'q': if (view->parent != NULL) { if (view->parent->type == TOG_VIEW_LOG) log_mark_clear(&view->parent->state.log); if (view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->parent->resize) { /* * Might need more commits * to fill fullscreen. */ err = view->parent->resize( view->parent, 0); if (err) break; } offset_selection_up(view->parent); } } err = view->input(new, view, ch); view->dying = 1; break; case 'Q': *done = 1; break; case 'F': view->count = 0; if (view_is_parent_view(view)) { if (view->child == NULL) break; if (view_is_splitscreen(view->child)) { view->focussed = 0; view->child->focussed = 1; err = view_fullscreen(view->child); } else { err = view_splitscreen(view->child); if (!err) err = view_resize_split(view, 0); } if (err) break; err = view->child->input(new, view->child, KEY_RESIZE); } else { if (view_is_splitscreen(view)) { view->parent->focussed = 0; view->focussed = 1; err = view_fullscreen(view); } else { err = view_splitscreen(view); if (!err && view->mode != TOG_VIEW_SPLIT_HRZN) err = view_resize(view->parent); if (!err) err = view_resize_split(view, 0); } if (err) break; err = view->input(new, view, KEY_RESIZE); } if (err) break; if (view->resize) { err = view->resize(view, 0); if (err) break; } if (view->parent) { if (view->parent->resize) { err = view->parent->resize(view->parent, 0); if (err != NULL) break; } err = offset_selection_down(view->parent); if (err != NULL) break; } err = offset_selection_down(view); break; case 'S': view->count = 0; err = switch_split(view); break; case '-': err = view_resize_split(view, -1); break; case '+': err = view_resize_split(view, 1); break; case KEY_RESIZE: break; case '/': view->count = 0; if (view->search_start) view_search_start(view, fast_refresh); else err = view->input(new, view, ch); break; case 'N': case 'n': if (view->search_started && view->search_next) { view->searching = (ch == 'n' ? TOG_SEARCH_FORWARD : TOG_SEARCH_BACKWARD); view->search_next_done = 0; view->search_next(view); } else err = view->input(new, view, ch); break; case 'A': if (tog_diff_algo == GOT_DIFF_ALGORITHM_MYERS) { tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; view->action = "Patience diff algorithm"; } else { tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS; view->action = "Myers diff algorithm"; } TAILQ_FOREACH(v, views, entry) { if (v->reset) { err = v->reset(v); if (err) return err; } if (v->child && v->child->reset) { err = v->child->reset(v->child); if (err) return err; } } break; case TOG_KEY_SCRDUMP: err = screendump(view); break; default: err = view->input(new, view, ch); break; } return err; } static int view_needs_focus_indication(struct tog_view *view) { if (view_is_parent_view(view)) { if (view->child == NULL || view->child->focussed) return 0; if (!view_is_splitscreen(view->child)) return 0; } else if (!view_is_splitscreen(view)) return 0; return view->focussed; } static const struct got_error * tog_io_close(void) { const struct got_error *err = NULL; if (tog_io.cin && fclose(tog_io.cin) == EOF) err = got_ferror(tog_io.cin, GOT_ERR_IO); if (tog_io.cout && fclose(tog_io.cout) == EOF && err == NULL) err = got_ferror(tog_io.cout, GOT_ERR_IO); if (tog_io.f && fclose(tog_io.f) == EOF && err == NULL) err = got_ferror(tog_io.f, GOT_ERR_IO); if (tog_io.sdump && fclose(tog_io.sdump) == EOF && err == NULL) err = got_ferror(tog_io.sdump, GOT_ERR_IO); if (tog_io.input_str != NULL) free(tog_io.input_str); return err; } static const struct got_error * view_loop(struct tog_view *view) { const struct got_error *err = NULL; struct tog_view_list_head views; struct tog_view *new_view; char *mode; int fast_refresh = 10; int done = 0, errcode; mode = getenv("TOG_VIEW_SPLIT_MODE"); if (!mode || !(*mode == 'h' || *mode == 'H')) view->mode = TOG_VIEW_SPLIT_VERT; else view->mode = TOG_VIEW_SPLIT_HRZN; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); TAILQ_INIT(&views); TAILQ_INSERT_HEAD(&views, view, entry); view->focussed = 1; err = view->show(view); if (err) return err; update_panels(); doupdate(); while (!TAILQ_EMPTY(&views) && !done && !tog_thread_error && !tog_fatal_signal_received()) { /* Refresh fast during initialization, then become slower. */ if (fast_refresh && --fast_refresh == 0 && !using_mock_io) halfdelay(10); /* switch to once per second */ err = view_input(&new_view, &done, view, &views, fast_refresh); if (err) break; if (view->dying && view == TAILQ_FIRST(&views) && TAILQ_NEXT(view, entry) == NULL) done = 1; if (done) { struct tog_view *v; /* * When we quit, scroll the screen up a single line * so we don't lose any information. */ TAILQ_FOREACH(v, &views, entry) { wmove(v->window, 0, 0); wdeleteln(v->window); wnoutrefresh(v->window); if (v->child && !view_is_fullscreen(v)) { wmove(v->child->window, 0, 0); wdeleteln(v->child->window); wnoutrefresh(v->child->window); } } doupdate(); } if (view->dying) { struct tog_view *v, *prev = NULL; if (view_is_parent_view(view)) prev = TAILQ_PREV(view, tog_view_list_head, entry); else if (view->parent) prev = view->parent; if (view->parent) { view->parent->child = NULL; view->parent->focus_child = 0; /* Restore fullscreen line height. */ view->parent->nlines = view->parent->lines; err = view_resize(view->parent); if (err) break; /* Make resized splits persist. */ view_transfer_size(view->parent, view); } else TAILQ_REMOVE(&views, view, entry); err = view_close(view); if (err) goto done; view = NULL; TAILQ_FOREACH(v, &views, entry) { if (v->focussed) break; } if (view == NULL && new_view == NULL) { /* No view has focus. Try to pick one. */ if (prev) view = prev; else if (!TAILQ_EMPTY(&views)) { view = TAILQ_LAST(&views, tog_view_list_head); } if (view) { if (view->focus_child) { view->child->focussed = 1; view = view->child; } else view->focussed = 1; } } } if (new_view) { struct tog_view *v, *t; /* Only allow one parent view per type. */ TAILQ_FOREACH_SAFE(v, &views, entry, t) { if (v->type != new_view->type) continue; TAILQ_REMOVE(&views, v, entry); err = view_close(v); if (err) goto done; break; } TAILQ_INSERT_TAIL(&views, new_view, entry); view = new_view; } if (view && !done) { if (view_is_parent_view(view)) { if (view->child && view->child->focussed) view = view->child; } else { if (view->parent && view->parent->focussed) view = view->parent; } show_panel(view->panel); if (view->child && view_is_splitscreen(view->child)) show_panel(view->child->panel); if (view->parent && view_is_splitscreen(view)) { err = view->parent->show(view->parent); if (err) goto done; } err = view->show(view); if (err) goto done; if (view->child) { err = view->child->show(view->child); if (err) goto done; } update_panels(); doupdate(); } } done: while (!TAILQ_EMPTY(&views)) { const struct got_error *close_err; view = TAILQ_FIRST(&views); TAILQ_REMOVE(&views, view, entry); close_err = view_close(view); if (close_err && err == NULL) err = close_err; } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); return err; } __dead static void usage_log(void) { endwin(); fprintf(stderr, "usage: %s log [-b] [-c commit] [-r repository-path] [path]\n", getprogname()); exit(1); } /* Create newly allocated wide-character string equivalent to a byte string. */ static const struct got_error * mbs2ws(wchar_t **ws, size_t *wlen, const char *s) { char *vis = NULL; const struct got_error *err = NULL; *ws = NULL; *wlen = mbstowcs(NULL, s, 0); if (*wlen == (size_t)-1) { int vislen; if (errno != EILSEQ) return got_error_from_errno("mbstowcs"); /* byte string invalid in current encoding; try to "fix" it */ err = got_mbsavis(&vis, &vislen, s); if (err) return err; *wlen = mbstowcs(NULL, vis, 0); if (*wlen == (size_t)-1) { err = got_error_from_errno("mbstowcs"); /* give up */ goto done; } } *ws = calloc(*wlen + 1, sizeof(**ws)); if (*ws == NULL) { err = got_error_from_errno("calloc"); goto done; } if (mbstowcs(*ws, vis ? vis : s, *wlen) != *wlen) err = got_error_from_errno("mbstowcs"); done: free(vis); if (err) { free(*ws); *ws = NULL; *wlen = 0; } return err; } static const struct got_error * expand_tab(char **ptr, const char *src) { char *dst; size_t len, n, idx = 0, sz = 0; *ptr = NULL; n = len = strlen(src); dst = malloc(n + 1); if (dst == NULL) return got_error_from_errno("malloc"); while (idx < len && src[idx]) { const char c = src[idx]; if (c == '\t') { size_t nb = TABSIZE - sz % TABSIZE; char *p; p = realloc(dst, n + nb); if (p == NULL) { free(dst); return got_error_from_errno("realloc"); } dst = p; n += nb; memset(dst + sz, ' ', nb); sz += nb; } else dst[sz++] = src[idx]; ++idx; } dst[sz] = '\0'; *ptr = dst; return NULL; } /* * Advance at most n columns from wline starting at offset off. * Return the index to the first character after the span operation. * Return the combined column width of all spanned wide characters in * *rcol. */ static int span_wline(int *rcol, int off, wchar_t *wline, int n, int col_tab_align) { int width, i, cols = 0; if (n == 0) { *rcol = cols; return off; } for (i = off; wline[i] != L'\0'; ++i) { if (wline[i] == L'\t') width = TABSIZE - ((cols + col_tab_align) % TABSIZE); else width = wcwidth(wline[i]); if (width == -1) { width = 1; wline[i] = L'.'; } if (cols + width > n) break; cols += width; } *rcol = cols; return i; } /* * Format a line for display, ensuring that it won't overflow a width limit. * With scrolling, the width returned refers to the scrolled version of the * line, which starts at (*wlinep)[*scrollxp]. The caller must free *wlinep. */ static const struct got_error * format_line(wchar_t **wlinep, int *widthp, int *scrollxp, const char *line, int nscroll, int wlimit, int col_tab_align, int expand) { const struct got_error *err = NULL; int cols; wchar_t *wline = NULL; char *exstr = NULL; size_t wlen; int i, scrollx; *wlinep = NULL; *widthp = 0; if (expand) { err = expand_tab(&exstr, line); if (err) return err; } err = mbs2ws(&wline, &wlen, expand ? exstr : line); free(exstr); if (err) return err; if (wlen > 0 && wline[wlen - 1] == L'\n') { wline[wlen - 1] = L'\0'; wlen--; } if (wlen > 0 && wline[wlen - 1] == L'\r') { wline[wlen - 1] = L'\0'; wlen--; } scrollx = span_wline(&cols, 0, wline, nscroll, col_tab_align); i = span_wline(&cols, scrollx, wline, wlimit, col_tab_align); wline[i] = L'\0'; if (widthp) *widthp = cols; if (scrollxp) *scrollxp = scrollx; if (err) free(wline); else *wlinep = wline; return err; } static const struct got_error* build_refs_str(char **refs_str, struct got_reflist_head *refs, struct got_object_id *id, struct got_repository *repo) { static const struct got_error *err = NULL; struct got_reflist_entry *re; char *s; const char *name; *refs_str = NULL; if (refs == NULL) return NULL; TAILQ_FOREACH(re, refs, entry) { struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; name = got_ref_get_name(re->ref); if (strcmp(name, GOT_REF_HEAD) == 0) continue; if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { name += 8; s = strstr(name, "/" GOT_REF_HEAD); if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0) continue; } err = got_ref_resolve(&ref_id, repo, re->ref); if (err) break; if (strncmp(name, "tags/", 5) == 0) { err = got_object_open_as_tag(&tag, repo, ref_id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(ref_id); break; } /* Ref points at something other than a tag. */ err = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = *refs_str; if (asprintf(refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { err = got_error_from_errno("asprintf"); free(s); *refs_str = NULL; break; } free(s); } return err; } static const struct got_error * format_author(wchar_t **wauthor, int *author_width, char *author, int limit, int col_tab_align) { char *smallerthan; smallerthan = strchr(author, '<'); if (smallerthan && smallerthan[1] != '\0') author = smallerthan + 1; author[strcspn(author, "@>")] = '\0'; return format_line(wauthor, author_width, NULL, author, 0, limit, col_tab_align, 0); } static const struct got_error * draw_commit_marker(struct tog_view *view, char c) { struct tog_color *tc; if (view->type != TOG_VIEW_LOG) return got_error_msg(GOT_ERR_NOT_IMPL, "view not supported"); tc = get_color(&view->state.log.colors, TOG_COLOR_COMMIT); if (tc != NULL) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); if (waddch(view->window, c) == ERR) return got_error_msg(GOT_ERR_IO, "waddch"); if (tc != NULL) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); return NULL; } static void tog_waddwstr(struct tog_view *view, wchar_t *wstr, int width, int *col, int color, int toeol) { struct tog_color *tc; int x; x = col != NULL ? *col : getcurx(view->window); tc = color > 0 ? get_color(&view->state.log.colors, color) : NULL; if (tc != NULL) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wstr); x += MAX(width, 0); if (toeol) { while (x < view->ncols) { waddch(view->window, ' '); ++x; } } if (tc != NULL) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (col != NULL) *col = x; } static void tog_waddnstr(struct tog_view *view, const char *str, int limit, int color) { struct tog_color *tc; if (limit == 0) limit = view->ncols - getcurx(view->window); tc = get_color(&view->state.log.colors, color); if (tc != NULL) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddnstr(view->window, str, limit); if (tc != NULL) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); } static const struct got_error * draw_author(struct tog_view *view, char *author, int author_display_cols, int limit, int *col, int color, int marker_column, struct commit_queue_entry *entry) { const struct got_error *err; struct tog_log_view_state *s = &view->state.log; struct tog_color *tc; wchar_t *wauthor; int author_width; err = format_author(&wauthor, &author_width, author, limit, *col); if (err != NULL) return err; if ((tc = get_color(&s->colors, color)) != NULL) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wauthor); free(wauthor); *col += author_width; while (*col < limit && author_width < author_display_cols + 2) { if (entry != NULL && s->marked_entry == entry && author_width == marker_column) { err = draw_commit_marker(view, '>'); if (err != NULL) return err; } else if (entry != NULL && tog_base_commit.marker != GOT_WORKTREE_STATE_UNKNOWN && author_width == marker_column && entry->idx == tog_base_commit.idx && !s->limit_view) { err = draw_commit_marker(view, tog_base_commit.marker); if (err != NULL) return err; } else waddch(view->window, ' '); ++(*col); ++(author_width); } if (tc != NULL) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); return NULL; } static const struct got_error * draw_idstr(struct tog_view *view, const char *id_str, int color) { char *str = NULL; if (strlen(id_str) > 9 && asprintf(&str, "%.8s ", id_str) == -1) return got_error_from_errno("asprintf"); tog_waddnstr(view, str != NULL ? str : id_str, 0, color); free(str); return NULL; } static const struct got_error * draw_ymd(struct tog_view *view, time_t t, int *limit, int avail, int date_display_cols) { struct tm tm; char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */ if (gmtime_r(&t, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(datebuf, sizeof(datebuf), "%F ", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); if (avail <= date_display_cols) *limit = MIN(sizeof(datebuf) - 1, avail); else *limit = MIN(date_display_cols, sizeof(datebuf) - 1); tog_waddnstr(view, datebuf, *limit, TOG_COLOR_DATE); return NULL; } static const struct got_error * draw_worktree_entry(struct tog_view *view, int wt_entry, const size_t date_display_cols, int author_display_cols) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; wchar_t *wmsg = NULL; char *author, *msg = NULL; char *base_commit_id = NULL; const char *p = TOG_WORKTREE_CHANGES_LOCAL_MSG; int col, limit, scrollx, width; const int avail = view->ncols; err = draw_ymd(view, time(NULL), &col, avail, date_display_cols); if (err != NULL) return err; if (col > avail) return NULL; if (avail >= 120) { err = draw_idstr(view, "........ ", TOG_COLOR_COMMIT); if (err != NULL) return err; col += 9; if (col > avail) return NULL; } author = strdup(s->thread_args.wctx.wt_author); if (author == NULL) return got_error_from_errno("strdup"); err = draw_author(view, author, author_display_cols, avail - col, &col, TOG_COLOR_AUTHOR, 0, NULL); if (err != NULL) goto done; if (col > avail) goto done; err = got_object_id_str(&base_commit_id, tog_base_commit.id); if (err != NULL) goto done; if (wt_entry & TOG_WORKTREE_CHANGES_STAGED) p = TOG_WORKTREE_CHANGES_STAGED_MSG; if (asprintf(&msg, "%s based on [%.10s]", p, base_commit_id) == -1) { err = got_error_from_errno("asprintf"); goto done; } limit = avail - col; if (view->child != NULL && !view_is_hsplit_top(view) && limit > 0) limit--; /* for the border */ err = format_line(&wmsg, &width, &scrollx, msg, view->x, limit, col, 1); if (err != NULL) goto done; tog_waddwstr(view, &wmsg[scrollx], width, &col, 0, 1); done: free(msg); free(wmsg); free(author); free(base_commit_id); return err; } static const struct got_error * draw_commit(struct tog_view *view, struct commit_queue_entry *entry, const size_t date_display_cols, int author_display_cols) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; struct got_commit_object *commit = entry->commit; struct got_object_id *id = entry->id; char *author, *newline, *logmsg, *logmsg0 = NULL, *refs_str = NULL; wchar_t *wrefstr = NULL, *wlogmsg = NULL; int refstr_width, logmsg_width, col, limit, scrollx, logmsg_x; const int avail = view->ncols, marker_column = author_display_cols + 1; time_t committer_time; struct got_reflist_head *refs; if (tog_base_commit.id != NULL && tog_base_commit.idx == -1 && got_object_id_cmp(id, tog_base_commit.id) == 0) tog_base_commit.idx = entry->idx; if (tog_io.wait_for_ui && s->thread_args.need_commit_marker) { int rc; rc = pthread_cond_wait(&s->thread_args.log_loaded, &tog_mutex); if (rc) return got_error_set_errno(rc, "pthread_cond_wait"); } committer_time = got_object_commit_get_committer_time(commit); err = draw_ymd(view, committer_time, &col, avail, date_display_cols); if (err != NULL) return err; if (col > avail) return NULL; if (avail >= 120) { char *id_str; err = got_object_id_str(&id_str, id); if (err) return err; err = draw_idstr(view, id_str, TOG_COLOR_COMMIT); free(id_str); if (err != NULL) return err; col += 9; if (col > avail) return NULL; } if (s->use_committer) author = strdup(got_object_commit_get_committer(commit)); else author = strdup(got_object_commit_get_author(commit)); if (author == NULL) return got_error_from_errno("strdup"); err = draw_author(view, author, author_display_cols, avail - col, &col, TOG_COLOR_AUTHOR, marker_column, entry); if (err != NULL) goto done; if (col > avail) goto done; err = got_object_commit_get_logmsg(&logmsg0, commit); if (err) goto done; logmsg = logmsg0; while (*logmsg == '\n') logmsg++; newline = strchr(logmsg, '\n'); if (newline) *newline = '\0'; limit = avail - col; if (view->child && !view_is_hsplit_top(view) && limit > 0) limit--; /* for the border */ /* Prepend reference labels to log message if possible .*/ refs = got_reflist_object_id_map_lookup(tog_refs_idmap, id); err = build_refs_str(&refs_str, refs, id, s->repo); if (err) goto done; if (refs_str) { char *rs; if (asprintf(&rs, "[%s]", refs_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } err = format_line(&wrefstr, &refstr_width, &scrollx, rs, view->x, limit, col, 1); free(rs); if (err) goto done; tog_waddwstr(view, &wrefstr[scrollx], refstr_width, &col, TOG_COLOR_COMMIT, 0); if (col > avail) goto done; if (col < avail) { waddch(view->window, ' '); col++; } if (refstr_width > 0) logmsg_x = 0; else { int unscrolled_refstr_width; size_t len = wcslen(wrefstr); /* * No need to check for -1 return value here since * unprintables have been replaced by span_wline(). */ unscrolled_refstr_width = wcswidth(wrefstr, len); unscrolled_refstr_width += 1; /* trailing space */ logmsg_x = view->x - unscrolled_refstr_width; } limit = avail - col; if (view->child && !view_is_hsplit_top(view) && limit > 0) limit--; /* for the border */ } else logmsg_x = view->x; err = format_line(&wlogmsg, &logmsg_width, &scrollx, logmsg, logmsg_x, limit, col, 1); if (err) goto done; tog_waddwstr(view, &wlogmsg[scrollx], logmsg_width, &col, 0, 1); done: free(logmsg0); free(wlogmsg); free(wrefstr); free(refs_str); free(author); return err; } static struct commit_queue_entry * alloc_commit_queue_entry(struct got_commit_object *commit, struct got_object_id *id) { struct commit_queue_entry *entry; struct got_object_id *dup; entry = calloc(1, sizeof(*entry)); if (entry == NULL) return NULL; dup = got_object_id_dup(id); if (dup == NULL) { free(entry); return NULL; } entry->id = dup; entry->commit = commit; return entry; } static void pop_commit(struct commit_queue *commits) { struct commit_queue_entry *entry; entry = TAILQ_FIRST(&commits->head); TAILQ_REMOVE(&commits->head, entry, entry); if (entry->worktree_entry == 0) got_object_commit_close(entry->commit); commits->ncommits--; free(entry->id); free(entry); } static void free_commits(struct commit_queue *commits) { while (!TAILQ_EMPTY(&commits->head)) pop_commit(commits); } static const struct got_error * match_commit(int *have_match, struct got_object_id *id, struct got_commit_object *commit, regex_t *regex) { const struct got_error *err = NULL; regmatch_t regmatch; char *id_str = NULL, *logmsg = NULL; *have_match = 0; err = got_object_id_str(&id_str, id); if (err) return err; err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; if (regexec(regex, got_object_commit_get_author(commit), 1, ®match, 0) == 0 || regexec(regex, got_object_commit_get_committer(commit), 1, ®match, 0) == 0 || regexec(regex, id_str, 1, ®match, 0) == 0 || regexec(regex, logmsg, 1, ®match, 0) == 0) *have_match = 1; done: free(id_str); free(logmsg); return err; } static const struct got_error * queue_commits(struct tog_log_thread_args *a) { const struct got_error *err = NULL; /* * We keep all commits open throughout the lifetime of the log * view in order to avoid having to re-fetch commits from disk * while updating the display. */ do { struct got_object_id id; struct got_commit_object *commit; struct commit_queue_entry *entry; int limit_match = 0; int errcode; err = got_commit_graph_iter_next(&id, a->graph, a->repo, NULL, NULL); if (err) break; err = got_object_open_as_commit(&commit, a->repo, &id); if (err) break; entry = alloc_commit_queue_entry(commit, &id); if (entry == NULL) { err = got_error_from_errno("alloc_commit_queue_entry"); break; } errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); break; } entry->idx = a->real_commits->ncommits; TAILQ_INSERT_TAIL(&a->real_commits->head, entry, entry); a->real_commits->ncommits++; if (*a->limiting) { err = match_commit(&limit_match, &id, commit, a->limit_regex); if (err) break; if (limit_match) { struct commit_queue_entry *matched; matched = alloc_commit_queue_entry( entry->commit, entry->id); if (matched == NULL) { err = got_error_from_errno( "alloc_commit_queue_entry"); break; } matched->commit = entry->commit; got_object_commit_retain(entry->commit); matched->idx = a->limit_commits->ncommits; TAILQ_INSERT_TAIL(&a->limit_commits->head, matched, entry); a->limit_commits->ncommits++; } /* * This is how we signal log_thread() that we * have found a match, and that it should be * counted as a new entry for the view. */ a->limit_match = limit_match; } if (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done) { int have_match; err = match_commit(&have_match, &id, commit, a->regex); if (err) break; if (*a->limiting) { if (limit_match && have_match) *a->search_next_done = TOG_SEARCH_HAVE_MORE; } else if (have_match) *a->search_next_done = TOG_SEARCH_HAVE_MORE; } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); if (err) break; } while (*a->searching == TOG_SEARCH_FORWARD && !*a->search_next_done); return err; } static void select_commit(struct tog_log_view_state *s) { struct commit_queue_entry *entry; int ncommits = 0; entry = s->first_displayed_entry; while (entry) { if (ncommits == s->selected) { s->selected_entry = entry; break; } entry = TAILQ_NEXT(entry, entry); ncommits++; } } /* lifted from got.c:652 (TODO make lib routine) */ static const struct got_error * get_author(char **author, struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; const char *got_author = NULL, *name, *email; const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *author = NULL; if (worktree) worktree_conf = got_worktree_get_gotconfig(worktree); repo_conf = got_repo_get_gotconfig(repo); /* * Priority of potential author information sources, from most * significant to least significant: * 1) work tree's .got/got.conf file * 2) repository's got.conf file * 3) repository's git config file * 4) environment variables * 5) global git config files (in user's home directory or /etc) */ if (worktree_conf) got_author = got_gotconfig_get_author(worktree_conf); if (got_author == NULL) got_author = got_gotconfig_get_author(repo_conf); if (got_author == NULL) { name = got_repo_get_gitconfig_author_name(repo); email = got_repo_get_gitconfig_author_email(repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } got_author = getenv("GOT_AUTHOR"); if (got_author == NULL) { name = got_repo_get_global_gitconfig_author_name(repo); email = got_repo_get_global_gitconfig_author_email( repo); if (name && email) { if (asprintf(author, "%s <%s>", name, email) == -1) return got_error_from_errno("asprintf"); return NULL; } /* TODO: Look up user in password database? */ return got_error(GOT_ERR_COMMIT_NO_AUTHOR); } } *author = strdup(got_author); if (*author == NULL) err = got_error_from_errno("strdup"); return err; } static const struct got_error * push_worktree_entry(struct tog_log_thread_args *ta, int wt_entry, struct got_worktree *worktree) { struct commit_queue_entry *e, *entry; int rc; entry = calloc(1, sizeof(*entry)); if (entry == NULL) return got_error_from_errno("calloc"); entry->idx = 0; entry->worktree_entry = wt_entry; rc = pthread_mutex_lock(&tog_mutex); if (rc != 0) { free(entry); return got_error_set_errno(rc, "pthread_mutex_lock"); } TAILQ_FOREACH(e, &ta->real_commits->head, entry) ++e->idx; TAILQ_INSERT_HEAD(&ta->real_commits->head, entry, entry); ta->wctx.wt_state |= wt_entry; ++ta->real_commits->ncommits; ++tog_base_commit.idx; rc = pthread_mutex_unlock(&tog_mutex); if (rc != 0) return got_error_set_errno(rc, "pthread_mutex_unlock"); return NULL; } static const struct got_error * check_cancelled(void *arg) { int rc, quit = 0; if ((rc = pthread_mutex_lock(&tog_mutex)) != 0) return got_error_set_errno(rc, "pthread_mutex_lock"); if (tog_sigint_received || tog_sigpipe_received || *((int *)arg)) quit = 1; if ((rc = pthread_mutex_unlock(&tog_mutex)) != 0) return got_error_set_errno(rc, "pthread_mutex_unlock"); if (quit) return got_error(GOT_ERR_CANCELLED); return NULL; } static const struct got_error * check_local_changes(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { int *have_local_changes = arg; switch (status) { case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_MODIFY: case GOT_STATUS_CONFLICT: *have_local_changes |= TOG_WORKTREE_CHANGES_LOCAL; default: break; } switch (staged_status) { case GOT_STATUS_ADD: case GOT_STATUS_DELETE: case GOT_STATUS_MODIFY: *have_local_changes |= TOG_WORKTREE_CHANGES_STAGED; default: break; } return NULL; } static const struct got_error * tog_worktree_status(struct tog_log_thread_args *ta) { const struct got_error *err, *close_err; struct tog_worktree_ctx *wctx = &ta->wctx; struct got_worktree *wt = ta->worktree; struct got_pathlist_head paths; char *cwd = NULL; int wt_state = 0; RB_INIT(&paths); if (wt == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); err = got_worktree_open(&wt, cwd, NULL); if (err != NULL) { if (err->code == GOT_ERR_NOT_WORKTREE) { /* * Shouldn't happen; this routine should only * be called if tog is invoked in a worktree. */ wctx->active = 0; err = NULL; } else if (err->code == GOT_ERR_WORKTREE_BUSY) err = NULL; /* retry next redraw */ goto done; } } err = got_pathlist_insert(NULL, &paths, "", NULL); if (err != NULL) goto done; err = got_worktree_status(wt, &paths, ta->repo, 0, check_local_changes, &wt_state, check_cancelled, ta->quit); if (err != NULL) goto done; if (wt_state != 0) { err = get_author(&wctx->wt_author, ta->repo, wt); if (err != NULL) { if (err->code != GOT_ERR_COMMIT_NO_AUTHOR) goto done; if ((wctx->wt_author = strdup("")) == NULL) { err = got_error_from_errno("strdup"); goto done; } } wctx->wt_root = strdup(got_worktree_get_root_path(wt)); if (wctx->wt_root == NULL) { err = got_error_from_errno("strdup"); goto done; } wctx->wt_ref = strdup(got_worktree_get_head_ref_name(wt)); if (wctx->wt_ref == NULL) { err = got_error_from_errno("strdup"); goto done; } } /* * Push staged entry first so it's the second log entry * if there are both staged and unstaged work tree changes. */ if (wt_state & TOG_WORKTREE_CHANGES_STAGED && (wctx->wt_state & TOG_WORKTREE_CHANGES_STAGED) == 0) { err = push_worktree_entry(ta, TOG_WORKTREE_CHANGES_STAGED, wt); if (err != NULL) goto done; } if (wt_state & TOG_WORKTREE_CHANGES_LOCAL && (wctx->wt_state & TOG_WORKTREE_CHANGES_LOCAL) == 0) { err = push_worktree_entry(ta, TOG_WORKTREE_CHANGES_LOCAL, wt); if (err != NULL) goto done; } done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE); if (ta->worktree == NULL && wt != NULL) { close_err = got_worktree_close(wt); if (close_err != NULL && err == NULL) err = close_err; } free(cwd); return err; } static const struct got_error * worktree_headref_str(char **ret, const char *ref) { if (strncmp(ref, "refs/heads/", 11) == 0) *ret = strdup(ref + 11); else *ret = strdup(ref); if (*ret == NULL) return got_error_from_errno("strdup"); return NULL; } static const struct got_error * fmtindex(char **index, int *ncommits, int wt_state, struct commit_queue_entry *entry, int limit_view) { int idx = 0; if (!limit_view) { if (*ncommits > 0 && wt_state & TOG_WORKTREE_CHANGES_LOCAL) --(*ncommits); if (*ncommits > 0 && wt_state & TOG_WORKTREE_CHANGES_STAGED) --(*ncommits); } if (entry != NULL && entry->worktree_entry == 0) { /* * Display 1-based index of selected commit entries only. * If a work tree entry is selected, show an index of 0. */ idx = entry->idx; if (wt_state == 0 || limit_view) ++idx; else if (wt_state > TOG_WORKTREE_CHANGES_STAGED) --idx; } if (asprintf(index, " [%d/%d] ", idx, *ncommits) == -1) { *index = NULL; return got_error_from_errno("asprintf"); } return NULL; } static const struct got_error * fmtheader(char **header, int *ncommits, struct commit_queue_entry *entry, struct tog_view *view) { const struct got_error *err; struct tog_log_view_state *s = &view->state.log; struct tog_worktree_ctx *wctx = &s->thread_args.wctx; struct got_reflist_head *refs; char *id_str = NULL, *index = NULL; char *wthdr = NULL, *ncommits_str = NULL; char *refs_str = NULL; int wt_entry; *header = NULL; wt_entry = entry != NULL ? entry->worktree_entry : 0; if (entry && !(view->searching && view->search_next_done == 0)) { if (entry->worktree_entry == 0) { err = got_object_id_str(&id_str, entry->id); if (err != NULL) return err; refs = got_reflist_object_id_map_lookup(tog_refs_idmap, entry->id); err = build_refs_str(&refs_str, refs, entry->id, s->repo); if (err != NULL) goto done; } else { err = worktree_headref_str(&refs_str, wctx->wt_ref); if (err != NULL) return err; } } err = fmtindex(&index, ncommits, wctx->wt_state, entry, s->limit_view); if (err != NULL) goto done; if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) { if (asprintf(&ncommits_str, "%s%s", index, (view->searching && !view->search_next_done) ? "searching..." : "loading...") == -1) { err = got_error_from_errno("asprintf"); goto done; } } else { const char *search_str = NULL; const char *limit_str = NULL; if (view->searching) { if (view->search_next_done == TOG_SEARCH_NO_MORE) search_str = "no more matches"; else if (view->search_next_done == TOG_SEARCH_HAVE_NONE) search_str = "no matches found"; else if (!view->search_next_done) search_str = "searching..."; } if (s->limit_view && ncommits == 0) limit_str = "no matches found"; if (asprintf(&ncommits_str, "%s%s %s", index, search_str ? search_str : (refs_str ? refs_str : ""), limit_str ? limit_str : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (wt_entry != 0) { const char *t = "", *p = TOG_WORKTREE_CHANGES_LOCAL_MSG; if (wt_entry == TOG_WORKTREE_CHANGES_STAGED) { p = TOG_WORKTREE_CHANGES_STAGED_MSG; t = "-s "; } if (asprintf(&wthdr, "%s%s (%s)", t, wctx->wt_root, p) == -1) { err = got_error_from_errno("asprintf"); goto done; } } if (s->in_repo_path != NULL && strcmp(s->in_repo_path, "/") != 0) { if (asprintf(header, "%s%s %s%s", wt_entry == 0 ? "commit " : "diff ", wt_entry == 0 ? id_str ? id_str : "........................................" : wthdr != NULL ? wthdr : "", s->in_repo_path, ncommits_str) == -1) err = got_error_from_errno("asprintf"); } else if (asprintf(header, "%s%s%s", wt_entry == 0 ? "commit " : "diff ", wt_entry == 0 ? id_str ? id_str : "........................................" : wthdr != NULL ? wthdr : "", ncommits_str) == -1) err = got_error_from_errno("asprintf"); if (err != NULL) *header = NULL; done: free(wthdr); free(index); free(id_str); free(refs_str); free(ncommits_str); return err; } static const struct got_error * draw_commits(struct tog_view *view) { const struct got_error *err; struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry = s->selected_entry; int width, limit = view->nlines; int ncommits = s->commits->ncommits, author_cols = 4, refstr_cols; char *header; wchar_t *wline; static const size_t date_display_cols = 12; if (view_is_hsplit_top(view)) --limit; /* account for border */ if (s->thread_args.commits_needed == 0 && s->thread_args.need_wt_status == 0 && s->thread_args.need_commit_marker == 0 && !using_mock_io) halfdelay(10); /* disable fast refresh */ err = fmtheader(&header, &ncommits, entry, view); if (err != NULL) return err; err = format_line(&wline, &width, NULL, header, 0, view->ncols, 0, 0); free(header); if (err) return err; werase(view->window); if (view_needs_focus_indication(view)) wstandout(view->window); tog_waddwstr(view, wline, width, NULL, TOG_COLOR_COMMIT, 1); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); if (limit <= 1) return NULL; /* Grow author column size if necessary, and set view->maxx. */ entry = s->first_displayed_entry; ncommits = 0; view->maxx = 0; while (entry) { struct got_reflist_head *refs; struct got_commit_object *c = entry->commit; char *author, *eol, *msg, *msg0, *refs_str; wchar_t *wauthor, *wmsg; int width; if (ncommits >= limit - 1) break; if (entry->worktree_entry != 0) author = strdup(s->thread_args.wctx.wt_author); else if (s->use_committer) author = strdup(got_object_commit_get_committer(c)); else author = strdup(got_object_commit_get_author(c)); if (author == NULL) return got_error_from_errno("strdup"); err = format_author(&wauthor, &width, author, COLS, date_display_cols); if (author_cols < width) author_cols = width; free(wauthor); free(author); if (err) return err; if (entry->worktree_entry != 0) { if (entry->worktree_entry == TOG_WORKTREE_CHANGES_LOCAL) width = sizeof(TOG_WORKTREE_CHANGES_LOCAL_MSG); else width = sizeof(TOG_WORKTREE_CHANGES_STAGED_MSG); view->maxx = MAX(view->maxx, width - 1); entry = TAILQ_NEXT(entry, entry); ++ncommits; continue; } refs = got_reflist_object_id_map_lookup(tog_refs_idmap, entry->id); err = build_refs_str(&refs_str, refs, entry->id, s->repo); if (err) return err; if (refs_str) { wchar_t *ws; err = format_line(&ws, &width, NULL, refs_str, 0, INT_MAX, date_display_cols + author_cols, 0); free(ws); free(refs_str); refs_str = NULL; if (err) return err; refstr_cols = width + 3; /* account for [ ] + space */ } else refstr_cols = 0; err = got_object_commit_get_logmsg(&msg0, c); if (err) return err; msg = msg0; while (*msg == '\n') ++msg; if ((eol = strchr(msg, '\n'))) *eol = '\0'; err = format_line(&wmsg, &width, NULL, msg, 0, INT_MAX, date_display_cols + author_cols + refstr_cols, 0); free(msg0); free(wmsg); if (err) return err; view->maxx = MAX(view->maxx, width + refstr_cols); ncommits++; entry = TAILQ_NEXT(entry, entry); } entry = s->first_displayed_entry; s->last_displayed_entry = s->first_displayed_entry; ncommits = 0; while (entry) { if (ncommits >= limit - 1) break; if (ncommits == s->selected) wstandout(view->window); if (entry->worktree_entry == 0) err = draw_commit(view, entry, date_display_cols, author_cols); else err = draw_worktree_entry(view, entry->worktree_entry, date_display_cols, author_cols); if (ncommits == s->selected) wstandend(view->window); if (err) return err; ncommits++; s->last_displayed_entry = entry; entry = TAILQ_NEXT(entry, entry); } view_border(view); return NULL; } static void log_scroll_up(struct tog_log_view_state *s, int maxscroll) { struct commit_queue_entry *entry; int nscrolled = 0; entry = TAILQ_FIRST(&s->commits->head); if (s->first_displayed_entry == entry) return; entry = s->first_displayed_entry; while (entry && nscrolled < maxscroll) { entry = TAILQ_PREV(entry, commit_queue_head, entry); if (entry) { s->first_displayed_entry = entry; nscrolled++; } } } static const struct got_error * trigger_log_thread(struct tog_view *view, int wait) { const struct got_error *err; struct tog_log_thread_args *ta = &view->state.log.thread_args; int errcode; if (!using_mock_io) halfdelay(1); /* fast refresh while loading commits */ while (!ta->log_complete && !tog_thread_error && (ta->commits_needed > 0 || ta->load_all)) { /* Wake the log thread. */ errcode = pthread_cond_signal(&ta->need_commits); if (errcode) return got_error_set_errno(errcode, "pthread_cond_signal"); /* * The mutex will be released while the view loop waits * in wgetch(), at which time the log thread will run. */ if (!wait) break; /* Display progress update in log view. */ err = show_log_view(view); if (err != NULL) return err; update_panels(); doupdate(); /* Wait right here while next commit is being loaded. */ errcode = pthread_cond_wait(&ta->commit_loaded, &tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_cond_wait"); /* Display progress update in log view. */ err = show_log_view(view); if (err != NULL) return err; update_panels(); doupdate(); } return NULL; } static const struct got_error * request_log_commits(struct tog_view *view) { struct tog_log_view_state *state = &view->state.log; const struct got_error *err = NULL; if (state->thread_args.log_complete) return NULL; state->thread_args.commits_needed += view->nscrolled; err = trigger_log_thread(view, 1); view->nscrolled = 0; return err; } static const struct got_error * log_scroll_down(struct tog_view *view, int maxscroll) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; struct commit_queue_entry *pentry; int nscrolled = 0, ncommits_needed; if (s->last_displayed_entry == NULL) return NULL; ncommits_needed = s->last_displayed_entry->idx + 2 + maxscroll; if (s->commits->ncommits < ncommits_needed && !s->thread_args.log_complete) { /* * Ask the log thread for required amount of commits. */ s->thread_args.commits_needed += ncommits_needed - s->commits->ncommits; err = trigger_log_thread(view, 1); if (err) return err; } do { pentry = TAILQ_NEXT(s->last_displayed_entry, entry); if (pentry == NULL && view->mode != TOG_VIEW_SPLIT_HRZN) break; s->last_displayed_entry = pentry ? pentry : s->last_displayed_entry; pentry = TAILQ_NEXT(s->first_displayed_entry, entry); if (pentry == NULL) break; s->first_displayed_entry = pentry; } while (++nscrolled < maxscroll); if (view->mode == TOG_VIEW_SPLIT_HRZN && !s->thread_args.log_complete) view->nscrolled += nscrolled; else view->nscrolled = 0; return err; } static const struct got_error * open_diff_view_for_commit(struct tog_view **new_view, int begin_y, int begin_x, struct commit_queue_entry *entry, struct tog_view *log_view, struct got_repository *repo) { const struct got_error *err; struct got_object_qid *p; struct got_object_id *parent_id; struct tog_view *diff_view; struct tog_log_view_state *ls = NULL; const char *worktree_root = NULL; diff_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_DIFF); if (diff_view == NULL) return got_error_from_errno("view_open"); if (log_view != NULL) { ls = &log_view->state.log; worktree_root = ls->thread_args.wctx.wt_root; } if (ls != NULL && ls->marked_entry != NULL && ls->marked_entry != ls->selected_entry) parent_id = ls->marked_entry->id; else if (entry->worktree_entry == 0 && (p = STAILQ_FIRST(got_object_commit_get_parent_ids(entry->commit)))) parent_id = &p->id; else parent_id = NULL; err = open_diff_view(diff_view, parent_id, entry->id, NULL, NULL, 3, 0, 0, 0, entry->worktree_entry, worktree_root, log_view, repo, NULL); if (err == NULL) *new_view = diff_view; return err; } static const struct got_error * tree_view_visit_subtree(struct tog_tree_view_state *s, struct got_tree_object *subtree) { struct tog_parent_tree *parent; parent = calloc(1, sizeof(*parent)); if (parent == NULL) return got_error_from_errno("calloc"); parent->tree = s->tree; parent->first_displayed_entry = s->first_displayed_entry; parent->selected_entry = s->selected_entry; parent->selected = s->selected; TAILQ_INSERT_HEAD(&s->parents, parent, entry); s->tree = subtree; s->selected = 0; s->first_displayed_entry = NULL; return NULL; } static const struct got_error * tree_view_walk_path(struct tog_tree_view_state *s, struct got_commit_object *commit, const char *path) { const struct got_error *err = NULL; struct got_tree_object *tree = NULL; const char *p; char *slash, *subpath = NULL; /* Walk the path and open corresponding tree objects. */ p = path; while (*p) { struct got_tree_entry *te; struct got_object_id *tree_id; char *te_name; while (p[0] == '/') p++; /* Ensure the correct subtree entry is selected. */ slash = strchr(p, '/'); if (slash == NULL) te_name = strdup(p); else te_name = strndup(p, slash - p); if (te_name == NULL) { err = got_error_from_errno("strndup"); break; } te = got_object_tree_find_entry(s->tree, te_name); if (te == NULL) { err = got_error_path(te_name, GOT_ERR_NO_TREE_ENTRY); free(te_name); break; } free(te_name); s->first_displayed_entry = s->selected_entry = te; if (!S_ISDIR(got_tree_entry_get_mode(s->selected_entry))) break; /* jump to this file's entry */ slash = strchr(p, '/'); if (slash) subpath = strndup(path, slash - path); else subpath = strdup(path); if (subpath == NULL) { err = got_error_from_errno("strdup"); break; } err = got_object_id_by_path(&tree_id, s->repo, commit, subpath); if (err) break; err = got_object_open_as_tree(&tree, s->repo, tree_id); free(tree_id); if (err) break; err = tree_view_visit_subtree(s, tree); if (err) { got_object_tree_close(tree); break; } if (slash == NULL) break; free(subpath); subpath = NULL; p = slash; } free(subpath); return err; } static const struct got_error * browse_commit_tree(struct tog_view **new_view, int begin_y, int begin_x, struct commit_queue_entry *entry, const char *path, const char *head_ref_name, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_tree_view_state *s; struct tog_view *tree_view; struct got_commit_object *commit = NULL; struct got_object_id *commit_id; *new_view = NULL; if (entry->id != NULL) commit_id = entry->id; else if (entry->worktree_entry) commit_id = tog_base_commit.id; else /* cannot happen */ return got_error(GOT_ERR_NOT_WORKTREE); tree_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_TREE); if (tree_view == NULL) return got_error_from_errno("view_open"); err = open_tree_view(tree_view, commit_id, head_ref_name, repo); if (err) return err; s = &tree_view->state.tree; *new_view = tree_view; if (got_path_is_root_dir(path)) return NULL; if (entry->worktree_entry) { err = got_object_open_as_commit(&commit, repo, commit_id); if (err != NULL) goto done; } err = tree_view_walk_path(s, commit ? commit : entry->commit, path); done: if (commit != NULL) got_object_commit_close(commit); if (err != NULL) { view_close(tree_view); *new_view = NULL; } return err; } /* * If work tree entries have been pushed onto the commit queue and the * first commit entry is still displayed, scroll the view so the new * work tree entries are visible. If the selection cursor is still on * the first commit entry, keep the cursor in place such that the first * work tree entry is selected, otherwise move the selection cursor so * the currently selected commit stays selected if it remains on screen. */ static void worktree_entries_reveal(struct tog_log_thread_args *a) { struct commit_queue_entry **first = a->first_displayed_entry; struct commit_queue_entry **select = a->selected_entry; int *cursor = a->selected; int wts = a->wctx.wt_state; #define select_worktree_entry(_first, _selected) do { \ *_first = TAILQ_FIRST(&a->real_commits->head); \ *_selected = *_first; \ } while (0) if (first == NULL) select_worktree_entry(first, select); else if (*select == *first) { if (wts == TOG_WORKTREE_CHANGES_LOCAL && (*first)->idx == 1) select_worktree_entry(first, select); else if (wts == TOG_WORKTREE_CHANGES_STAGED && (*first)->idx == 1) select_worktree_entry(first, select); else if (wts & TOG_WORKTREE_CHANGES_ALL && (*first)->idx == 2) select_worktree_entry(first, select); } else if (wts & TOG_WORKTREE_CHANGES_ALL && (*first)->idx == 2) { *first = TAILQ_FIRST(&a->real_commits->head); if (*cursor + 2 < *a->view_nlines - 1) (*cursor) += 2; else if (*cursor + 1 < *a->view_nlines - 1) { *select = TAILQ_PREV(*select, commit_queue_head, entry); ++(*cursor); } else { *select = TAILQ_PREV(*select, commit_queue_head, entry); *select = TAILQ_PREV(*select, commit_queue_head, entry); } } else if (wts != 0 && (*first)->idx == 1) { *first = TAILQ_FIRST(&a->real_commits->head); if (*cursor + 1 < *a->view_nlines - 1) ++(*cursor); else *select = TAILQ_PREV(*select, commit_queue_head, entry); } #undef select_worktree_entry } static const struct got_error * block_signals_used_by_main_thread(void) { sigset_t sigset; int errcode; if (sigemptyset(&sigset) == -1) return got_error_from_errno("sigemptyset"); /* tog handles SIGWINCH, SIGCONT, SIGINT, SIGTERM */ if (sigaddset(&sigset, SIGWINCH) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGCONT) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGINT) == -1) return got_error_from_errno("sigaddset"); if (sigaddset(&sigset, SIGTERM) == -1) return got_error_from_errno("sigaddset"); /* ncurses handles SIGTSTP */ if (sigaddset(&sigset, SIGTSTP) == -1) return got_error_from_errno("sigaddset"); errcode = pthread_sigmask(SIG_BLOCK, &sigset, NULL); if (errcode) return got_error_set_errno(errcode, "pthread_sigmask"); return NULL; } static void * log_thread(void *arg) { const struct got_error *err = NULL; int errcode = 0; struct tog_log_thread_args *a = arg; int done = 0; /* * Sync startup with main thread such that we begin our * work once view_input() has released the mutex. */ errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); return (void *)err; } err = block_signals_used_by_main_thread(); if (err) { pthread_mutex_unlock(&tog_mutex); goto done; } while (!done && !err && !tog_fatal_signal_received()) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_unlock"); goto done; } err = queue_commits(a); if (err) { if (err->code != GOT_ERR_ITER_COMPLETED) goto done; err = NULL; done = 1; a->commits_needed = 0; } else if (a->commits_needed > 0 && !a->load_all) { if (*a->limiting) { if (a->limit_match) a->commits_needed--; } else a->commits_needed--; } errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } else if (*a->quit) done = 1; else if (*a->limiting && *a->first_displayed_entry == NULL) { *a->first_displayed_entry = TAILQ_FIRST(&a->limit_commits->head); *a->selected_entry = *a->first_displayed_entry; } else if (*a->first_displayed_entry == NULL) { *a->first_displayed_entry = TAILQ_FIRST(&a->real_commits->head); *a->selected_entry = *a->first_displayed_entry; } if (done) a->log_complete = 1; errcode = pthread_cond_signal(&a->commit_loaded); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_signal"); pthread_mutex_unlock(&tog_mutex); goto done; } if (a->commits_needed == 0 && a->need_wt_status) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_unlock"); goto done; } err = tog_worktree_status(a); if (err != NULL) { if (err->code == GOT_ERR_CANCELLED) err = NULL; goto done; } errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } if (a->wctx.wt_state != 0) worktree_entries_reveal(a); a->need_wt_status = 0; } if (a->commits_needed == 0 && a->need_commit_marker && a->worktree) { errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_unlock"); goto done; } err = got_worktree_get_state(&tog_base_commit.marker, a->repo, a->worktree, NULL, NULL); if (err) goto done; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } a->need_commit_marker = 0; /* * The main thread did not close this * work tree yet. Close it now. */ got_worktree_close(a->worktree); a->worktree = NULL; if (*a->quit) done = 1; } if (done) a->commits_needed = 0; else { if (a->commits_needed == 0 && !a->load_all) { if (tog_io.wait_for_ui) { errcode = pthread_cond_signal( &a->log_loaded); if (errcode) { err = got_error_set_errno( errcode, "pthread_cond_signal"); pthread_mutex_unlock( &tog_mutex); goto done; } } errcode = pthread_cond_wait(&a->need_commits, &tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_wait"); pthread_mutex_unlock(&tog_mutex); goto done; } if (*a->quit) done = 1; } } } a->log_complete = 1; if (tog_io.wait_for_ui) { errcode = pthread_cond_signal(&a->log_loaded); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_signal"); } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); done: if (err) { tog_thread_error = 1; pthread_cond_signal(&a->commit_loaded); if (a->worktree) { got_worktree_close(a->worktree); a->worktree = NULL; } } return (void *)err; } static const struct got_error * stop_log_thread(struct tog_log_view_state *s) { const struct got_error *err = NULL, *thread_err = NULL; int errcode; if (s->thread) { s->quit = 1; errcode = pthread_cond_signal(&s->thread_args.need_commits); if (errcode) return got_error_set_errno(errcode, "pthread_cond_signal"); errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); errcode = pthread_join(s->thread, (void **)&thread_err); if (errcode) return got_error_set_errno(errcode, "pthread_join"); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); s->thread = 0; //NULL; } if (s->thread_args.repo) { err = got_repo_close(s->thread_args.repo); s->thread_args.repo = NULL; } if (s->thread_args.pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(s->thread_args.pack_fds); if (err == NULL) err = pack_err; s->thread_args.pack_fds = NULL; } if (s->thread_args.graph) { got_commit_graph_close(s->thread_args.graph); s->thread_args.graph = NULL; } return err ? err : thread_err; } static void worktree_ctx_close(struct tog_log_thread_args *ta) { struct tog_worktree_ctx *wctx = &ta->wctx; if (wctx->active) { free(wctx->wt_author); wctx->wt_author = NULL; free(wctx->wt_root); wctx->wt_root = NULL; free(wctx->wt_ref); wctx->wt_ref = NULL; wctx->wt_state = 0; ta->need_wt_status = 1; } } static const struct got_error * close_log_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int errcode; log_mark_clear(s); err = stop_log_thread(s); errcode = pthread_cond_destroy(&s->thread_args.need_commits); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_destroy"); errcode = pthread_cond_destroy(&s->thread_args.commit_loaded); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_destroy"); if (using_mock_io) { errcode = pthread_cond_destroy(&s->thread_args.log_loaded); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_destroy"); } free_commits(&s->limit_commits); free_commits(&s->real_commits); free_colors(&s->colors); free(s->in_repo_path); s->in_repo_path = NULL; free(s->start_id); s->start_id = NULL; free(s->head_ref_name); s->head_ref_name = NULL; worktree_ctx_close(&s->thread_args); return err; } /* * We use two queues to implement the limit feature: first consists of * commits matching the current limit_regex; second is the real queue * of all known commits (real_commits). When the user starts limiting, * we swap queues such that all movement and displaying functionality * works with very slight change. */ static const struct got_error * limit_log_view(struct tog_view *view) { struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry; struct tog_view *v = view; const struct got_error *err = NULL; char pattern[1024]; int ret; if (view_is_hsplit_top(view)) v = view->child; else if (view->mode == TOG_VIEW_SPLIT_VERT && view->parent) v = view->parent; if (tog_io.input_str != NULL) { if (strlcpy(pattern, tog_io.input_str, sizeof(pattern)) >= sizeof(pattern)) return got_error(GOT_ERR_NO_SPACE); } else { wmove(v->window, v->nlines - 1, 0); wclrtoeol(v->window); mvwaddstr(v->window, v->nlines - 1, 0, "&/"); nodelay(v->window, FALSE); nocbreak(); echo(); ret = wgetnstr(v->window, pattern, sizeof(pattern)); cbreak(); noecho(); nodelay(v->window, TRUE); if (ret == ERR) return NULL; } if (*pattern == '\0') { /* * Safety measure for the situation where the user * resets limit without previously limiting anything. */ if (!s->limit_view) return NULL; /* * User could have pressed Ctrl+L, which refreshed the * commit queues, it means we can't save previously * (before limit took place) displayed entries, * because they would point to already free'ed memory, * so we are forced to always select first entry of * the queue. */ s->commits = &s->real_commits; s->first_displayed_entry = TAILQ_FIRST(&s->real_commits.head); s->selected_entry = s->first_displayed_entry; s->selected = 0; s->limit_view = 0; return NULL; } if (regcomp(&s->limit_regex, pattern, REG_EXTENDED | REG_NEWLINE)) return NULL; s->limit_view = 1; /* Clear the screen while loading limit view */ s->first_displayed_entry = NULL; s->last_displayed_entry = NULL; s->selected_entry = NULL; s->commits = &s->limit_commits; /* Prepare limit queue for new search */ free_commits(&s->limit_commits); s->limit_commits.ncommits = 0; /* First process commits, which are in queue already */ TAILQ_FOREACH(entry, &s->real_commits.head, entry) { int have_match = 0; if (entry->worktree_entry == 0) { err = match_commit(&have_match, entry->id, entry->commit, &s->limit_regex); if (err) return err; } if (have_match) { struct commit_queue_entry *matched; matched = alloc_commit_queue_entry(entry->commit, entry->id); if (matched == NULL) { err = got_error_from_errno( "alloc_commit_queue_entry"); break; } matched->commit = entry->commit; got_object_commit_retain(entry->commit); matched->idx = s->limit_commits.ncommits; TAILQ_INSERT_TAIL(&s->limit_commits.head, matched, entry); s->limit_commits.ncommits++; } } /* Second process all the commits, until we fill the screen */ if (s->limit_commits.ncommits < view->nlines - 1 && !s->thread_args.log_complete) { s->thread_args.commits_needed += view->nlines - s->limit_commits.ncommits - 1; err = trigger_log_thread(view, 1); if (err) return err; } s->first_displayed_entry = TAILQ_FIRST(&s->commits->head); s->selected_entry = TAILQ_FIRST(&s->commits->head); s->selected = 0; return NULL; } static const struct got_error * search_start_log_view(struct tog_view *view) { struct tog_log_view_state *s = &view->state.log; s->matched_entry = NULL; s->search_entry = NULL; return NULL; } static const struct got_error * search_next_log_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; struct commit_queue_entry *entry; /* Display progress update in log view. */ err = show_log_view(view); if (err != NULL) return err; update_panels(); doupdate(); if (s->search_entry) { if (!using_mock_io) { int errcode, ch; errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); ch = wgetch(view->window); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (ch == CTRL('g') || ch == KEY_BACKSPACE) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } } if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(s->search_entry, entry); else entry = TAILQ_PREV(s->search_entry, commit_queue_head, entry); } else if (s->matched_entry) { /* * If the user has moved the cursor after we hit a match, * the position from where we should continue searching * might have changed. */ if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(s->selected_entry, entry); else entry = TAILQ_PREV(s->selected_entry, commit_queue_head, entry); } else { entry = s->selected_entry; } while (1) { int have_match = 0; if (entry == NULL) { if (s->thread_args.log_complete || view->searching == TOG_SEARCH_BACKWARD) { view->search_next_done = (s->matched_entry == NULL ? TOG_SEARCH_HAVE_NONE : TOG_SEARCH_NO_MORE); s->search_entry = NULL; return NULL; } /* * Poke the log thread for more commits and return, * allowing the main loop to make progress. Search * will resume at s->search_entry once we come back. */ s->search_entry = s->selected_entry; s->thread_args.commits_needed++; return trigger_log_thread(view, 0); } if (entry->worktree_entry == 0) { err = match_commit(&have_match, entry->id, entry->commit, &view->regex); if (err) break; if (have_match) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = entry; break; } } s->search_entry = entry; if (view->searching == TOG_SEARCH_FORWARD) entry = TAILQ_NEXT(entry, entry); else entry = TAILQ_PREV(entry, commit_queue_head, entry); } if (s->matched_entry) { int cur = s->selected_entry->idx; while (cur < s->matched_entry->idx) { err = input_log_view(NULL, view, KEY_DOWN); if (err) return err; cur++; } while (cur > s->matched_entry->idx) { err = input_log_view(NULL, view, KEY_UP); if (err) return err; cur--; } } s->search_entry = NULL; return NULL; } static const struct got_error * open_log_view(struct tog_view *view, struct got_object_id *start_id, struct got_repository *repo, const char *head_ref_name, const char *in_repo_path, int log_branches, struct got_worktree *worktree) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; struct got_repository *thread_repo = NULL; struct got_commit_graph *thread_graph = NULL; int errcode; if (in_repo_path != s->in_repo_path) { free(s->in_repo_path); s->in_repo_path = strdup(in_repo_path); if (s->in_repo_path == NULL) { err = got_error_from_errno("strdup"); goto done; } } /* The commit queue only contains commits being displayed. */ TAILQ_INIT(&s->real_commits.head); s->real_commits.ncommits = 0; s->commits = &s->real_commits; TAILQ_INIT(&s->limit_commits.head); s->limit_view = 0; s->limit_commits.ncommits = 0; s->repo = repo; if (head_ref_name) { s->head_ref_name = strdup(head_ref_name); if (s->head_ref_name == NULL) { err = got_error_from_errno("strdup"); goto done; } } s->start_id = got_object_id_dup(start_id); if (s->start_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } s->log_branches = log_branches; s->use_committer = 1; STAILQ_INIT(&s->colors); if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^$", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_AUTHOR, get_color_value("TOG_COLOR_AUTHOR")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_DATE, get_color_value("TOG_COLOR_DATE")); if (err) goto done; } view->show = show_log_view; view->input = input_log_view; view->resize = resize_log_view; view->close = close_log_view; view->search_start = search_start_log_view; view->search_next = search_next_log_view; if (s->thread_args.pack_fds == NULL) { err = got_repo_pack_fds_open(&s->thread_args.pack_fds); if (err) goto done; } err = got_repo_open(&thread_repo, got_repo_get_path(repo), NULL, s->thread_args.pack_fds); if (err) goto done; err = got_commit_graph_open(&thread_graph, s->in_repo_path, !s->log_branches); if (err) goto done; err = got_commit_graph_bfsort(thread_graph, s->start_id, s->repo, NULL, NULL); if (err) goto done; errcode = pthread_cond_init(&s->thread_args.need_commits, NULL); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_init"); goto done; } errcode = pthread_cond_init(&s->thread_args.commit_loaded, NULL); if (errcode) { err = got_error_set_errno(errcode, "pthread_cond_init"); goto done; } if (using_mock_io) { int rc; rc = pthread_cond_init(&s->thread_args.log_loaded, NULL); if (rc) return got_error_set_errno(rc, "pthread_cond_init"); } s->thread_args.view_nlines = &view->nlines; s->thread_args.commits_needed = view->nlines; s->thread_args.graph = thread_graph; s->thread_args.real_commits = &s->real_commits; s->thread_args.limit_commits = &s->limit_commits; s->thread_args.in_repo_path = s->in_repo_path; s->thread_args.start_id = s->start_id; s->thread_args.repo = thread_repo; s->thread_args.log_complete = 0; s->thread_args.quit = &s->quit; s->thread_args.first_displayed_entry = &s->first_displayed_entry; s->thread_args.last_displayed_entry = &s->last_displayed_entry; s->thread_args.selected_entry = &s->selected_entry; s->thread_args.selected = &s->selected; s->thread_args.searching = &view->searching; s->thread_args.search_next_done = &view->search_next_done; s->thread_args.regex = &view->regex; s->thread_args.limiting = &s->limit_view; s->thread_args.limit_regex = &s->limit_regex; s->thread_args.limit_commits = &s->limit_commits; s->thread_args.worktree = worktree; if (worktree) { s->thread_args.wctx.active = 1; s->thread_args.need_wt_status = 1; s->thread_args.need_commit_marker = 1; } done: if (err) { if (view->close == NULL) close_log_view(view); view_close(view); } return err; } static const struct got_error * show_log_view(struct tog_view *view) { const struct got_error *err; struct tog_log_view_state *s = &view->state.log; if (s->thread == 0) { //NULL) { int errcode = pthread_create(&s->thread, NULL, log_thread, &s->thread_args); if (errcode) return got_error_set_errno(errcode, "pthread_create"); if (s->thread_args.commits_needed > 0) { err = trigger_log_thread(view, 1); if (err) return err; } } return draw_commits(view); } static void log_move_cursor_up(struct tog_view *view, int page, int home) { struct tog_log_view_state *s = &view->state.log; if (s->first_displayed_entry == NULL) return; if (s->selected_entry->idx == 0) view->count = 0; if ((page && TAILQ_FIRST(&s->commits->head) == s->first_displayed_entry) || home) s->selected = home ? 0 : MAX(0, s->selected - page - 1); if (!page && !home && s->selected > 0) --s->selected; else log_scroll_up(s, home ? s->commits->ncommits : MAX(page, 1)); select_commit(s); return; } static const struct got_error * log_move_cursor_down(struct tog_view *view, int page) { struct tog_log_view_state *s = &view->state.log; const struct got_error *err = NULL; int eos = view->nlines - 2; if (s->first_displayed_entry == NULL) return NULL; if (s->thread_args.log_complete && s->selected_entry->idx >= s->commits->ncommits - 1) return NULL; if (view_is_hsplit_top(view)) --eos; /* border consumes the last line */ if (!page) { if (s->selected < MIN(eos, s->commits->ncommits - 1)) ++s->selected; else err = log_scroll_down(view, 1); } else if (s->thread_args.load_all && s->thread_args.log_complete) { struct commit_queue_entry *entry; int n; s->selected = 0; entry = TAILQ_LAST(&s->commits->head, commit_queue_head); s->last_displayed_entry = entry; for (n = 0; n <= eos; n++) { if (entry == NULL) break; s->first_displayed_entry = entry; entry = TAILQ_PREV(entry, commit_queue_head, entry); } if (n > 0) s->selected = n - 1; } else { if (s->last_displayed_entry->idx == s->commits->ncommits - 1 && s->thread_args.log_complete) s->selected += MIN(page, s->commits->ncommits - s->selected_entry->idx - 1); else err = log_scroll_down(view, page); } if (err) return err; /* * We might necessarily overshoot in horizontal * splits; if so, select the last displayed commit. */ if (view_is_hsplit_top(view) && s->first_displayed_entry && s->last_displayed_entry) { s->selected = MIN(s->selected, s->last_displayed_entry->idx - s->first_displayed_entry->idx); } select_commit(s); if (s->thread_args.log_complete && s->selected_entry->idx == s->commits->ncommits - 1) view->count = 0; return NULL; } static void view_get_split(struct tog_view *view, int *y, int *x) { *x = 0; *y = 0; if (view->mode == TOG_VIEW_SPLIT_HRZN) { if (view->child && view->child->resized_y) *y = view->child->resized_y; else if (view->resized_y) *y = view->resized_y; else *y = view_split_begin_y(view->lines); } else if (view->mode == TOG_VIEW_SPLIT_VERT) { if (view->child && view->child->resized_x) *x = view->child->resized_x; else if (view->resized_x) *x = view->resized_x; else *x = view_split_begin_x(view->begin_x); } } /* Split view horizontally at y and offset view->state->selected line. */ static const struct got_error * view_init_hsplit(struct tog_view *view, int y) { const struct got_error *err = NULL; view->nlines = y; view->ncols = COLS; err = view_resize(view); if (err) return err; err = offset_selection_down(view); return err; } static const struct got_error * log_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int g, idx = s->selected_entry->idx; if (s->first_displayed_entry == NULL || s->last_displayed_entry == NULL) return NULL; g = view->gline; view->gline = 0; if (g >= s->first_displayed_entry->idx + 1 && g <= s->last_displayed_entry->idx + 1 && g - s->first_displayed_entry->idx - 1 < nlines) { s->selected = g - s->first_displayed_entry->idx - 1; select_commit(s); return NULL; } if (idx + 1 < g) { err = log_move_cursor_down(view, g - idx - 1); if (!err && g > s->selected_entry->idx + 1) err = log_move_cursor_down(view, g - s->first_displayed_entry->idx - 1); if (err) return err; } else if (idx + 1 > g) log_move_cursor_up(view, idx - g + 1, 0); if (g < nlines && s->first_displayed_entry->idx == 0) s->selected = g - 1; select_commit(s); return NULL; } static void horizontal_scroll_input(struct tog_view *view, int ch) { switch (ch) { case KEY_LEFT: case 'h': view->x -= MIN(view->x, 2); if (view->x <= 0) view->count = 0; break; case KEY_RIGHT: case 'l': if (view->x + view->ncols / 2 < view->maxx) view->x += 2; else view->count = 0; break; case '0': view->x = 0; break; case '$': view->x = MAX(view->maxx - view->ncols / 2, 0); view->count = 0; break; default: break; } } static void log_mark_commit(struct tog_log_view_state *s) { if (s->selected_entry == s->marked_entry) s->marked_entry = NULL; else s->marked_entry = s->selected_entry; } static const struct got_error * input_log_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_log_view_state *s = &view->state.log; int eos, nscroll; if (s->thread_args.load_all) { if (ch == CTRL('g') || ch == KEY_BACKSPACE) s->thread_args.load_all = 0; else if (s->thread_args.log_complete) { err = log_move_cursor_down(view, s->commits->ncommits); s->thread_args.load_all = 0; } if (err) return err; } eos = nscroll = view->nlines - 1; if (view_is_hsplit_top(view)) --eos; /* border */ if (view->gline) return log_goto_line(view, eos); switch (ch) { case '&': view->count = 0; err = limit_log_view(view); break; case 'q': s->quit = 1; break; case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'k': case KEY_UP: case '<': case ',': case CTRL('p'): log_move_cursor_up(view, 0, 0); break; case 'g': case '=': case KEY_HOME: log_move_cursor_up(view, 0, 1); view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': log_move_cursor_up(view, nscroll, 0); break; case 'j': case KEY_DOWN: case '>': case '.': case CTRL('n'): err = log_move_cursor_down(view, 0); break; case '@': s->use_committer = !s->use_committer; view->action = s->use_committer ? "show committer" : "show commit author"; break; case 'G': case '*': case KEY_END: { /* We don't know yet how many commits, so we're forced to * traverse them all. */ view->count = 0; s->thread_args.load_all = 1; if (!s->thread_args.log_complete) return trigger_log_thread(view, 0); err = log_move_cursor_down(view, s->commits->ncommits); s->thread_args.load_all = 0; break; } case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': err = log_move_cursor_down(view, nscroll); break; case KEY_RESIZE: if (s->selected > view->nlines - 2) s->selected = view->nlines - 2; if (s->selected > s->commits->ncommits - 1) s->selected = s->commits->ncommits - 1; select_commit(s); if (s->commits->ncommits < view->nlines - 1 && !s->thread_args.log_complete) { s->thread_args.commits_needed += (view->nlines - 1) - s->commits->ncommits; err = trigger_log_thread(view, 1); } break; case KEY_ENTER: case '\r': view->count = 0; if (s->selected_entry == NULL) break; err = view_request_new(new_view, view, TOG_VIEW_DIFF); break; case 'T': view->count = 0; if (s->selected_entry == NULL) break; err = view_request_new(new_view, view, TOG_VIEW_TREE); break; case KEY_BACKSPACE: case CTRL('l'): case 'B': view->count = 0; if (ch == KEY_BACKSPACE && got_path_is_root_dir(s->in_repo_path)) break; err = stop_log_thread(s); if (err) return err; if (ch == KEY_BACKSPACE) { char *parent_path; err = got_path_dirname(&parent_path, s->in_repo_path); if (err) return err; free(s->in_repo_path); s->in_repo_path = parent_path; s->thread_args.in_repo_path = s->in_repo_path; } else if (ch == CTRL('l')) { struct got_object_id *start_id; err = got_repo_match_object_id(&start_id, NULL, s->head_ref_name ? s->head_ref_name : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, s->repo); if (err) { if (s->head_ref_name == NULL || err->code != GOT_ERR_NOT_REF) return err; /* Try to cope with deleted references. */ free(s->head_ref_name); s->head_ref_name = NULL; err = got_repo_match_object_id(&start_id, NULL, GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, s->repo); if (err) return err; } free(s->start_id); s->start_id = start_id; s->thread_args.start_id = s->start_id; } else /* 'B' */ s->log_branches = !s->log_branches; if (s->thread_args.pack_fds == NULL) { err = got_repo_pack_fds_open(&s->thread_args.pack_fds); if (err) return err; } err = got_repo_open(&s->thread_args.repo, got_repo_get_path(s->repo), NULL, s->thread_args.pack_fds); if (err) return err; tog_free_refs(); err = tog_load_refs(s->repo, 0); if (err) return err; err = got_commit_graph_open(&s->thread_args.graph, s->in_repo_path, !s->log_branches); if (err) return err; err = got_commit_graph_bfsort(s->thread_args.graph, s->start_id, s->repo, NULL, NULL); if (err) return err; free_commits(&s->real_commits); free_commits(&s->limit_commits); s->first_displayed_entry = NULL; s->last_displayed_entry = NULL; s->selected_entry = NULL; s->selected = 0; s->thread_args.log_complete = 0; s->quit = 0; s->thread_args.commits_needed = view->lines; s->matched_entry = NULL; s->search_entry = NULL; tog_base_commit.idx = -1; worktree_ctx_close(&s->thread_args); view->offset = 0; break; case 'm': if (s->selected_entry->worktree_entry == 0) log_mark_commit(s); break; case 'R': view->count = 0; err = view_request_new(new_view, view, TOG_VIEW_REF); break; default: view->count = 0; break; } return err; } static const struct got_error * apply_unveil(const char *repo_path, const char *worktree_path) { const struct got_error *error; #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) return got_error_from_errno2("unveil", "gmon.out"); #endif if (repo_path && unveil(repo_path, "r") != 0) return got_error_from_errno2("unveil", repo_path); if (worktree_path && unveil(worktree_path, "rwc") != 0) return got_error_from_errno2("unveil", worktree_path); if (unveil(GOT_TMPDIR_STR, "rwc") != 0) return got_error_from_errno2("unveil", GOT_TMPDIR_STR); error = got_privsep_unveil_exec_helpers(); if (error != NULL) return error; if (unveil(NULL, NULL) != 0) return got_error_from_errno("unveil"); return NULL; } static const struct got_error * init_mock_term(const char *test_script_path) { const struct got_error *err = NULL; const char *screen_dump_path; int in; if (test_script_path == NULL || *test_script_path == '\0') return got_error_msg(GOT_ERR_IO, "TOG_TEST_SCRIPT not defined"); tog_io.f = fopen(test_script_path, "re"); if (tog_io.f == NULL) { err = got_error_from_errno_fmt("fopen: %s", test_script_path); goto done; } /* test mode, we don't want any output */ tog_io.cout = fopen("/dev/null", "w+"); if (tog_io.cout == NULL) { err = got_error_from_errno2("fopen", "/dev/null"); goto done; } in = dup(fileno(tog_io.cout)); if (in == -1) { err = got_error_from_errno("dup"); goto done; } tog_io.cin = fdopen(in, "r"); if (tog_io.cin == NULL) { err = got_error_from_errno("fdopen"); close(in); goto done; } screen_dump_path = getenv("TOG_SCR_DUMP"); if (screen_dump_path == NULL || *screen_dump_path == '\0') return got_error_msg(GOT_ERR_IO, "TOG_SCR_DUMP not defined"); tog_io.sdump = fopen(screen_dump_path, "we"); if (tog_io.sdump == NULL) { err = got_error_from_errno2("fopen", screen_dump_path); goto done; } if (fseeko(tog_io.f, 0L, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } if (newterm(NULL, tog_io.cout, tog_io.cin) == NULL) err = got_error_msg(GOT_ERR_IO, "newterm: failed to initialise curses"); using_mock_io = 1; done: if (err) tog_io_close(); return err; } static void init_curses(void) { if (using_mock_io) /* In test mode we use a fake terminal */ return; initscr(); cbreak(); halfdelay(1); /* Fast refresh while initial view is loading. */ noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); curs_set(0); if (getenv("TOG_COLORS") != NULL) { start_color(); use_default_colors(); } return; } static const struct got_error * set_tog_base_commit(struct got_repository *repo, struct got_worktree *worktree) { tog_base_commit.id = got_object_id_dup( got_worktree_get_base_commit_id(worktree)); if (tog_base_commit.id == NULL) return got_error_from_errno( "got_object_id_dup"); return NULL; } static const struct got_error * get_in_repo_path_from_argv0(char **in_repo_path, int argc, char *argv[], struct got_repository *repo, struct got_worktree *worktree) { const struct got_error *err = NULL; if (argc == 0) { *in_repo_path = strdup("/"); if (*in_repo_path == NULL) return got_error_from_errno("strdup"); return NULL; } if (worktree) { const char *prefix = got_worktree_get_path_prefix(worktree); char *p; err = got_worktree_resolve_path(&p, worktree, argv[0]); if (err) return err; if (asprintf(in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "", p) == -1) { err = got_error_from_errno("asprintf"); *in_repo_path = NULL; } free(p); } else err = got_repo_map_path(in_repo_path, repo, argv[0]); return err; } static const struct got_error * cmd_log(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *start_id = NULL; char *in_repo_path = NULL, *repo_path = NULL, *cwd = NULL; char *keyword_idstr = NULL, *start_commit = NULL, *label = NULL; struct got_reference *ref = NULL; const char *head_ref_name = NULL; int ch, log_branches = 0; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "bc:r:")) != -1) { switch (ch) { case 'b': log_branches = 1; break; case 'c': start_commit = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_log(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_log(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) { error = got_error_from_errno("getcwd"); goto done; } error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; /* already loaded by tog_log_with_path()? */ if (TAILQ_EMPTY(&tog_refs)) { error = tog_load_refs(repo, 0); if (error) goto done; } if (start_commit == NULL) { error = got_repo_match_object_id(&start_id, &label, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; head_ref_name = label; } else { error = got_keyword_to_idstr(&keyword_idstr, start_commit, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) start_commit = keyword_idstr; error = got_ref_open(&ref, repo, start_commit, 0); if (error == NULL) head_ref_name = got_ref_get_name(ref); else if (error->code != GOT_ERR_NOT_REF) goto done; error = got_repo_match_object_id(&start_id, NULL, start_commit, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; } view = view_open(0, 0, 0, 0, TOG_VIEW_LOG); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; } error = open_log_view(view, start_id, repo, head_ref_name, in_repo_path, log_branches, worktree); if (error) goto done; if (worktree) { /* The work tree will be closed by the log thread. */ worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(keyword_idstr); free(in_repo_path); free(repo_path); free(cwd); free(start_id); free(label); if (ref) got_ref_close(ref); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } __dead static void usage_diff(void) { endwin(); fprintf(stderr, "usage: %s diff [-asw] [-C number] [-c commit] " "[-r repository-path] [object1 object2 | path ...]\n", getprogname()); exit(1); } static int match_line(const char *line, regex_t *regex, size_t nmatch, regmatch_t *regmatch) { return regexec(regex, line, nmatch, regmatch, 0) == 0; } static struct tog_color * match_color(struct tog_colors *colors, const char *line) { struct tog_color *tc = NULL; STAILQ_FOREACH(tc, colors, entry) { if (match_line(line, &tc->regex, 0, NULL)) return tc; } return NULL; } static const struct got_error * add_matched_line(int *wtotal, const char *line, int wlimit, int col_tab_align, WINDOW *window, int skipcol, regmatch_t *regmatch) { const struct got_error *err = NULL; char *exstr = NULL; wchar_t *wline = NULL; int rme, rms, n, width, scrollx; int width0 = 0, width1 = 0, width2 = 0; char *seg0 = NULL, *seg1 = NULL, *seg2 = NULL; *wtotal = 0; rms = regmatch->rm_so; rme = regmatch->rm_eo; err = expand_tab(&exstr, line); if (err) return err; /* Split the line into 3 segments, according to match offsets. */ seg0 = strndup(exstr, rms); if (seg0 == NULL) { err = got_error_from_errno("strndup"); goto done; } seg1 = strndup(exstr + rms, rme - rms); if (seg1 == NULL) { err = got_error_from_errno("strndup"); goto done; } seg2 = strdup(exstr + rme); if (seg2 == NULL) { err = got_error_from_errno("strndup"); goto done; } /* draw up to matched token if we haven't scrolled past it */ err = format_line(&wline, &width0, NULL, seg0, 0, wlimit, col_tab_align, 1); if (err) goto done; n = MAX(width0 - skipcol, 0); if (n) { free(wline); err = format_line(&wline, &width, &scrollx, seg0, skipcol, wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, &wline[scrollx]); wlimit -= width; *wtotal += width; } if (wlimit > 0) { int i = 0, w = 0; size_t wlen; free(wline); err = format_line(&wline, &width1, NULL, seg1, 0, wlimit, col_tab_align, 1); if (err) goto done; wlen = wcslen(wline); while (i < wlen) { width = wcwidth(wline[i]); if (width == -1) { /* should not happen, tabs are expanded */ err = got_error(GOT_ERR_RANGE); goto done; } if (width0 + w + width > skipcol) break; w += width; i++; } /* draw (visible part of) matched token (if scrolled into it) */ if (width1 - w > 0) { wattron(window, A_STANDOUT); waddwstr(window, &wline[i]); wattroff(window, A_STANDOUT); wlimit -= (width1 - w); *wtotal += (width1 - w); } } if (wlimit > 0) { /* draw rest of line */ free(wline); if (skipcol > width0 + width1) { err = format_line(&wline, &width2, &scrollx, seg2, skipcol - (width0 + width1), wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, &wline[scrollx]); } else { err = format_line(&wline, &width2, NULL, seg2, 0, wlimit, col_tab_align, 1); if (err) goto done; waddwstr(window, wline); } *wtotal += width2; } done: free(wline); free(exstr); free(seg0); free(seg1); free(seg2); return err; } static int gotoline(struct tog_view *view, int *lineno, int *nprinted) { FILE *f = NULL; int *eof, *first, *selected; if (view->type == TOG_VIEW_DIFF) { struct tog_diff_view_state *s = &view->state.diff; first = &s->first_displayed_line; selected = first; eof = &s->eof; f = s->f; } else if (view->type == TOG_VIEW_HELP) { struct tog_help_view_state *s = &view->state.help; first = &s->first_displayed_line; selected = first; eof = &s->eof; f = s->f; } else if (view->type == TOG_VIEW_BLAME) { struct tog_blame_view_state *s = &view->state.blame; first = &s->first_displayed_line; selected = &s->selected_line; eof = &s->eof; f = s->blame.f; } else return 0; /* Center gline in the middle of the page like vi(1). */ if (*lineno < view->gline - (view->nlines - 3) / 2) return 0; if (*first != 1 && (*lineno > view->gline - (view->nlines - 3) / 2)) { rewind(f); *eof = 0; *first = 1; *lineno = 0; *nprinted = 0; return 0; } *selected = view->gline <= (view->nlines - 3) / 2 ? view->gline : (view->nlines - 3) / 2 + 1; view->gline = 0; return 1; } static const struct got_error * draw_file(struct tog_view *view, const char *header) { struct tog_diff_view_state *s = &view->state.diff; regmatch_t *regmatch = &view->regmatch; const struct got_error *err; int nprinted = 0; char *line; size_t linesize = 0; ssize_t linelen; wchar_t *wline; int width; int max_lines = view->nlines; int nlines = s->nlines; off_t line_offset; s->lineno = s->first_displayed_line - 1; line_offset = s->lines[s->first_displayed_line - 1].offset; if (fseeko(s->f, line_offset, SEEK_SET) == -1) return got_error_from_errno("fseek"); werase(view->window); if (view->gline > s->nlines - 1) view->gline = s->nlines - 1; if (header) { int ln = view->gline ? view->gline <= (view->nlines - 3) / 2 ? 1 : view->gline - (view->nlines - 3) / 2 : s->lineno + s->selected_line; if (asprintf(&line, "[%d/%d] %s", ln, nlines, header) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); waddwstr(view->window, wline); free(wline); wline = NULL; while (width++ < view->ncols) waddch(view->window, ' '); if (view_needs_focus_indication(view)) wstandend(view->window); if (max_lines <= 1) return NULL; max_lines--; } s->eof = 0; view->maxx = 0; line = NULL; while (max_lines > 0 && nprinted < max_lines) { enum got_diff_line_type linetype; attr_t attr = 0; linelen = getline(&line, &linesize, s->f); if (linelen == -1) { if (feof(s->f)) { s->eof = 1; break; } free(line); return got_ferror(s->f, GOT_ERR_IO); } if (++s->lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &s->lineno, &nprinted)) continue; if (s->lineno == view->hiline) attr = A_STANDOUT; /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, view->x ? 1 : 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; linetype = s->lines[s->lineno].type; if (linetype > GOT_DIFF_LINE_LOGMSG && linetype < GOT_DIFF_LINE_CONTEXT) attr |= COLOR_PAIR(linetype); if (attr) wattron(view->window, attr); if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols, 0, view->window, view->x, regmatch); if (err) { free(line); return err; } } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols, 0, view->x ? 1 : 0); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); free(wline); wline = NULL; } if (s->lineno == view->hiline) { /* highlight full gline length */ while (width++ < view->ncols) waddch(view->window, ' '); } else { if (width <= view->ncols - 1) waddch(view->window, '\n'); } if (attr) wattroff(view->window, attr); if (++nprinted == 1) s->first_displayed_line = s->lineno; } free(line); if (nprinted >= 1) s->last_displayed_line = s->first_displayed_line + (nprinted - 1); else s->last_displayed_line = s->first_displayed_line; view_border(view); if (s->eof) { while (nprinted < view->nlines) { waddch(view->window, '\n'); nprinted++; } err = format_line(&wline, &width, NULL, TOG_EOF_STRING, 0, view->ncols, 0, 0); if (err) { return err; } wstandout(view->window); waddwstr(view->window, wline); free(wline); wline = NULL; wstandend(view->window); } return NULL; } static char * get_datestr(time_t *time, char *datebuf) { struct tm mytm, *tm; char *p, *s; tm = gmtime_r(time, &mytm); if (tm == NULL) return NULL; s = asctime_r(tm, datebuf); if (s == NULL) return NULL; p = strchr(s, '\n'); if (p) *p = '\0'; return s; } static const struct got_error * add_line_metadata(struct got_diff_line **lines, size_t *nlines, off_t off, uint8_t type) { struct got_diff_line *p; p = reallocarray(*lines, *nlines + 1, sizeof(**lines)); if (p == NULL) return got_error_from_errno("reallocarray"); *lines = p; (*lines)[*nlines].offset = off; (*lines)[*nlines].type = type; (*nlines)++; return NULL; } static const struct got_error * cat_diff(FILE *dst, FILE *src, struct got_diff_line **d_lines, size_t *d_nlines, struct got_diff_line *s_lines, size_t s_nlines) { struct got_diff_line *p; char buf[BUFSIZ]; size_t i, r; if (fseeko(src, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); for (;;) { r = fread(buf, 1, sizeof(buf), src); if (r == 0) { if (ferror(src)) return got_error_from_errno("fread"); if (feof(src)) break; } if (fwrite(buf, 1, r, dst) != r) return got_ferror(dst, GOT_ERR_IO); } if (s_nlines == 0 && *d_nlines == 0) return NULL; /* * If commit info was in dst, increment line offsets * of the appended diff content, but skip s_lines[0] * because offset zero is already in *d_lines. */ if (*d_nlines > 0) { for (i = 1; i < s_nlines; ++i) s_lines[i].offset += (*d_lines)[*d_nlines - 1].offset; if (s_nlines > 0) { --s_nlines; ++s_lines; } } p = reallocarray(*d_lines, *d_nlines + s_nlines, sizeof(*p)); if (p == NULL) { /* d_lines is freed in close_diff_view() */ return got_error_from_errno("reallocarray"); } *d_lines = p; memcpy(*d_lines + *d_nlines, s_lines, s_nlines * sizeof(*s_lines)); *d_nlines += s_nlines; return NULL; } static const struct got_error * write_diffstat(FILE *outfile, struct got_diff_line **lines, size_t *nlines, struct got_diffstat_cb_arg *dsa) { const struct got_error *err; struct got_pathlist_entry *pe; off_t offset; int n; if (*nlines == 0) { err = add_line_metadata(lines, nlines, 0, GOT_DIFF_LINE_NONE); if (err != NULL) return err; offset = 0; } else offset = (*lines)[*nlines - 1].offset; RB_FOREACH(pe, got_pathlist_head, dsa->paths) { struct got_diff_changed_path *cp = pe->data; int pad = dsa->max_path_len - pe->path_len + 1; n = fprintf(outfile, "%c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad, ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm); if (n < 0) return got_error_from_errno("fprintf"); offset += n; err = add_line_metadata(lines, nlines, offset, GOT_DIFF_LINE_CHANGES); if (err != NULL) return err; } if (fputc('\n', outfile) == EOF) return got_error_from_errno("fputc"); offset++; err = add_line_metadata(lines, nlines, offset, GOT_DIFF_LINE_NONE); if (err != NULL) return err; n = fprintf(outfile, "%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n", dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins, dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : ""); if (n < 0) return got_error_from_errno("fprintf"); offset += n; err = add_line_metadata(lines, nlines, offset, GOT_DIFF_LINE_NONE); if (err != NULL) return err; if (fputc('\n', outfile) == EOF) return got_error_from_errno("fputc"); offset++; return add_line_metadata(lines, nlines, offset, GOT_DIFF_LINE_NONE); } static const struct got_error * write_commit_info(struct got_diff_line **lines, size_t *nlines, struct got_object_id *commit_id, struct got_reflist_head *refs, struct got_repository *repo, int ignore_ws, int force_text_diff, struct got_diffstat_cb_arg *dsa, FILE *outfile) { const struct got_error *err = NULL; char datebuf[26], *datestr; struct got_commit_object *commit; char *id_str = NULL, *logmsg = NULL, *s = NULL, *line; time_t committer_time; const char *author, *committer; char *refs_str = NULL; off_t outoff = 0; int n; err = build_refs_str(&refs_str, refs, commit_id, repo); if (err) return err; err = got_object_open_as_commit(&commit, repo, commit_id); if (err) return err; err = got_object_id_str(&id_str, commit_id); if (err) { err = got_error_from_errno("got_object_id_str"); goto done; } err = add_line_metadata(lines, nlines, 0, GOT_DIFF_LINE_NONE); if (err) goto done; n = fprintf(outfile, "commit %s%s%s%s\n", id_str, refs_str ? " (" : "", refs_str ? refs_str : "", refs_str ? ")" : ""); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_META); if (err) goto done; n = fprintf(outfile, "from: %s\n", got_object_commit_get_author(commit)); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_AUTHOR); if (err) goto done; author = got_object_commit_get_author(commit); committer = got_object_commit_get_committer(commit); if (strcmp(author, committer) != 0) { n = fprintf(outfile, "via: %s\n", committer); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_AUTHOR); if (err) goto done; } committer_time = got_object_commit_get_committer_time(commit); datestr = get_datestr(&committer_time, datebuf); if (datestr) { n = fprintf(outfile, "date: %s UTC\n", datestr); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_DATE); if (err) goto done; } if (got_object_commit_get_nparents(commit) > 1) { const struct got_object_id_queue *parent_ids; struct got_object_qid *qid; int pn = 1; parent_ids = got_object_commit_get_parent_ids(commit); STAILQ_FOREACH(qid, parent_ids, entry) { err = got_object_id_str(&id_str, &qid->id); if (err) goto done; n = fprintf(outfile, "parent %d: %s\n", pn++, id_str); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_META); if (err) goto done; free(id_str); id_str = NULL; } } err = got_object_commit_get_logmsg(&logmsg, commit); if (err) goto done; s = logmsg; while ((line = strsep(&s, "\n")) != NULL) { n = fprintf(outfile, "%s\n", line); if (n < 0) { err = got_error_from_errno("fprintf"); goto done; } outoff += n; err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_LOGMSG); if (err) goto done; } done: free(id_str); free(logmsg); free(refs_str); got_object_commit_close(commit); return err; } static void evict_worktree_entry(struct tog_log_thread_args *ta, int victim) { struct commit_queue_entry *e, *v = *ta->selected_entry; if (victim == 0) return; /* paranoid check */ if (v->worktree_entry != victim) { TAILQ_FOREACH(v, &ta->real_commits->head, entry) { if (v->worktree_entry == victim) break; } if (v == NULL) return; } ta->wctx.wt_state &= ~victim; if (*ta->selected_entry == v) *ta->selected_entry = TAILQ_NEXT(v, entry); if (*ta->first_displayed_entry == v) *ta->first_displayed_entry = TAILQ_NEXT(v, entry); if (*ta->last_displayed_entry == v) *ta->last_displayed_entry = TAILQ_NEXT(v, entry); for (e = TAILQ_NEXT(v, entry); e != NULL; e = TAILQ_NEXT(e, entry)) --e->idx; --tog_base_commit.idx; --ta->real_commits->ncommits; TAILQ_REMOVE(&ta->real_commits->head, v, entry); free(v); } /* * Create a file which contains the target path of a symlink so we can feed * it as content to the diff engine. */ static const struct got_error * get_symlink_target_file(int *fd, int dirfd, const char *de_name, const char *abspath) { const struct got_error *err = NULL; char target_path[PATH_MAX]; ssize_t target_len, outlen; *fd = -1; if (dirfd != -1) { target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlinkat", abspath); } else { target_len = readlink(abspath, target_path, PATH_MAX); if (target_len == -1) return got_error_from_errno2("readlink", abspath); } *fd = got_opentempfd(); if (*fd == -1) return got_error_from_errno("got_opentempfd"); outlen = write(*fd, target_path, target_len); if (outlen == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } if (lseek(*fd, 0, SEEK_SET) == -1) { err = got_error_from_errno2("lseek", abspath); goto done; } done: if (err) { close(*fd); *fd = -1; } return err; } static const struct got_error * emit_base_commit_header(FILE *f, struct got_diff_line **lines, size_t *nlines, struct got_object_id *commit_id, struct got_worktree *worktree) { const struct got_error *err; struct got_object_id *base_commit_id; char *base_commit_idstr; int n; if (worktree == NULL) /* shouldn't happen */ return got_error(GOT_ERR_NOT_WORKTREE); base_commit_id = got_worktree_get_base_commit_id(worktree); if (commit_id != NULL) { if (got_object_id_cmp(commit_id, base_commit_id) != 0) base_commit_id = commit_id; } err = got_object_id_str(&base_commit_idstr, base_commit_id); if (err != NULL) return err; if ((n = fprintf(f, "commit - %s\n", base_commit_idstr)) < 0) err = got_error_from_errno("fprintf"); free(base_commit_idstr); if (err != NULL) return err; return add_line_metadata(lines, nlines, (*lines)[*nlines - 1].offset + n, GOT_DIFF_LINE_META); } static const struct got_error * tog_worktree_diff(void *arg, unsigned char status, unsigned char staged_status, const char *path, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id, int dirfd, const char *de_name) { const struct got_error *err = NULL; struct diff_worktree_arg *a = arg; struct got_blob_object *blob1 = NULL; struct stat sb; FILE *f2 = NULL; char *abspath = NULL, *label1 = NULL; off_t size1 = 0; off_t outoff = 0; int fd = -1, fd1 = -1, fd2 = -1; int n, f2_exists = 1; if (a->diff_staged) { if (staged_status != GOT_STATUS_MODIFY && staged_status != GOT_STATUS_ADD && staged_status != GOT_STATUS_DELETE) return NULL; } else { if (staged_status == GOT_STATUS_DELETE) return NULL; if (status == GOT_STATUS_NONEXISTENT) return got_error_set_errno(ENOENT, path); if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_ADD && status != GOT_STATUS_DELETE && status != GOT_STATUS_CONFLICT) return NULL; } err = got_opentemp_truncate(a->f1); if (err != NULL) return got_error_from_errno("got_opentemp_truncate"); err = got_opentemp_truncate(a->f2); if (err != NULL) return got_error_from_errno("got_opentemp_truncate"); if (!a->header_shown) { n = fprintf(a->outfile, "path + %s%s\n", got_worktree_get_root_path(a->worktree), a->diff_staged ? " (staged changes)" : ""); if (n < 0) return got_error_from_errno("fprintf"); outoff += n; err = add_line_metadata(a->lines, a->nlines, outoff, GOT_DIFF_LINE_META); if (err != NULL) return err; a->header_shown = 1; } err = emit_base_commit_header(a->outfile, a->lines, a->nlines, commit_id, a->worktree); if (err != NULL) return err; if (a->diff_staged) { const char *label1 = NULL, *label2 = NULL; switch (staged_status) { case GOT_STATUS_MODIFY: label1 = path; label2 = path; break; case GOT_STATUS_ADD: label2 = path; break; case GOT_STATUS_DELETE: label1 = path; break; default: return got_error(GOT_ERR_FILE_STATUS); } fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_diff_objects_as_blobs(a->lines, a->nlines, a->f1, a->f2, fd1, fd2, blob_id, staged_blob_id, label1, label2, a->diff_algo, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->repo, a->outfile); goto done; } fd1 = got_opentempfd(); if (fd1 == -1) return got_error_from_errno("got_opentempfd"); if (staged_status == GOT_STATUS_ADD || staged_status == GOT_STATUS_MODIFY) { char *id_str; err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id, 8192, fd1); if (err != NULL) goto done; err = got_object_id_str(&id_str, staged_blob_id); if (err != NULL) goto done; if (asprintf(&label1, "%s (staged)", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); goto done; } free(id_str); } else if (status != GOT_STATUS_ADD) { err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192, fd1); if (err != NULL) goto done; } if (status != GOT_STATUS_DELETE) { if (asprintf(&abspath, "%s/%s", got_worktree_get_root_path(a->worktree), path) == -1) { err = got_error_from_errno("asprintf"); goto done; } if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err != NULL) goto done; } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", abspath); goto done; } err = get_symlink_target_file(&fd, dirfd, de_name, abspath); if (err != NULL) goto done; } } if (fstat(fd, &sb) == -1) { err = got_error_from_errno2("fstat", abspath); goto done; } f2 = fdopen(fd, "r"); if (f2 == NULL) { err = got_error_from_errno2("fdopen", abspath); goto done; } fd = -1; } else { sb.st_size = 0; f2_exists = 0; } if (blob1 != NULL) { err = got_object_blob_dump_to_file(&size1, NULL, NULL, a->f1, blob1); if (err != NULL) goto done; } err = got_diff_blob_file(a->lines, a->nlines, blob1, a->f1, size1, label1, f2 != NULL ? f2 : a->f2, f2_exists, &sb, path, tog_diff_algo, a->diff_context, a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile); done: if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob1 != NULL) got_object_blob_close(blob1); if (f2 != NULL && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); free(abspath); free(label1); return err; } static const struct got_error * tog_diff_worktree(struct tog_diff_view_state *s, FILE *f, struct got_diff_line **lines, size_t *nlines, struct got_diffstat_cb_arg *dsa) { const struct got_error *close_err, *err; struct got_worktree *worktree = NULL; struct diff_worktree_arg arg; struct got_pathlist_head pathlist; char *cwd, *id_str = NULL; RB_INIT(&pathlist); cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); err = add_line_metadata(lines, nlines, 0, GOT_DIFF_LINE_NONE); if (err != NULL) goto done; err = got_worktree_open(&worktree, cwd, NULL); if (err != NULL) { if (err->code == GOT_ERR_WORKTREE_BUSY) { int n; if ((n = fprintf(f, "%s\n", err->msg)) < 0) { err = got_ferror(f, GOT_ERR_IO); goto done; } err = add_line_metadata(lines, nlines, n, GOT_DIFF_LINE_META); if (err != NULL) goto done; err = got_error(GOT_ERR_DIFF_NOCHANGES); } goto done; } err = got_object_id_str(&id_str, got_worktree_get_base_commit_id(worktree)); if (err != NULL) goto done; err = got_repo_match_object_id(&s->id1, NULL, id_str, GOT_OBJ_TYPE_ANY, &tog_refs, s->repo); if (err != NULL) goto done; arg.id_str = id_str; arg.diff_algo = tog_diff_algo; arg.repo = s->repo; arg.worktree = worktree; arg.diffstat = dsa; arg.diff_context = s->diff_context; arg.diff_staged = s->diff_staged; arg.ignore_whitespace = s->ignore_whitespace; arg.force_text_diff = s->force_text_diff; arg.header_shown = 0; arg.lines = lines; arg.nlines = nlines; arg.f1 = s->f1; arg.f2 = s->f2; arg.outfile = f; if (s->paths == NULL) { err = got_pathlist_insert(NULL, &pathlist, "", NULL); if (err != NULL) goto done; } err = got_worktree_status(worktree, s->paths ? s->paths : &pathlist, s->repo, 0, tog_worktree_diff, &arg, NULL, NULL); if (err != NULL) goto done; if (*nlines == 1) { const char *msg = TOG_WORKTREE_CHANGES_LOCAL_MSG; int n, victim = TOG_WORKTREE_CHANGES_LOCAL; if (s->diff_staged) { victim = TOG_WORKTREE_CHANGES_STAGED; msg = TOG_WORKTREE_CHANGES_STAGED_MSG; } if ((n = fprintf(f, "no %s\n", msg)) < 0) { err = got_ferror(f, GOT_ERR_IO); goto done; } err = add_line_metadata(lines, nlines, n, GOT_DIFF_LINE_META); if (err != NULL) goto done; if (s->parent_view && s->parent_view->type == TOG_VIEW_LOG) evict_worktree_entry( &s->parent_view->state.log.thread_args, victim); err = got_error(GOT_ERR_DIFF_NOCHANGES); } done: free(cwd); free(id_str); got_pathlist_free(&pathlist, GOT_PATHLIST_FREE_NONE); if (worktree != NULL) { if ((close_err = got_worktree_close(worktree)) != NULL) { if (err == NULL || err->code == GOT_ERR_DIFF_NOCHANGES) err = close_err; } } return err; } static const struct got_error * tog_diff_objects(struct tog_diff_view_state *s, FILE *f, struct got_diff_line **lines, size_t *nlines, struct got_diffstat_cb_arg *dsa) { const struct got_error *err; int obj_type; if (s->id1) err = got_object_get_type(&obj_type, s->repo, s->id1); else err = got_object_get_type(&obj_type, s->repo, s->id2); if (err != NULL) return err; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = got_diff_objects_as_blobs(lines, nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL, NULL, tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, dsa, s->repo, f); if (err != NULL) return err; break; case GOT_OBJ_TYPE_TREE: err = got_diff_objects_as_trees(lines, nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, s->paths, "", "", tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, dsa, s->repo, f); if (err != NULL) return err; break; case GOT_OBJ_TYPE_COMMIT: { const struct got_object_id_queue *parent_ids; struct got_commit_object *commit2; struct got_object_qid *pid; struct got_reflist_head *refs; err = got_diff_objects_as_commits(lines, nlines, s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, s->paths, tog_diff_algo, s->diff_context, s->ignore_whitespace, s->force_text_diff, dsa, s->repo, f); if (err != NULL) return err; refs = got_reflist_object_id_map_lookup(tog_refs_idmap, s->id2); /* Show commit info if we're diffing to a parent/root commit. */ if (s->id1 == NULL) return write_commit_info(&s->lines, &s->nlines, s->id2, refs, s->repo, s->ignore_whitespace, s->force_text_diff, dsa, s->f); err = got_object_open_as_commit(&commit2, s->repo, s->id2); if (err != NULL) return err; parent_ids = got_object_commit_get_parent_ids(commit2); STAILQ_FOREACH(pid, parent_ids, entry) { if (got_object_id_cmp(s->id1, &pid->id) == 0) { err = write_commit_info(&s->lines, &s->nlines, s->id2, refs, s->repo, s->ignore_whitespace, s->force_text_diff, dsa, s->f); break; } } if (commit2 != NULL) got_object_commit_close(commit2); if (err != NULL) return err; break; } default: return got_error(GOT_ERR_OBJ_TYPE); } return NULL; } static const struct got_error * create_diff(struct tog_diff_view_state *s) { const struct got_error *err = NULL; FILE *tmp_diff_file = NULL; struct got_diff_line *lines = NULL; struct got_pathlist_head changed_paths; struct got_diffstat_cb_arg dsa; size_t nlines = 0; RB_INIT(&changed_paths); memset(&dsa, 0, sizeof(dsa)); dsa.paths = &changed_paths; dsa.diff_algo = tog_diff_algo; dsa.force_text = s->force_text_diff; dsa.ignore_ws = s->ignore_whitespace; free(s->lines); s->lines = malloc(sizeof(*s->lines)); if (s->lines == NULL) return got_error_from_errno("malloc"); s->nlines = 0; if (s->f && fclose(s->f) == EOF) { s->f = NULL; return got_error_from_errno("fclose"); } s->f = got_opentemp(); if (s->f == NULL) return got_error_from_errno("got_opentemp"); /* * The diffstat requires the diff to be built first, but we want the * diffstat to precede the diff when displayed. Build the diff first * in the temporary file and write the diffstat and/or commit info to * the persistent file (s->f) from which views are drawn, then append * the diff from the temp file to the diffstat/commit info in s->f. */ tmp_diff_file = got_opentemp(); if (tmp_diff_file == NULL) return got_error_from_errno("got_opentemp"); lines = malloc(sizeof(*lines)); if (lines == NULL) { err = got_error_from_errno("malloc"); goto done; } if (s->parent_view != NULL && s->parent_view->type == TOG_VIEW_LOG) { struct tog_log_view_state *ls = &s->parent_view->state.log; struct commit_queue_entry *cqe = ls->selected_entry; if (cqe->worktree_entry != 0) { if (cqe->worktree_entry == TOG_WORKTREE_CHANGES_STAGED) s->diff_staged = 1; s->diff_worktree = 1; } } if (s->diff_worktree) err = tog_diff_worktree(s, tmp_diff_file, &lines, &nlines, &dsa); else err = tog_diff_objects(s, tmp_diff_file, &lines, &nlines, &dsa); if (err != NULL) { if (err->code != GOT_ERR_DIFF_NOCHANGES) goto done; } else { err = write_diffstat(s->f, &s->lines, &s->nlines, &dsa); if (err != NULL) goto done; } err = cat_diff(s->f, tmp_diff_file, &s->lines, &s->nlines, lines, nlines); done: free(lines); got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL); if (s->f && fflush(s->f) != 0 && err == NULL) err = got_error_from_errno("fflush"); if (tmp_diff_file && fclose(tmp_diff_file) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static void diff_view_indicate_progress(struct tog_view *view) { mvwaddstr(view->window, 0, 0, "diffing..."); update_panels(); doupdate(); } static const struct got_error * search_start_diff_view(struct tog_view *view) { struct tog_diff_view_state *s = &view->state.diff; s->matched_line = 0; return NULL; } static void search_setup_diff_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_diff_view_state *s = &view->state.diff; *f = s->f; *nlines = s->nlines; *line_offsets = NULL; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * search_next_view_match(struct tog_view *view) { const struct got_error *err = NULL; FILE *f; int lineno; char *line = NULL; size_t linesize = 0; ssize_t linelen; off_t *line_offsets; size_t nlines = 0; int *first, *last, *match, *selected; if (!view->search_setup) return got_error_msg(GOT_ERR_NOT_IMPL, "view search not supported"); view->search_setup(view, &f, &line_offsets, &nlines, &first, &last, &match, &selected); if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (*match) { if (view->searching == TOG_SEARCH_FORWARD) lineno = *first + 1; else lineno = *first - 1; } else lineno = *first - 1 + *selected; while (1) { off_t offset; if (lineno <= 0 || lineno > nlines) { if (*match == 0) { view->search_next_done = TOG_SEARCH_HAVE_MORE; break; } if (view->searching == TOG_SEARCH_FORWARD) lineno = 1; else lineno = nlines; } offset = view->type == TOG_VIEW_DIFF ? view->state.diff.lines[lineno - 1].offset : line_offsets[lineno - 1]; if (fseeko(f, offset, SEEK_SET) != 0) { free(line); return got_error_from_errno("fseeko"); } linelen = getline(&line, &linesize, f); if (linelen != -1) { char *exstr; err = expand_tab(&exstr, line); if (err) break; if (match_line(exstr, &view->regex, 1, &view->regmatch)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; *match = lineno; free(exstr); break; } free(exstr); } if (view->searching == TOG_SEARCH_FORWARD) lineno++; else lineno--; } free(line); if (*match) { *first = *match; *selected = 1; } return err; } static const struct got_error * close_diff_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_diff_view_state *s = &view->state.diff; free(s->id1); s->id1 = NULL; free(s->id2); s->id2 = NULL; free(s->action); s->action = NULL; if (s->f && fclose(s->f) == EOF) err = got_error_from_errno("fclose"); s->f = NULL; if (s->f1 && fclose(s->f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); s->f1 = NULL; if (s->f2 && fclose(s->f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); s->f2 = NULL; if (s->fd1 != -1 && close(s->fd1) == -1 && err == NULL) err = got_error_from_errno("close"); s->fd1 = -1; if (s->fd2 != -1 && close(s->fd2) == -1 && err == NULL) err = got_error_from_errno("close"); s->fd2 = -1; free(s->lines); s->lines = NULL; s->nlines = 0; return err; } static const struct got_error * open_diff_view(struct tog_view *view, struct got_object_id *id1, struct got_object_id *id2, const char *label1, const char *label2, int diff_context, int ignore_whitespace, int force_text_diff, int diff_staged, int diff_worktree, const char *worktree_root, struct tog_view *parent_view, struct got_repository *repo, struct got_pathlist_head *paths) { const struct got_error *err; struct tog_diff_view_state *s = &view->state.diff; memset(s, 0, sizeof(*s)); s->fd1 = -1; s->fd2 = -1; if (id1 != NULL && id2 != NULL) { int type1, type2; err = got_object_get_type(&type1, repo, id1); if (err) goto done; err = got_object_get_type(&type2, repo, id2); if (err) goto done; if (type1 != type2) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } } if (diff_worktree == 0) { if (id1) { s->id1 = got_object_id_dup(id1); if (s->id1 == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } else s->id1 = NULL; s->id2 = got_object_id_dup(id2); if (s->id2 == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } } s->f1 = got_opentemp(); if (s->f1 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } s->f2 = got_opentemp(); if (s->f2 == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } s->fd1 = got_opentempfd(); if (s->fd1 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } s->fd2 = got_opentempfd(); if (s->fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; s->label1 = label1; s->label2 = label2; s->diff_context = diff_context; s->ignore_whitespace = ignore_whitespace; s->force_text_diff = force_text_diff; s->diff_worktree = diff_worktree; s->diff_staged = diff_staged; s->parent_view = parent_view; s->paths = paths; s->repo = repo; s->worktree_root = worktree_root; if (has_colors() && getenv("TOG_COLORS") != NULL && !using_mock_io) { int rc; rc = init_pair(GOT_DIFF_LINE_MINUS, get_color_value("TOG_COLOR_DIFF_MINUS"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_PLUS, get_color_value("TOG_COLOR_DIFF_PLUS"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_HUNK, get_color_value("TOG_COLOR_DIFF_CHUNK_HEADER"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_META, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_CHANGES, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_BLOB_MIN, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_BLOB_PLUS, get_color_value("TOG_COLOR_DIFF_META"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_AUTHOR, get_color_value("TOG_COLOR_AUTHOR"), -1); if (rc != ERR) rc = init_pair(GOT_DIFF_LINE_DATE, get_color_value("TOG_COLOR_DATE"), -1); if (rc == ERR) { err = got_error(GOT_ERR_RANGE); goto done; } } if (parent_view && parent_view->type == TOG_VIEW_LOG && view_is_splitscreen(view)) { err = show_log_view(parent_view); /* draw border */ if (err != NULL) goto done; } diff_view_indicate_progress(view); err = create_diff(s); view->show = show_diff_view; view->input = input_diff_view; view->reset = reset_diff_view; view->close = close_diff_view; view->search_start = search_start_diff_view; view->search_setup = search_setup_diff_view; view->search_next = search_next_view_match; done: if (err) { if (view->close == NULL) close_diff_view(view); view_close(view); } return err; } static const struct got_error * show_diff_view(struct tog_view *view) { const struct got_error *err; struct tog_diff_view_state *s = &view->state.diff; char *header; if (s->diff_worktree) { if (asprintf(&header, "diff %s%s", s->diff_staged ? "-s " : "", s->worktree_root) == -1) return got_error_from_errno("asprintf"); } else { char *id_str2, *id_str1 = NULL; const char *label1, *label2; if (s->id1) { err = got_object_id_str(&id_str1, s->id1); if (err) return err; label1 = s->label1 ? s->label1 : id_str1; } else label1 = "/dev/null"; err = got_object_id_str(&id_str2, s->id2); if (err) return err; label2 = s->label2 ? s->label2 : id_str2; if (asprintf(&header, "diff %s %s", label1, label2) == -1) { err = got_error_from_errno("asprintf"); free(id_str1); free(id_str2); return err; } free(id_str1); free(id_str2); } err = draw_file(view, header); free(header); return err; } static const struct got_error * diff_write_patch(struct tog_view *view) { const struct got_error *err; struct tog_diff_view_state *s = &view->state.diff; struct got_object_id *id2 = s->id2; FILE *f = NULL; char buf[BUFSIZ], pathbase[PATH_MAX]; char *idstr1, *idstr2 = NULL, *path = NULL; char *repo_name = NULL; size_t r; off_t pos; int rc; if (s->action != NULL) { free(s->action); s->action = NULL; } pos = ftello(s->f); if (pos == -1) return got_error_from_errno("ftello"); if (fseeko(s->f, 0L, SEEK_SET) == -1) return got_error_from_errno("fseeko"); if (s->id1 != NULL) { err = got_object_id_str(&idstr1, s->id1); if (err != NULL) return err; } if (id2 == NULL) { if (s->diff_worktree == 0 || tog_base_commit.id == NULL) { /* illegal state that should not be possible */ err = got_error(GOT_ERR_NOT_WORKTREE); goto done; } id2 = tog_base_commit.id; } err = got_object_id_str(&idstr2, id2); if (err != NULL) goto done; err = got_path_basename(&repo_name, got_repo_get_path(s->repo)); if (err) goto done; rc = snprintf(pathbase, sizeof(pathbase), "%s/tog-%s-%.8s-%.8s", GOT_TMPDIR_STR, repo_name, idstr1 != NULL ? idstr1 : "empty", idstr2); if (rc < 0 || (size_t)rc >= sizeof(pathbase)) { err = got_error(rc < 0 ? GOT_ERR_IO : GOT_ERR_NO_SPACE); goto done; } err = got_opentemp_named(&path, &f, pathbase, ".diff"); if (err != NULL) goto done; while ((r = fread(buf, 1, sizeof(buf), s->f)) > 0) { if (fwrite(buf, 1, r, f) != r) { err = got_ferror(f, GOT_ERR_IO); goto done; } } if (ferror(s->f)) { err = got_error_from_errno("fread"); goto done; } if (fseeko(s->f, pos, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } if (fflush(f) == EOF) { err = got_error_from_errno2("fflush", path); goto done; } if (asprintf(&s->action, "patch file written to %s", path) == -1) { err = got_error_from_errno("asprintf"); goto done; } view->action = s->action; done: if (f != NULL && fclose(f) == EOF && err == NULL) err = got_error_from_errno2("fclose", path); free(path); free(idstr1); free(idstr2); free(repo_name); return err; } static const struct got_error * set_selected_commit(struct tog_diff_view_state *s, struct commit_queue_entry *entry) { const struct got_error *err; const struct got_object_id_queue *parent_ids; struct got_commit_object *selected_commit; struct got_object_qid *pid; free(s->id1); s->id1 = NULL; free(s->id2); s->id2 = NULL; if (entry->worktree_entry == 0) { s->id2 = got_object_id_dup(entry->id); if (s->id2 == NULL) return got_error_from_errno("got_object_id_dup"); err = got_object_open_as_commit(&selected_commit, s->repo, entry->id); if (err) return err; parent_ids = got_object_commit_get_parent_ids(selected_commit); pid = STAILQ_FIRST(parent_ids); s->id1 = pid ? got_object_id_dup(&pid->id) : NULL; got_object_commit_close(selected_commit); } return NULL; } static const struct got_error * reset_diff_view(struct tog_view *view) { struct tog_diff_view_state *s = &view->state.diff; view->count = 0; wclear(view->window); s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; if (s->action != NULL) { free(s->action); s->action = NULL; } diff_view_indicate_progress(view); return create_diff(s); } static void diff_prev_index(struct tog_diff_view_state *s, enum got_diff_line_type type) { int start, i; i = start = s->first_displayed_line - 1; while (s->lines[i].type != type) { if (i == 0) i = s->nlines - 1; if (--i == start) return; /* do nothing, requested type not in file */ } s->selected_line = 1; s->first_displayed_line = i; } static void diff_next_index(struct tog_diff_view_state *s, enum got_diff_line_type type) { int start, i; i = start = s->first_displayed_line + 1; while (s->lines[i].type != type) { if (i == s->nlines - 1) i = 0; if (++i == start) return; /* do nothing, requested type not in file */ } s->selected_line = 1; s->first_displayed_line = i; } static struct got_object_id *get_selected_commit_id(struct tog_blame_line *, int, int, int); static struct got_object_id *get_annotation_for_line(struct tog_blame_line *, int, int); static const struct got_error * input_diff_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_diff_view_state *s = &view->state.diff; struct tog_log_view_state *ls; struct commit_queue_entry *old_selected_entry; char *line = NULL; size_t linesize = 0; ssize_t linelen; int i, nscroll = view->nlines - 1, up = 0; s->lineno = s->first_displayed_line - 1 + s->selected_line; if (s->action != NULL && ch != ERR) { free(s->action); s->action = NULL; view->action = NULL; } switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'a': case 'w': if (ch == 'a') { s->force_text_diff = !s->force_text_diff; view->action = s->force_text_diff ? "force ASCII text enabled" : "force ASCII text disabled"; } else if (ch == 'w') { s->ignore_whitespace = !s->ignore_whitespace; view->action = s->ignore_whitespace ? "ignore whitespace enabled" : "ignore whitespace disabled"; } err = reset_diff_view(view); break; case 'g': case KEY_HOME: s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: view->count = 0; if (s->eof) break; s->first_displayed_line = (s->nlines - view->nlines) + 2; s->eof = 1; break; case 'k': case KEY_UP: case CTRL('p'): if (s->first_displayed_line > 1) s->first_displayed_line--; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { view->count = 0; break; } i = 0; while (i++ < nscroll && s->first_displayed_line > 1) s->first_displayed_line--; break; case 'j': case KEY_DOWN: case CTRL('n'): if (!s->eof) s->first_displayed_line++; else view->count = 0; break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->eof) { view->count = 0; break; } i = 0; while (!s->eof && i++ < nscroll) { linelen = getline(&line, &linesize, s->f); s->first_displayed_line++; if (linelen == -1) { if (feof(s->f)) { s->eof = 1; } else err = got_ferror(s->f, GOT_ERR_IO); break; } } free(line); break; case '(': diff_prev_index(s, GOT_DIFF_LINE_BLOB_MIN); break; case ')': diff_next_index(s, GOT_DIFF_LINE_BLOB_MIN); break; case '{': diff_prev_index(s, GOT_DIFF_LINE_HUNK); break; case '}': diff_next_index(s, GOT_DIFF_LINE_HUNK); break; case '[': if (s->diff_context > 0) { s->diff_context--; s->matched_line = 0; diff_view_indicate_progress(view); err = create_diff(s); if (s->first_displayed_line + view->nlines - 1 > s->nlines) { s->first_displayed_line = 1; s->last_displayed_line = view->nlines; } } else view->count = 0; break; case ']': if (s->diff_context < GOT_DIFF_MAX_CONTEXT) { s->diff_context++; s->matched_line = 0; diff_view_indicate_progress(view); err = create_diff(s); } else view->count = 0; break; case '<': case ',': case 'K': up = 1; /* FALL THROUGH */ case '>': case '.': case 'J': if (s->parent_view == NULL) { view->count = 0; break; } s->parent_view->count = view->count; if (s->parent_view->type == TOG_VIEW_LOG) { ls = &s->parent_view->state.log; old_selected_entry = ls->selected_entry; err = input_log_view(NULL, s->parent_view, up ? KEY_UP : KEY_DOWN); if (err) break; view->count = s->parent_view->count; if (old_selected_entry == ls->selected_entry) break; log_mark_clear(ls); err = set_selected_commit(s, ls->selected_entry); if (err) break; if (s->worktree_root == NULL) s->worktree_root = ls->thread_args.wctx.wt_root; } else if (s->parent_view->type == TOG_VIEW_BLAME) { struct tog_blame_view_state *bs; struct got_object_id *id, *prev_id; bs = &s->parent_view->state.blame; prev_id = get_annotation_for_line(bs->blame.lines, bs->blame.nlines, bs->last_diffed_line); err = input_blame_view(&view, s->parent_view, up ? KEY_UP : KEY_DOWN); if (err) break; view->count = s->parent_view->count; if (prev_id == NULL) break; id = get_selected_commit_id(bs->blame.lines, bs->blame.nlines, bs->first_displayed_line, bs->selected_line); if (id == NULL) break; if (!got_object_id_cmp(prev_id, id)) break; err = input_blame_view(&view, s->parent_view, KEY_ENTER); if (err) break; } s->diff_staged = 0; s->diff_worktree = 0; s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; view->x = 0; diff_view_indicate_progress(view); err = create_diff(s); break; case 'p': view->count = 0; err = diff_write_patch(view); break; default: view->count = 0; break; } return err; } static const struct got_error * get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc, char *argv[], struct got_worktree *worktree) { const struct got_error *err = NULL; char *path; struct got_pathlist_entry *new; int i; if (argc == 0) { path = strdup(""); if (path == NULL) return got_error_from_errno("strdup"); return got_pathlist_insert(NULL, paths, path, NULL); } for (i = 0; i < argc; i++) { err = got_worktree_resolve_path(&path, worktree, argv[i]); if (err) break; err = got_pathlist_insert(&new, paths, path, NULL); if (err != NULL || new == NULL) { free(path); if (err != NULL) break; } } return err; } static const struct got_error * cmd_diff(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_pathlist_head paths; struct got_object_id *ids[2] = { NULL, NULL }; const char *commit_args[2] = { NULL, NULL }; char *labels[2] = { NULL, NULL }; char *repo_path = NULL, *worktree_path = NULL, *cwd = NULL; int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY; int i, ncommit_args = 0, diff_context = 3, ignore_whitespace = 0; int ch, diff_staged = 0, diff_worktree = 0, force_text_diff = 0; const char *errstr; struct tog_view *view; int *pack_fds = NULL; RB_INIT(&paths); while ((ch = getopt(argc, argv, "aC:c:r:sw")) != -1) { switch (ch) { case 'a': force_text_diff = 1; break; case 'C': diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT, &errstr); if (errstr != NULL) errx(1, "number of context lines is %s: %s", errstr, errstr); break; case 'c': if (ncommit_args >= 2) errx(1, "too many -c options used"); commit_args[ncommit_args++] = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); got_path_strip_trailing_slashes(repo_path); break; case 's': diff_staged = 1; break; case 'w': ignore_whitespace = 1; break; default: usage_diff(); /* NOTREACHED */ } } argc -= optind; argv += optind; error = got_repo_pack_fds_open(&pack_fds); if (error) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error) goto done; if (diff_staged && (worktree == NULL || ncommit_args > 0)) { error = got_error_msg(GOT_ERR_BAD_OPTION, "-s can only be used when diffing a work tree"); goto done; } init_curses(); error = apply_unveil(got_repo_get_path(repo), worktree != NULL ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; if (argc == 2 || ncommit_args > 0) { int obj_type = (ncommit_args > 0 ? GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY); error = tog_load_refs(repo, 0); if (error != NULL) goto done; for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); ++i) { const char *arg; char *keyword_idstr = NULL; if (ncommit_args > 0) arg = commit_args[i]; else arg = argv[i]; error = got_keyword_to_idstr(&keyword_idstr, arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) arg = keyword_idstr; error = got_repo_match_object_id(&ids[i], &labels[i], arg, obj_type, &tog_refs, repo); free(keyword_idstr); if (error != NULL) { if (error->code != GOT_ERR_NOT_REF && error->code != GOT_ERR_NO_OBJ) goto done; if (ncommit_args > 0) goto done; error = NULL; break; } } } if (diff_staged && ids[0] != NULL) { error = got_error_msg(GOT_ERR_BAD_OPTION, "-s can only be used when diffing a work tree"); goto done; } if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) { if (worktree == NULL) { if (argc == 2 && ids[0] == NULL) { error = got_error_path(argv[0], GOT_ERR_NO_OBJ); goto done; } else if (argc == 2 && ids[1] == NULL) { error = got_error_path(argv[1], GOT_ERR_NO_OBJ); goto done; } else if (argc > 0) { error = got_error_fmt(GOT_ERR_NOT_WORKTREE, "%s", "specified paths cannot be resolved"); goto done; } else { error = got_error(GOT_ERR_NOT_WORKTREE); goto done; } } error = get_worktree_paths_from_argv(&paths, argc, argv, worktree); if (error != NULL) goto done; worktree_path = strdup(got_worktree_get_root_path(worktree)); if (worktree_path == NULL) { error = got_error_from_errno("strdup"); goto done; } diff_worktree = 1; } if (ncommit_args == 1) { /* diff commit against its first parent */ struct got_commit_object *commit; error = got_object_open_as_commit(&commit, repo, ids[0]); if (error != NULL) goto done; labels[1] = labels[0]; ids[1] = ids[0]; if (got_object_commit_get_nparents(commit) > 0) { const struct got_object_id_queue *pids; struct got_object_qid *pid; pids = got_object_commit_get_parent_ids(commit); pid = STAILQ_FIRST(pids); ids[0] = got_object_id_dup(&pid->id); if (ids[0] == NULL) { error = got_error_from_errno( "got_object_id_dup"); got_object_commit_close(commit); goto done; } error = got_object_id_str(&labels[0], ids[0]); if (error != NULL) { got_object_commit_close(commit); goto done; } } else { ids[0] = NULL; labels[0] = strdup("/dev/null"); if (labels[0] == NULL) { error = got_error_from_errno("strdup"); got_object_commit_close(commit); goto done; } } got_object_commit_close(commit); } if (ncommit_args == 0 && argc > 2) { error = got_error_msg(GOT_ERR_BAD_PATH, "path arguments cannot be used when diffing two objects"); goto done; } if (ids[0]) { error = got_object_get_type(&type1, repo, ids[0]); if (error != NULL) goto done; } if (diff_worktree == 0) { error = got_object_get_type(&type2, repo, ids[1]); if (error != NULL) goto done; if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) { error = got_error_msg(GOT_ERR_OBJ_TYPE, "path arguments cannot be used when diffing blobs"); goto done; } } for (i = 0; ncommit_args > 0 && i < argc; i++) { char *in_repo_path; struct got_pathlist_entry *new; if (worktree) { const char *prefix; char *p; error = got_worktree_resolve_path(&p, worktree, argv[i]); if (error != NULL) goto done; prefix = got_worktree_get_path_prefix(worktree); while (prefix[0] == '/') prefix++; if (asprintf(&in_repo_path, "%s%s%s", prefix, (p[0] != '\0' && prefix[0] != '\0') ? "/" : "", p) == -1) { error = got_error_from_errno("asprintf"); free(p); goto done; } free(p); } else { char *mapped_path, *s; error = got_repo_map_path(&mapped_path, repo, argv[i]); if (error != NULL) goto done; s = mapped_path; while (s[0] == '/') s++; in_repo_path = strdup(s); if (in_repo_path == NULL) { error = got_error_from_errno("asprintf"); free(mapped_path); goto done; } free(mapped_path); } error = got_pathlist_insert(&new, &paths, in_repo_path, NULL); if (error != NULL || new == NULL) free(in_repo_path); if (error != NULL) goto done; } view = view_open(0, 0, 0, 0, TOG_VIEW_DIFF); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = open_diff_view(view, ids[0], ids[1], labels[0], labels[1], diff_context, ignore_whitespace, force_text_diff, diff_staged, diff_worktree, worktree_path, NULL, repo, &paths); if (error) goto done; error = view_loop(view); done: got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH); free(tog_base_commit.id); free(worktree_path); free(repo_path); free(labels[0]); free(labels[1]); free(ids[0]); free(ids[1]); free(cwd); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } __dead static void usage_blame(void) { endwin(); fprintf(stderr, "usage: %s blame [-c commit] [-r repository-path] path\n", getprogname()); exit(1); } struct tog_blame_line { int annotated; struct got_object_id *id; }; static const struct got_error * draw_blame(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; struct tog_blame *blame = &s->blame; regmatch_t *regmatch = &view->regmatch; const struct got_error *err; int lineno = 0, nprinted = 0; char *line = NULL; size_t linesize = 0; ssize_t linelen; wchar_t *wline; int width; struct tog_blame_line *blame_line; struct got_object_id *prev_id = NULL; char *id_str; struct tog_color *tc; err = got_object_id_str(&id_str, &s->blamed_commit->id); if (err) return err; rewind(blame->f); werase(view->window); if (asprintf(&line, "commit %s", id_str) == -1) { err = got_error_from_errno("asprintf"); free(id_str); return err; } err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); line = NULL; if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wline); while (width++ < view->ncols) waddch(view->window, ' '); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); wline = NULL; if (view->gline > blame->nlines) view->gline = blame->nlines; if (tog_io.wait_for_ui) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_wait(&bta->blame_complete, &tog_mutex); if (rc) return got_error_set_errno(rc, "pthread_cond_wait"); tog_io.wait_for_ui = 0; } if (asprintf(&line, "[%d/%d] %s%s", view->gline ? view->gline : s->first_displayed_line - 1 + s->selected_line, blame->nlines, s->blame_complete ? "" : "annotating... ", s->path) == -1) { free(id_str); return got_error_from_errno("asprintf"); } free(id_str); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); free(line); line = NULL; if (err) return err; waddwstr(view->window, wline); free(wline); wline = NULL; if (width < view->ncols - 1) waddch(view->window, '\n'); s->eof = 0; view->maxx = 0; while (nprinted < view->nlines - 2) { linelen = getline(&line, &linesize, blame->f); if (linelen == -1) { if (feof(blame->f)) { s->eof = 1; break; } free(line); return got_ferror(blame->f, GOT_ERR_IO); } if (++lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &lineno, &nprinted)) continue; /* Set view->maxx based on full line length. */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 9, 1); if (err) { free(line); return err; } free(wline); wline = NULL; view->maxx = MAX(view->maxx, width); if (nprinted == s->selected_line - 1) wstandout(view->window); if (blame->nlines > 0) { blame_line = &blame->lines[lineno - 1]; if (blame_line->annotated && prev_id && got_object_id_cmp(prev_id, blame_line->id) == 0 && !(nprinted == s->selected_line - 1)) { waddstr(view->window, " "); } else if (blame_line->annotated) { char *id_str; err = got_object_id_str(&id_str, blame_line->id); if (err) { free(line); return err; } tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); wprintw(view->window, "%.8s", id_str); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); free(id_str); prev_id = blame_line->id; } else { waddstr(view->window, "........"); prev_id = NULL; } } else { waddstr(view->window, "........"); prev_id = NULL; } if (nprinted == s->selected_line - 1) wstandend(view->window); waddstr(view->window, " "); if (view->ncols <= 9) { width = 9; } else if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols - 9, 9, view->window, view->x, regmatch); if (err) { free(line); return err; } width += 9; } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols - 9, 9, 1); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); width += 9; free(wline); wline = NULL; } if (width <= view->ncols - 1) waddch(view->window, '\n'); if (++nprinted == 1) s->first_displayed_line = lineno; } free(line); s->last_displayed_line = lineno; view_border(view); return NULL; } static const struct got_error * blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct tog_blame_cb_args *a = arg; struct tog_blame_line *line; int errcode; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (*a->quit) { /* user has quit the blame view */ err = got_error(GOT_ERR_ITER_COMPLETED); goto done; } if (lineno == -1) goto done; /* no change in this commit */ line = &a->lines[lineno - 1]; if (line->annotated) goto done; line->id = got_object_id_dup(id); if (line->id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } line->annotated = 1; done: errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); return err; } static void * blame_thread(void *arg) { const struct got_error *err, *close_err; struct tog_blame_thread_args *ta = arg; struct tog_blame_cb_args *a = ta->cb_args; int errcode, fd1 = -1, fd2 = -1; FILE *f1 = NULL, *f2 = NULL; fd1 = got_opentempfd(); if (fd1 == -1) return (void *)got_error_from_errno("got_opentempfd"); fd2 = got_opentempfd(); if (fd2 == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } f1 = got_opentemp(); if (f1 == NULL) { err = (void *)got_error_from_errno("got_opentemp"); goto done; } f2 = got_opentemp(); if (f2 == NULL) { err = (void *)got_error_from_errno("got_opentemp"); goto done; } err = block_signals_used_by_main_thread(); if (err) goto done; err = got_blame(ta->path, a->commit_id, ta->repo, tog_diff_algo, blame_cb, ta->cb_args, ta->cancel_cb, ta->cancel_arg, fd1, fd2, f1, f2); if (err && err->code == GOT_ERR_CANCELLED) err = NULL; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) { err = got_error_set_errno(errcode, "pthread_mutex_lock"); goto done; } close_err = got_repo_close(ta->repo); if (err == NULL) err = close_err; ta->repo = NULL; *ta->complete = 1; if (tog_io.wait_for_ui) { errcode = pthread_cond_signal(&ta->blame_complete); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_cond_signal"); } errcode = pthread_mutex_unlock(&tog_mutex); if (errcode && err == NULL) err = got_error_set_errno(errcode, "pthread_mutex_unlock"); done: if (fd1 != -1 && close(fd1) == -1 && err == NULL) err = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && err == NULL) err = got_error_from_errno("close"); if (f1 && fclose(f1) == EOF && err == NULL) err = got_error_from_errno("fclose"); if (f2 && fclose(f2) == EOF && err == NULL) err = got_error_from_errno("fclose"); return (void *)err; } static struct got_object_id * get_selected_commit_id(struct tog_blame_line *lines, int nlines, int first_displayed_line, int selected_line) { struct tog_blame_line *line; if (nlines <= 0) return NULL; line = &lines[first_displayed_line - 1 + selected_line - 1]; if (!line->annotated) return NULL; return line->id; } static struct got_object_id * get_annotation_for_line(struct tog_blame_line *lines, int nlines, int lineno) { struct tog_blame_line *line; if (nlines <= 0 || lineno >= nlines) return NULL; line = &lines[lineno - 1]; if (!line->annotated) return NULL; return line->id; } static const struct got_error * stop_blame(struct tog_blame *blame) { const struct got_error *err = NULL; int i; if (blame->thread) { int errcode; errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); errcode = pthread_join(blame->thread, (void **)&err); if (errcode) return got_error_set_errno(errcode, "pthread_join"); errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (err && err->code == GOT_ERR_ITER_COMPLETED) err = NULL; blame->thread = 0; //NULL; } if (blame->thread_args.repo) { const struct got_error *close_err; close_err = got_repo_close(blame->thread_args.repo); if (err == NULL) err = close_err; blame->thread_args.repo = NULL; } if (blame->f) { if (fclose(blame->f) == EOF && err == NULL) err = got_error_from_errno("fclose"); blame->f = NULL; } if (blame->lines) { for (i = 0; i < blame->nlines; i++) free(blame->lines[i].id); free(blame->lines); blame->lines = NULL; } free(blame->cb_args.commit_id); blame->cb_args.commit_id = NULL; if (blame->pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(blame->pack_fds); if (err == NULL) err = pack_err; blame->pack_fds = NULL; } free(blame->line_offsets); blame->line_offsets = NULL; return err; } static const struct got_error * cancel_blame_view(void *arg) { const struct got_error *err = NULL; int *done = arg; int errcode; errcode = pthread_mutex_lock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_lock"); if (*done) err = got_error(GOT_ERR_CANCELLED); errcode = pthread_mutex_unlock(&tog_mutex); if (errcode) return got_error_set_errno(errcode, "pthread_mutex_unlock"); return err; } static const struct got_error * run_blame(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; struct tog_blame *blame = &s->blame; const struct got_error *err = NULL; struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL; struct got_repository *thread_repo = NULL; struct got_object_id *obj_id = NULL; int obj_type, fd = -1; int *pack_fds = NULL; err = got_object_open_as_commit(&commit, s->repo, &s->blamed_commit->id); if (err) return err; fd = got_opentempfd(); if (fd == -1) { err = got_error_from_errno("got_opentempfd"); goto done; } err = got_object_id_by_path(&obj_id, s->repo, commit, s->path); if (err) goto done; err = got_object_get_type(&obj_type, s->repo, obj_id); if (err) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { err = got_error(GOT_ERR_OBJ_TYPE); goto done; } err = got_object_open_as_blob(&blob, s->repo, obj_id, 8192, fd); if (err) goto done; blame->f = got_opentemp(); if (blame->f == NULL) { err = got_error_from_errno("got_opentemp"); goto done; } err = got_object_blob_dump_to_file(&blame->filesize, &blame->nlines, &blame->line_offsets, blame->f, blob); if (err) goto done; if (blame->nlines == 0) { s->blame_complete = 1; goto done; } /* Don't include \n at EOF in the blame line count. */ if (blame->line_offsets[blame->nlines - 1] == blame->filesize) blame->nlines--; blame->lines = calloc(blame->nlines, sizeof(*blame->lines)); if (blame->lines == NULL) { err = got_error_from_errno("calloc"); goto done; } err = got_repo_pack_fds_open(&pack_fds); if (err) goto done; err = got_repo_open(&thread_repo, got_repo_get_path(s->repo), NULL, pack_fds); if (err) goto done; blame->pack_fds = pack_fds; blame->cb_args.view = view; blame->cb_args.lines = blame->lines; blame->cb_args.nlines = blame->nlines; blame->cb_args.commit_id = got_object_id_dup(&s->blamed_commit->id); if (blame->cb_args.commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } blame->cb_args.quit = &s->done; blame->thread_args.path = s->path; blame->thread_args.repo = thread_repo; blame->thread_args.cb_args = &blame->cb_args; blame->thread_args.complete = &s->blame_complete; blame->thread_args.cancel_cb = cancel_blame_view; blame->thread_args.cancel_arg = &s->done; s->blame_complete = 0; if (s->first_displayed_line + view->nlines - 1 > blame->nlines) { s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; } s->matched_line = 0; done: if (commit) got_object_commit_close(commit); if (fd != -1 && close(fd) == -1 && err == NULL) err = got_error_from_errno("close"); if (blob) got_object_blob_close(blob); free(obj_id); if (err) stop_blame(blame); return err; } static const struct got_error * open_blame_view(struct tog_view *view, char *path, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; STAILQ_INIT(&s->blamed_commits); s->path = strdup(path); if (s->path == NULL) return got_error_from_errno("strdup"); err = got_object_qid_alloc(&s->blamed_commit, commit_id); if (err) { free(s->path); return err; } STAILQ_INSERT_HEAD(&s->blamed_commits, s->blamed_commit, entry); s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; s->blame_complete = 0; s->repo = repo; s->commit_id = commit_id; memset(&s->blame, 0, sizeof(s->blame)); STAILQ_INIT(&s->colors); if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) return err; } view->show = show_blame_view; view->input = input_blame_view; view->reset = reset_blame_view; view->close = close_blame_view; view->search_start = search_start_blame_view; view->search_setup = search_setup_blame_view; view->search_next = search_next_view_match; if (using_mock_io) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_init(&bta->blame_complete, NULL); if (rc) return got_error_set_errno(rc, "pthread_cond_init"); } return run_blame(view); } static const struct got_error * close_blame_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; if (s->blame.thread) err = stop_blame(&s->blame); got_object_id_queue_free(&s->blamed_commits); if (using_mock_io) { struct tog_blame_thread_args *bta = &s->blame.thread_args; int rc; rc = pthread_cond_destroy(&bta->blame_complete); if (rc && err == NULL) err = got_error_set_errno(rc, "pthread_cond_destroy"); } free(s->path); free_colors(&s->colors); return err; } static const struct got_error * search_start_blame_view(struct tog_view *view) { struct tog_blame_view_state *s = &view->state.blame; s->matched_line = 0; return NULL; } static void search_setup_blame_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_blame_view_state *s = &view->state.blame; *f = s->blame.f; *nlines = s->blame.nlines; *line_offsets = s->blame.line_offsets; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * show_blame_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_blame_view_state *s = &view->state.blame; int errcode; if (s->blame.thread == 0 && !s->blame_complete) { errcode = pthread_create(&s->blame.thread, NULL, blame_thread, &s->blame.thread_args); if (errcode) return got_error_set_errno(errcode, "pthread_create"); if (!using_mock_io) halfdelay(1); /* fast refresh while annotating */ } if (s->blame_complete && !using_mock_io) halfdelay(10); /* disable fast refresh */ err = draw_blame(view); view_border(view); return err; } static const struct got_error * log_annotated_line(struct tog_view **new_view, int begin_y, int begin_x, struct got_repository *repo, struct got_object_id *id) { struct tog_view *log_view; const struct got_error *err = NULL; *new_view = NULL; log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) return got_error_from_errno("view_open"); err = open_log_view(log_view, id, repo, GOT_REF_HEAD, "", 0, NULL); if (err) view_close(log_view); else *new_view = log_view; return err; } static const struct got_error * input_blame_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL, *thread_err = NULL; struct tog_view *diff_view; struct tog_blame_view_state *s = &view->state.blame; int eos, nscroll, begin_y = 0, begin_x = 0; eos = nscroll = view->nlines - 2; if (view_is_hsplit_top(view)) --eos; /* border */ switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'q': s->done = 1; break; case 'g': case KEY_HOME: s->selected_line = 1; s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: if (s->blame.nlines < eos) { s->selected_line = s->blame.nlines; s->first_displayed_line = 1; } else { s->selected_line = eos; s->first_displayed_line = s->blame.nlines - (eos - 1); } view->count = 0; break; case 'k': case KEY_UP: case CTRL('p'): if (s->selected_line > 1) s->selected_line--; else if (s->selected_line == 1 && s->first_displayed_line > 1) s->first_displayed_line--; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { if (view->count > 1) nscroll += nscroll; s->selected_line = MAX(1, s->selected_line - nscroll); view->count = 0; break; } if (s->first_displayed_line > nscroll) s->first_displayed_line -= nscroll; else s->first_displayed_line = 1; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected_line < eos && s->first_displayed_line + s->selected_line <= s->blame.nlines) s->selected_line++; else if (s->first_displayed_line < s->blame.nlines - (eos - 1)) s->first_displayed_line++; else view->count = 0; break; case 'c': case 'p': { struct got_object_id *id = NULL; view->count = 0; id = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (id == NULL) break; if (ch == 'p') { struct got_commit_object *commit, *pcommit; struct got_object_qid *pid; struct got_object_id *blob_id = NULL; int obj_type; err = got_object_open_as_commit(&commit, s->repo, id); if (err) break; pid = STAILQ_FIRST( got_object_commit_get_parent_ids(commit)); if (pid == NULL) { got_object_commit_close(commit); break; } /* Check if path history ends here. */ err = got_object_open_as_commit(&pcommit, s->repo, &pid->id); if (err) break; err = got_object_id_by_path(&blob_id, s->repo, pcommit, s->path); got_object_commit_close(pcommit); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) err = NULL; got_object_commit_close(commit); break; } err = got_object_get_type(&obj_type, s->repo, blob_id); free(blob_id); /* Can't blame non-blob type objects. */ if (obj_type != GOT_OBJ_TYPE_BLOB) { got_object_commit_close(commit); break; } err = got_object_qid_alloc(&s->blamed_commit, &pid->id); got_object_commit_close(commit); } else { if (got_object_id_cmp(id, &s->blamed_commit->id) == 0) break; err = got_object_qid_alloc(&s->blamed_commit, id); } if (err) break; s->done = 1; thread_err = stop_blame(&s->blame); s->done = 0; if (thread_err) break; STAILQ_INSERT_HEAD(&s->blamed_commits, s->blamed_commit, entry); err = run_blame(view); if (err) break; break; } case 'C': { struct got_object_qid *first; view->count = 0; first = STAILQ_FIRST(&s->blamed_commits); if (!got_object_id_cmp(&first->id, s->commit_id)) break; s->done = 1; thread_err = stop_blame(&s->blame); s->done = 0; if (thread_err) break; STAILQ_REMOVE_HEAD(&s->blamed_commits, entry); got_object_qid_free(s->blamed_commit); s->blamed_commit = STAILQ_FIRST(&s->blamed_commits); err = run_blame(view); if (err) break; break; } case 'L': view->count = 0; s->id_to_log = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (s->id_to_log) err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case KEY_ENTER: case '\r': { struct got_object_id *id = NULL; struct got_object_qid *pid; struct got_commit_object *commit = NULL; view->count = 0; id = get_selected_commit_id(s->blame.lines, s->blame.nlines, s->first_displayed_line, s->selected_line); if (id == NULL) break; err = got_object_open_as_commit(&commit, s->repo, id); if (err) break; pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit)); if (*new_view) { /* traversed from diff view, release diff resources */ err = close_diff_view(*new_view); if (err) break; diff_view = *new_view; } else { if (view_is_parent_view(view)) view_get_split(view, &begin_y, &begin_x); diff_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_DIFF); if (diff_view == NULL) { got_object_commit_close(commit); err = got_error_from_errno("view_open"); break; } } err = open_diff_view(diff_view, pid ? &pid->id : NULL, id, NULL, NULL, 3, 0, 0, 0, 0, NULL, view, s->repo, NULL); got_object_commit_close(commit); if (err) break; s->last_diffed_line = s->first_displayed_line - 1 + s->selected_line; if (*new_view) break; /* still open from active diff view */ if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN) { err = view_init_hsplit(view, begin_y); if (err) break; } view->focussed = 0; diff_view->focussed = 1; diff_view->mode = view->mode; diff_view->nlines = view->lines - begin_y; if (view_is_parent_view(view)) { view_transfer_size(diff_view, view); err = view_close_child(view); if (err) break; err = view_set_child(view, diff_view); if (err) break; view->focus_child = 1; } else *new_view = diff_view; if (err) break; break; } case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->last_displayed_line >= s->blame.nlines && s->selected_line >= MIN(s->blame.nlines, view->nlines - 2)) { view->count = 0; break; } if (s->last_displayed_line >= s->blame.nlines && s->selected_line < view->nlines - 2) { s->selected_line += MIN(nscroll, s->last_displayed_line - s->first_displayed_line - s->selected_line + 1); } if (s->last_displayed_line + nscroll <= s->blame.nlines) s->first_displayed_line += nscroll; else s->first_displayed_line = s->blame.nlines - (view->nlines - 3); break; case KEY_RESIZE: if (s->selected_line > view->nlines - 2) { s->selected_line = MIN(s->blame.nlines, view->nlines - 2); } break; default: view->count = 0; break; } return thread_err ? thread_err : err; } static const struct got_error * reset_blame_view(struct tog_view *view) { const struct got_error *err; struct tog_blame_view_state *s = &view->state.blame; view->count = 0; s->done = 1; err = stop_blame(&s->blame); s->done = 0; if (err) return err; return run_blame(view); } static const struct got_error * cmd_blame(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *link_target = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; char *keyword_idstr = NULL, *commit_id_str = NULL; int ch; struct tog_view *view = NULL; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_str = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_blame(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) usage_blame(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; if (commit_id_str == NULL) { struct got_reference *head_ref; error = got_ref_open(&head_ref, repo, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0); if (error != NULL) goto done; error = got_ref_resolve(&commit_id, repo, head_ref); got_ref_close(head_ref); } else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_str, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_str = keyword_idstr; error = got_repo_match_object_id(&commit_id, NULL, commit_id_str, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); } if (error != NULL) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_resolve_symlinks(&link_target, in_repo_path, commit, repo); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_BLAME); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_blame_view(view, link_target ? link_target : in_repo_path, commit_id, repo); if (error != NULL) { if (view->close == NULL) close_blame_view(view); view_close(view); goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(repo_path); free(in_repo_path); free(link_target); free(cwd); free(commit_id); free(keyword_idstr); if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error * draw_tree_entries(struct tog_view *view, const char *parent_path) { struct tog_tree_view_state *s = &view->state.tree; const struct got_error *err = NULL; struct got_tree_entry *te; wchar_t *wline; char *index = NULL; struct tog_color *tc; int width, n, nentries, scrollx, i = 1; int limit = view->nlines; s->ndisplayed = 0; if (view_is_hsplit_top(view)) --limit; /* border */ werase(view->window); if (limit == 0) return NULL; err = format_line(&wline, &width, NULL, s->tree_label, 0, view->ncols, 0, 0); if (err) return err; if (view_needs_focus_indication(view)) wstandout(view->window); tc = get_color(&s->colors, TOG_COLOR_COMMIT); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, wline); free(wline); wline = NULL; while (width++ < view->ncols) waddch(view->window, ' '); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (view_needs_focus_indication(view)) wstandend(view->window); if (--limit <= 0) return NULL; i += s->selected; if (s->first_displayed_entry) { i += got_tree_entry_get_index(s->first_displayed_entry); if (s->tree != s->root) ++i; /* account for ".." entry */ } nentries = got_object_tree_get_nentries(s->tree); if (asprintf(&index, "[%d/%d] %s", i, nentries + (s->tree == s->root ? 0 : 1), parent_path) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, index, 0, view->ncols, 0, 0); free(index); if (err) return err; waddwstr(view->window, wline); free(wline); wline = NULL; if (width < view->ncols - 1) waddch(view->window, '\n'); if (--limit <= 0) return NULL; waddch(view->window, '\n'); if (--limit <= 0) return NULL; if (s->first_displayed_entry == NULL) { te = got_object_tree_get_first_entry(s->tree); if (s->selected == 0) { if (view->focussed) wstandout(view->window); s->selected_entry = NULL; } waddstr(view->window, " ..\n"); /* parent directory */ if (s->selected == 0 && view->focussed) wstandend(view->window); s->ndisplayed++; if (--limit <= 0) return NULL; n = 1; } else { n = 0; te = s->first_displayed_entry; } view->maxx = 0; for (i = got_tree_entry_get_index(te); i < nentries; i++) { char *line = NULL, *id_str = NULL, *link_target = NULL; const char *modestr = ""; mode_t mode; te = got_object_tree_get_entry(s->tree, i); mode = got_tree_entry_get_mode(te); if (s->show_ids) { err = got_object_id_str(&id_str, got_tree_entry_get_id(te)); if (err) return got_error_from_errno( "got_object_id_str"); } if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) { int i; err = got_tree_entry_get_symlink_target(&link_target, te, s->repo); if (err) { free(id_str); return err; } for (i = 0; link_target[i] != '\0'; i++) { if (!isprint((unsigned char)link_target[i])) link_target[i] = '?'; } modestr = "@"; } else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; if (asprintf(&line, "%s %s%s%s%s", id_str ? id_str : "", got_tree_entry_get_name(te), modestr, link_target ? " -> ": "", link_target ? link_target : "") == -1) { free(id_str); free(link_target); return got_error_from_errno("asprintf"); } free(id_str); free(link_target); /* use full line width to determine view->maxx */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, 0); if (err) { free(line); break; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; err = format_line(&wline, &width, &scrollx, line, view->x, view->ncols, 0, 0); if (err) { free(line); break; } if (n == s->selected) { if (view->focussed) wstandout(view->window); s->selected_entry = te; } tc = match_color(&s->colors, line); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, &wline[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (width < view->ncols) waddch(view->window, '\n'); if (n == s->selected && view->focussed) wstandend(view->window); free(line); free(wline); wline = NULL; n++; s->ndisplayed++; s->last_displayed_entry = te; if (--limit <= 0) break; } return err; } static void tree_scroll_up(struct tog_tree_view_state *s, int maxscroll) { struct got_tree_entry *te; int isroot = s->tree == s->root; int i = 0; if (s->first_displayed_entry == NULL) return; te = got_tree_entry_get_prev(s->tree, s->first_displayed_entry); while (i++ < maxscroll) { if (te == NULL) { if (!isroot) s->first_displayed_entry = NULL; break; } s->first_displayed_entry = te; te = got_tree_entry_get_prev(s->tree, te); } } static const struct got_error * tree_scroll_down(struct tog_view *view, int maxscroll) { struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *next, *last; int n = 0; if (s->first_displayed_entry) next = got_tree_entry_get_next(s->tree, s->first_displayed_entry); else next = got_object_tree_get_first_entry(s->tree); last = s->last_displayed_entry; while (next && n++ < maxscroll) { if (last) { s->last_displayed_entry = last; last = got_tree_entry_get_next(s->tree, last); } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN && next)) { s->first_displayed_entry = next; next = got_tree_entry_get_next(s->tree, next); } } return NULL; } static const struct got_error * tree_entry_path(char **path, struct tog_parent_trees *parents, struct got_tree_entry *te) { const struct got_error *err = NULL; struct tog_parent_tree *pt; size_t len = 2; /* for leading slash and NUL */ TAILQ_FOREACH(pt, parents, entry) len += strlen(got_tree_entry_get_name(pt->selected_entry)) + 1 /* slash */; if (te) len += strlen(got_tree_entry_get_name(te)); *path = calloc(1, len); if (path == NULL) return got_error_from_errno("calloc"); (*path)[0] = '/'; pt = TAILQ_LAST(parents, tog_parent_trees); while (pt) { const char *name = got_tree_entry_get_name(pt->selected_entry); if (strlcat(*path, name, len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } if (strlcat(*path, "/", len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } pt = TAILQ_PREV(pt, tog_parent_trees, entry); } if (te) { if (strlcat(*path, got_tree_entry_get_name(te), len) >= len) { err = got_error(GOT_ERR_NO_SPACE); goto done; } } done: if (err) { free(*path); *path = NULL; } return err; } static const struct got_error * blame_tree_entry(struct tog_view **new_view, int begin_y, int begin_x, struct got_tree_entry *te, struct tog_parent_trees *parents, struct got_object_id *commit_id, struct got_repository *repo) { const struct got_error *err = NULL; char *path; struct tog_view *blame_view; *new_view = NULL; err = tree_entry_path(&path, parents, te); if (err) return err; blame_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_BLAME); if (blame_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_blame_view(blame_view, path, commit_id, repo); if (err) { if (err->code == GOT_ERR_CANCELLED) err = NULL; view_close(blame_view); } else *new_view = blame_view; done: free(path); return err; } static const struct got_error * log_selected_tree_entry(struct tog_view **new_view, int begin_y, int begin_x, struct tog_tree_view_state *s) { struct tog_view *log_view; const struct got_error *err = NULL; char *path; *new_view = NULL; log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) return got_error_from_errno("view_open"); err = tree_entry_path(&path, &s->parents, s->selected_entry); if (err) return err; err = open_log_view(log_view, s->commit_id, s->repo, s->head_ref_name, path, 0, NULL); if (err) view_close(log_view); else *new_view = log_view; free(path); return err; } static const struct got_error * open_tree_view(struct tog_view *view, struct got_object_id *commit_id, const char *head_ref_name, struct got_repository *repo) { const struct got_error *err = NULL; char *commit_id_str = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_commit_object *commit = NULL; TAILQ_INIT(&s->parents); STAILQ_INIT(&s->colors); s->commit_id = got_object_id_dup(commit_id); if (s->commit_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } err = got_object_open_as_commit(&commit, repo, commit_id); if (err) goto done; /* * The root is opened here and will be closed when the view is closed. * Any visited subtrees and their path-wise parents are opened and * closed on demand. */ err = got_object_open_as_tree(&s->root, repo, got_object_commit_get_tree_id(commit)); if (err) goto done; s->tree = s->root; err = got_object_id_str(&commit_id_str, commit_id); if (err != NULL) goto done; if (asprintf(&s->tree_label, "commit %s", commit_id_str) == -1) { err = got_error_from_errno("asprintf"); goto done; } s->first_displayed_entry = got_object_tree_get_entry(s->tree, 0); s->selected_entry = got_object_tree_get_entry(s->tree, 0); if (head_ref_name) { s->head_ref_name = strdup(head_ref_name); if (s->head_ref_name == NULL) { err = got_error_from_errno("strdup"); goto done; } } s->repo = repo; if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "\\$$", TOG_COLOR_TREE_SUBMODULE, get_color_value("TOG_COLOR_TREE_SUBMODULE")); if (err) goto done; err = add_color(&s->colors, "@$", TOG_COLOR_TREE_SYMLINK, get_color_value("TOG_COLOR_TREE_SYMLINK")); if (err) goto done; err = add_color(&s->colors, "/$", TOG_COLOR_TREE_DIRECTORY, get_color_value("TOG_COLOR_TREE_DIRECTORY")); if (err) goto done; err = add_color(&s->colors, "\\*$", TOG_COLOR_TREE_EXECUTABLE, get_color_value("TOG_COLOR_TREE_EXECUTABLE")); if (err) goto done; err = add_color(&s->colors, "^$", TOG_COLOR_COMMIT, get_color_value("TOG_COLOR_COMMIT")); if (err) goto done; } view->show = show_tree_view; view->input = input_tree_view; view->close = close_tree_view; view->search_start = search_start_tree_view; view->search_next = search_next_tree_view; done: free(commit_id_str); if (commit) got_object_commit_close(commit); if (err) { if (view->close == NULL) close_tree_view(view); view_close(view); } return err; } static const struct got_error * close_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; free_colors(&s->colors); free(s->tree_label); s->tree_label = NULL; free(s->commit_id); s->commit_id = NULL; free(s->head_ref_name); s->head_ref_name = NULL; while (!TAILQ_EMPTY(&s->parents)) { struct tog_parent_tree *parent; parent = TAILQ_FIRST(&s->parents); TAILQ_REMOVE(&s->parents, parent, entry); if (parent->tree != s->root) got_object_tree_close(parent->tree); free(parent); } if (s->tree != NULL && s->tree != s->root) got_object_tree_close(s->tree); if (s->root) got_object_tree_close(s->root); return NULL; } static const struct got_error * search_start_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; s->matched_entry = NULL; return NULL; } static int match_tree_entry(struct got_tree_entry *te, regex_t *regex) { regmatch_t regmatch; return regexec(regex, got_tree_entry_get_name(te), 1, ®match, 0) == 0; } static const struct got_error * search_next_tree_view(struct tog_view *view) { struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *te = NULL; if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (s->matched_entry) { if (view->searching == TOG_SEARCH_FORWARD) { if (s->selected_entry) te = got_tree_entry_get_next(s->tree, s->selected_entry); else te = got_object_tree_get_first_entry(s->tree); } else { if (s->selected_entry == NULL) te = got_object_tree_get_last_entry(s->tree); else te = got_tree_entry_get_prev(s->tree, s->selected_entry); } } else { if (s->selected_entry) te = s->selected_entry; else if (view->searching == TOG_SEARCH_FORWARD) te = got_object_tree_get_first_entry(s->tree); else te = got_object_tree_get_last_entry(s->tree); } while (1) { if (te == NULL) { if (s->matched_entry == NULL) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (view->searching == TOG_SEARCH_FORWARD) te = got_object_tree_get_first_entry(s->tree); else te = got_object_tree_get_last_entry(s->tree); } if (match_tree_entry(te, &view->regex)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = te; break; } if (view->searching == TOG_SEARCH_FORWARD) te = got_tree_entry_get_next(s->tree, te); else te = got_tree_entry_get_prev(s->tree, te); } if (s->matched_entry) { s->first_displayed_entry = s->matched_entry; s->selected = 0; } return NULL; } static const struct got_error * show_tree_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; char *parent_path; err = tree_entry_path(&parent_path, &s->parents, NULL); if (err) return err; err = draw_tree_entries(view, parent_path); free(parent_path); view_border(view); return err; } static const struct got_error * tree_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry **fte, **lte, **ste; int g, last, first = 1, i = 1; int root = s->tree == s->root; int off = root ? 1 : 2; g = view->gline; view->gline = 0; if (g == 0) g = 1; else if (g > got_object_tree_get_nentries(s->tree)) g = got_object_tree_get_nentries(s->tree) + (root ? 0 : 1); fte = &s->first_displayed_entry; lte = &s->last_displayed_entry; ste = &s->selected_entry; if (*fte != NULL) { first = got_tree_entry_get_index(*fte); first += off; /* account for ".." */ } last = got_tree_entry_get_index(*lte); last += off; if (g >= first && g <= last && g - first < nlines) { s->selected = g - first; return NULL; /* gline is on the current page */ } if (*ste != NULL) { i = got_tree_entry_get_index(*ste); i += off; } if (i < g) { err = tree_scroll_down(view, g - i); if (err) return err; if (got_tree_entry_get_index(*lte) >= got_object_tree_get_nentries(s->tree) - 1 && first + s->selected < g && s->selected < s->ndisplayed - 1) { first = got_tree_entry_get_index(*fte); first += off; s->selected = g - first; } } else if (i > g) tree_scroll_up(s, i - g); if (g < nlines && (*fte == NULL || (root && !got_tree_entry_get_index(*fte)))) s->selected = g - 1; return NULL; } static const struct got_error * input_tree_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_tree_view_state *s = &view->state.tree; struct got_tree_entry *te; int n, nscroll = view->nlines - 3; if (view->gline) return tree_goto_line(view, nscroll); switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'i': s->show_ids = !s->show_ids; view->count = 0; break; case 'L': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case 'R': view->count = 0; err = view_request_new(new_view, view, TOG_VIEW_REF); break; case 'g': case '=': case KEY_HOME: s->selected = 0; view->count = 0; if (s->tree == s->root) s->first_displayed_entry = got_object_tree_get_first_entry(s->tree); else s->first_displayed_entry = NULL; break; case 'G': case '*': case KEY_END: { int eos = view->nlines - 3; if (view->mode == TOG_VIEW_SPLIT_HRZN) --eos; /* border */ s->selected = 0; view->count = 0; te = got_object_tree_get_last_entry(s->tree); for (n = 0; n < eos; n++) { if (te == NULL) { if (s->tree != s->root) { s->first_displayed_entry = NULL; n++; } break; } s->first_displayed_entry = te; te = got_tree_entry_get_prev(s->tree, te); } if (n > 0) s->selected = n - 1; break; } case 'k': case KEY_UP: case CTRL('p'): if (s->selected > 0) { s->selected--; break; } tree_scroll_up(s, 1); if (s->selected_entry == NULL || (s->tree == s->root && s->selected_entry == got_object_tree_get_first_entry(s->tree))) view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->tree == s->root) { if (got_object_tree_get_first_entry(s->tree) == s->first_displayed_entry) s->selected -= MIN(s->selected, nscroll); } else { if (s->first_displayed_entry == NULL) s->selected -= MIN(s->selected, nscroll); } tree_scroll_up(s, MAX(0, nscroll)); if (s->selected_entry == NULL || (s->tree == s->root && s->selected_entry == got_object_tree_get_first_entry(s->tree))) view->count = 0; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected < s->ndisplayed - 1) { s->selected++; break; } if (s->last_displayed_entry == NULL || got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further */ view->count = 0; break; } tree_scroll_down(view, 1); break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->last_displayed_entry == NULL || got_tree_entry_get_next(s->tree, s->last_displayed_entry) == NULL) { /* can't scroll any further; move cursor down */ if (s->selected < s->ndisplayed - 1) s->selected += MIN(nscroll, s->ndisplayed - s->selected - 1); else view->count = 0; break; } tree_scroll_down(view, nscroll); break; case KEY_ENTER: case '\r': case KEY_BACKSPACE: if (s->selected_entry == NULL || ch == KEY_BACKSPACE) { struct tog_parent_tree *parent; /* user selected '..' */ if (s->tree == s->root) { view->count = 0; break; } parent = TAILQ_FIRST(&s->parents); TAILQ_REMOVE(&s->parents, parent, entry); got_object_tree_close(s->tree); s->tree = parent->tree; s->first_displayed_entry = parent->first_displayed_entry; s->selected_entry = parent->selected_entry; s->selected = parent->selected; if (s->selected > view->nlines - 3) { err = offset_selection_down(view); if (err) break; } free(parent); } else if (S_ISDIR(got_tree_entry_get_mode( s->selected_entry))) { struct got_tree_object *subtree; view->count = 0; err = got_object_open_as_tree(&subtree, s->repo, got_tree_entry_get_id(s->selected_entry)); if (err) break; err = tree_view_visit_subtree(s, subtree); if (err) { got_object_tree_close(subtree); break; } } else if (S_ISREG(got_tree_entry_get_mode(s->selected_entry))) err = view_request_new(new_view, view, TOG_VIEW_BLAME); break; case KEY_RESIZE: if (view->nlines >= 4 && s->selected >= view->nlines - 3) s->selected = view->nlines - 4; view->count = 0; break; default: view->count = 0; break; } return err; } __dead static void usage_tree(void) { endwin(); fprintf(stderr, "usage: %s tree [-c commit] [-r repository-path] [path]\n", getprogname()); exit(1); } static const struct got_error * cmd_tree(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; struct got_object_id *commit_id = NULL; struct got_commit_object *commit = NULL; const char *commit_id_arg = NULL; char *keyword_idstr = NULL, *label = NULL; struct got_reference *ref = NULL; const char *head_ref_name = NULL; int ch; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "c:r:")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; break; case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_tree(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_tree(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; if (commit_id_arg == NULL) { error = got_repo_match_object_id(&commit_id, &label, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; head_ref_name = label; } else { error = got_keyword_to_idstr(&keyword_idstr, commit_id_arg, repo, worktree); if (error != NULL) goto done; if (keyword_idstr != NULL) commit_id_arg = keyword_idstr; error = got_ref_open(&ref, repo, commit_id_arg, 0); if (error == NULL) head_ref_name = got_ref_get_name(ref); else if (error->code != GOT_ERR_NOT_REF) goto done; error = got_repo_match_object_id(&commit_id, NULL, commit_id_arg, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_TREE); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_tree_view(view, commit_id, head_ref_name, repo); if (error) goto done; if (!got_path_is_root_dir(in_repo_path)) { error = tree_view_walk_path(&view->state.tree, commit, in_repo_path); if (error) goto done; } if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(keyword_idstr); free(repo_path); free(cwd); free(commit_id); free(label); if (commit != NULL) got_object_commit_close(commit); if (ref) got_ref_close(ref); if (worktree != NULL) got_worktree_close(worktree); if (repo) { const struct got_error *close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error * ref_view_load_refs(struct tog_ref_view_state *s) { struct got_reflist_entry *sre; struct tog_reflist_entry *re; s->nrefs = 0; TAILQ_FOREACH(sre, &tog_refs, entry) { if (strncmp(got_ref_get_name(sre->ref), "refs/got/", 9) == 0 && strncmp(got_ref_get_name(sre->ref), "refs/got/backup/", 16) != 0) continue; re = malloc(sizeof(*re)); if (re == NULL) return got_error_from_errno("malloc"); re->ref = got_ref_dup(sre->ref); if (re->ref == NULL) return got_error_from_errno("got_ref_dup"); re->idx = s->nrefs++; TAILQ_INSERT_TAIL(&s->refs, re, entry); } s->first_displayed_entry = TAILQ_FIRST(&s->refs); return NULL; } static void ref_view_free_refs(struct tog_ref_view_state *s) { struct tog_reflist_entry *re; while (!TAILQ_EMPTY(&s->refs)) { re = TAILQ_FIRST(&s->refs); TAILQ_REMOVE(&s->refs, re, entry); got_ref_close(re->ref); free(re); } } static const struct got_error * open_ref_view(struct tog_view *view, struct got_repository *repo) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; s->selected_entry = 0; s->repo = repo; TAILQ_INIT(&s->refs); STAILQ_INIT(&s->colors); err = ref_view_load_refs(s); if (err) goto done; if (has_colors() && getenv("TOG_COLORS") != NULL) { err = add_color(&s->colors, "^refs/heads/", TOG_COLOR_REFS_HEADS, get_color_value("TOG_COLOR_REFS_HEADS")); if (err) goto done; err = add_color(&s->colors, "^refs/tags/", TOG_COLOR_REFS_TAGS, get_color_value("TOG_COLOR_REFS_TAGS")); if (err) goto done; err = add_color(&s->colors, "^refs/remotes/", TOG_COLOR_REFS_REMOTES, get_color_value("TOG_COLOR_REFS_REMOTES")); if (err) goto done; err = add_color(&s->colors, "^refs/got/backup/", TOG_COLOR_REFS_BACKUP, get_color_value("TOG_COLOR_REFS_BACKUP")); if (err) goto done; } view->show = show_ref_view; view->input = input_ref_view; view->close = close_ref_view; view->search_start = search_start_ref_view; view->search_next = search_next_ref_view; done: if (err) { if (view->close == NULL) close_ref_view(view); view_close(view); } return err; } static const struct got_error * close_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; ref_view_free_refs(s); free_colors(&s->colors); return NULL; } static const struct got_error * resolve_reflist_entry(struct got_object_id **commit_id, struct tog_reflist_entry *re, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *obj_id; struct got_tag_object *tag = NULL; int obj_type; *commit_id = NULL; err = got_ref_resolve(&obj_id, repo, re->ref); if (err) return err; err = got_object_get_type(&obj_type, repo, obj_id); if (err) goto done; switch (obj_type) { case GOT_OBJ_TYPE_COMMIT: break; case GOT_OBJ_TYPE_TAG: /* * Git allows nested tags that point to tags; keep peeling * till we reach the bottom, which is always a non-tag ref. */ do { if (tag != NULL) got_object_tag_close(tag); err = got_object_open_as_tag(&tag, repo, obj_id); if (err) goto done; free(obj_id); obj_id = got_object_id_dup( got_object_tag_get_object_id(tag)); if (obj_id == NULL) { err = got_error_from_errno("got_object_id_dup"); goto done; } err = got_object_get_type(&obj_type, repo, obj_id); if (err) goto done; } while (obj_type == GOT_OBJ_TYPE_TAG); if (obj_type != GOT_OBJ_TYPE_COMMIT) err = got_error(GOT_ERR_OBJ_TYPE); break; default: err = got_error(GOT_ERR_OBJ_TYPE); break; } done: if (tag) got_object_tag_close(tag); if (err == NULL) *commit_id = obj_id; else free(obj_id); return err; } static const struct got_error * log_ref_entry(struct tog_view **new_view, int begin_y, int begin_x, struct tog_reflist_entry *re, struct got_repository *repo) { struct tog_view *log_view; const struct got_error *err = NULL; struct got_object_id *commit_id = NULL; *new_view = NULL; err = resolve_reflist_entry(&commit_id, re, repo); if (err) return err; log_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_LOG); if (log_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_log_view(log_view, commit_id, repo, got_ref_get_name(re->ref), "", 0, NULL); done: if (err) view_close(log_view); else *new_view = log_view; free(commit_id); return err; } static void ref_scroll_up(struct tog_ref_view_state *s, int maxscroll) { struct tog_reflist_entry *re; int i = 0; if (s->first_displayed_entry == TAILQ_FIRST(&s->refs)) return; re = TAILQ_PREV(s->first_displayed_entry, tog_reflist_head, entry); while (i++ < maxscroll) { if (re == NULL) break; s->first_displayed_entry = re; re = TAILQ_PREV(re, tog_reflist_head, entry); } } static const struct got_error * ref_scroll_down(struct tog_view *view, int maxscroll) { struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *next, *last; int n = 0; if (s->first_displayed_entry) next = TAILQ_NEXT(s->first_displayed_entry, entry); else next = TAILQ_FIRST(&s->refs); last = s->last_displayed_entry; while (next && n++ < maxscroll) { if (last) { s->last_displayed_entry = last; last = TAILQ_NEXT(last, entry); } if (last || (view->mode == TOG_VIEW_SPLIT_HRZN)) { s->first_displayed_entry = next; next = TAILQ_NEXT(next, entry); } } return NULL; } static const struct got_error * search_start_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; s->matched_entry = NULL; return NULL; } static int match_reflist_entry(struct tog_reflist_entry *re, regex_t *regex) { regmatch_t regmatch; return regexec(regex, got_ref_get_name(re->ref), 1, ®match, 0) == 0; } static const struct got_error * search_next_ref_view(struct tog_view *view) { struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re = NULL; if (!view->searching) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (s->matched_entry) { if (view->searching == TOG_SEARCH_FORWARD) { if (s->selected_entry) re = TAILQ_NEXT(s->selected_entry, entry); else re = TAILQ_PREV(s->selected_entry, tog_reflist_head, entry); } else { if (s->selected_entry == NULL) re = TAILQ_LAST(&s->refs, tog_reflist_head); else re = TAILQ_PREV(s->selected_entry, tog_reflist_head, entry); } } else { if (s->selected_entry) re = s->selected_entry; else if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_FIRST(&s->refs); else re = TAILQ_LAST(&s->refs, tog_reflist_head); } while (1) { if (re == NULL) { if (s->matched_entry == NULL) { view->search_next_done = TOG_SEARCH_HAVE_MORE; return NULL; } if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_FIRST(&s->refs); else re = TAILQ_LAST(&s->refs, tog_reflist_head); } if (match_reflist_entry(re, &view->regex)) { view->search_next_done = TOG_SEARCH_HAVE_MORE; s->matched_entry = re; break; } if (view->searching == TOG_SEARCH_FORWARD) re = TAILQ_NEXT(re, entry); else re = TAILQ_PREV(re, tog_reflist_head, entry); } if (s->matched_entry) { s->first_displayed_entry = s->matched_entry; s->selected = 0; } return NULL; } static const struct got_error * show_ref_view(struct tog_view *view) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re; char *line = NULL; wchar_t *wline; struct tog_color *tc; int width, n, scrollx; int limit = view->nlines; werase(view->window); s->ndisplayed = 0; if (view_is_hsplit_top(view)) --limit; /* border */ if (limit == 0) return NULL; re = s->first_displayed_entry; if (asprintf(&line, "references [%d/%d]", re->idx + s->selected + 1, s->nrefs) == -1) return got_error_from_errno("asprintf"); err = format_line(&wline, &width, NULL, line, 0, view->ncols, 0, 0); if (err) { free(line); return err; } if (view_needs_focus_indication(view)) wstandout(view->window); waddwstr(view->window, wline); while (width++ < view->ncols) waddch(view->window, ' '); if (view_needs_focus_indication(view)) wstandend(view->window); free(wline); wline = NULL; free(line); line = NULL; if (--limit <= 0) return NULL; n = 0; view->maxx = 0; while (re && limit > 0) { char *line = NULL; char ymd[13]; /* YYYY-MM-DD + " " + NUL */ if (s->show_date) { struct got_commit_object *ci; struct got_tag_object *tag; struct got_object_id *id; struct tm tm; time_t t; err = got_ref_resolve(&id, s->repo, re->ref); if (err) return err; err = got_object_open_as_tag(&tag, s->repo, id); if (err) { if (err->code != GOT_ERR_OBJ_TYPE) { free(id); return err; } err = got_object_open_as_commit(&ci, s->repo, id); if (err) { free(id); return err; } t = got_object_commit_get_committer_time(ci); got_object_commit_close(ci); } else { t = got_object_tag_get_tagger_time(tag); got_object_tag_close(tag); } free(id); if (gmtime_r(&t, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(ymd, sizeof(ymd), "%F ", &tm) == 0) return got_error(GOT_ERR_NO_SPACE); } if (got_ref_is_symbolic(re->ref)) { if (asprintf(&line, "%s%s -> %s", s->show_date ? ymd : "", got_ref_get_name(re->ref), got_ref_get_symref_target(re->ref)) == -1) return got_error_from_errno("asprintf"); } else if (s->show_ids) { struct got_object_id *id; char *id_str; err = got_ref_resolve(&id, s->repo, re->ref); if (err) return err; err = got_object_id_str(&id_str, id); if (err) { free(id); return err; } if (asprintf(&line, "%s%s: %s", s->show_date ? ymd : "", got_ref_get_name(re->ref), id_str) == -1) { err = got_error_from_errno("asprintf"); free(id); free(id_str); return err; } free(id); free(id_str); } else if (asprintf(&line, "%s%s", s->show_date ? ymd : "", got_ref_get_name(re->ref)) == -1) return got_error_from_errno("asprintf"); /* use full line width to determine view->maxx */ err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; err = format_line(&wline, &width, &scrollx, line, view->x, view->ncols, 0, 0); if (err) { free(line); return err; } if (n == s->selected) { if (view->focussed) wstandout(view->window); s->selected_entry = re; } tc = match_color(&s->colors, got_ref_get_name(re->ref)); if (tc) wattr_on(view->window, COLOR_PAIR(tc->colorpair), NULL); waddwstr(view->window, &wline[scrollx]); if (tc) wattr_off(view->window, COLOR_PAIR(tc->colorpair), NULL); if (width < view->ncols) waddch(view->window, '\n'); if (n == s->selected && view->focussed) wstandend(view->window); free(line); free(wline); wline = NULL; n++; s->ndisplayed++; s->last_displayed_entry = re; limit--; re = TAILQ_NEXT(re, entry); } view_border(view); return err; } static const struct got_error * browse_ref_tree(struct tog_view **new_view, int begin_y, int begin_x, struct tog_reflist_entry *re, struct got_repository *repo) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL; struct tog_view *tree_view; *new_view = NULL; err = resolve_reflist_entry(&commit_id, re, repo); if (err) return err; tree_view = view_open(0, 0, begin_y, begin_x, TOG_VIEW_TREE); if (tree_view == NULL) { err = got_error_from_errno("view_open"); goto done; } err = open_tree_view(tree_view, commit_id, got_ref_get_name(re->ref), repo); if (err) goto done; *new_view = tree_view; done: free(commit_id); return err; } static const struct got_error * ref_goto_line(struct tog_view *view, int nlines) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; int g, idx = s->selected_entry->idx; g = view->gline; view->gline = 0; if (g == 0) g = 1; else if (g > s->nrefs) g = s->nrefs; if (g >= s->first_displayed_entry->idx + 1 && g <= s->last_displayed_entry->idx + 1 && g - s->first_displayed_entry->idx - 1 < nlines) { s->selected = g - s->first_displayed_entry->idx - 1; return NULL; } if (idx + 1 < g) { err = ref_scroll_down(view, g - idx - 1); if (err) return err; if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL && s->first_displayed_entry->idx + s->selected < g && s->selected < s->ndisplayed - 1) s->selected = g - s->first_displayed_entry->idx - 1; } else if (idx + 1 > g) ref_scroll_up(s, idx - g + 1); if (g < nlines && s->first_displayed_entry->idx == 0) s->selected = g - 1; return NULL; } static const struct got_error * input_ref_view(struct tog_view **new_view, struct tog_view *view, int ch) { const struct got_error *err = NULL; struct tog_ref_view_state *s = &view->state.ref; struct tog_reflist_entry *re; int n, nscroll = view->nlines - 1; if (view->gline) return ref_goto_line(view, nscroll); switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'i': s->show_ids = !s->show_ids; view->count = 0; break; case 'm': s->show_date = !s->show_date; view->count = 0; break; case 'o': s->sort_by_date = !s->sort_by_date; view->action = s->sort_by_date ? "sort by date" : "sort by name"; view->count = 0; err = got_reflist_sort(&tog_refs, s->sort_by_date ? got_ref_cmp_by_commit_timestamp_descending : tog_ref_cmp_by_name, s->repo); if (err) break; got_reflist_object_id_map_free(tog_refs_idmap); err = got_reflist_object_id_map_create(&tog_refs_idmap, &tog_refs, s->repo); if (err) break; ref_view_free_refs(s); err = ref_view_load_refs(s); break; case KEY_ENTER: case '\r': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_LOG); break; case 'T': view->count = 0; if (!s->selected_entry) break; err = view_request_new(new_view, view, TOG_VIEW_TREE); break; case 'g': case '=': case KEY_HOME: s->selected = 0; view->count = 0; s->first_displayed_entry = TAILQ_FIRST(&s->refs); break; case 'G': case '*': case KEY_END: { int eos = view->nlines - 1; if (view->mode == TOG_VIEW_SPLIT_HRZN) --eos; /* border */ s->selected = 0; view->count = 0; re = TAILQ_LAST(&s->refs, tog_reflist_head); for (n = 0; n < eos; n++) { if (re == NULL) break; s->first_displayed_entry = re; re = TAILQ_PREV(re, tog_reflist_head, entry); } if (n > 0) s->selected = n - 1; break; } case 'k': case KEY_UP: case CTRL('p'): if (s->selected > 0) { s->selected--; break; } ref_scroll_up(s, 1); if (s->selected_entry == TAILQ_FIRST(&s->refs)) view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_entry == TAILQ_FIRST(&s->refs)) s->selected -= MIN(nscroll, s->selected); ref_scroll_up(s, MAX(0, nscroll)); if (s->selected_entry == TAILQ_FIRST(&s->refs)) view->count = 0; break; case 'j': case KEY_DOWN: case CTRL('n'): if (s->selected < s->ndisplayed - 1) { s->selected++; break; } if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) { /* can't scroll any further */ view->count = 0; break; } ref_scroll_down(view, 1); break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (TAILQ_NEXT(s->last_displayed_entry, entry) == NULL) { /* can't scroll any further; move cursor down */ if (s->selected < s->ndisplayed - 1) s->selected += MIN(nscroll, s->ndisplayed - s->selected - 1); if (view->count > 1 && s->selected < s->ndisplayed - 1) s->selected += s->ndisplayed - s->selected - 1; view->count = 0; break; } ref_scroll_down(view, nscroll); break; case CTRL('l'): view->count = 0; tog_free_refs(); err = tog_load_refs(s->repo, s->sort_by_date); if (err) break; ref_view_free_refs(s); err = ref_view_load_refs(s); break; case KEY_RESIZE: if (view->nlines >= 2 && s->selected >= view->nlines - 1) s->selected = view->nlines - 2; break; default: view->count = 0; break; } return err; } __dead static void usage_ref(void) { endwin(); fprintf(stderr, "usage: %s ref [-r repository-path]\n", getprogname()); exit(1); } static const struct got_error * cmd_ref(int argc, char *argv[]) { const struct got_error *error; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL; int ch; struct tog_view *view; int *pack_fds = NULL; while ((ch = getopt(argc, argv, "r:")) != -1) { switch (ch) { case 'r': repo_path = realpath(optarg, NULL); if (repo_path == NULL) return got_error_from_errno2("realpath", optarg); break; default: usage_ref(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc > 1) usage_ref(); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; if (repo_path == NULL) { cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; init_curses(); error = apply_unveil(got_repo_get_path(repo), NULL); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; view = view_open(0, 0, 0, 0, TOG_VIEW_REF); if (view == NULL) { error = got_error_from_errno("view_open"); goto done; } error = open_ref_view(view, repo); if (error) goto done; if (worktree) { error = set_tog_base_commit(repo, worktree); if (error != NULL) goto done; /* Release work tree lock. */ got_worktree_close(worktree); worktree = NULL; } error = view_loop(view); done: free(tog_base_commit.id); free(repo_path); free(cwd); if (worktree != NULL) got_worktree_close(worktree); if (repo) { const struct got_error *close_err; close_err = got_repo_close(repo); if (close_err && error == NULL) error = close_err; } if (pack_fds) { const struct got_error *pack_err; pack_err = got_repo_pack_fds_close(pack_fds); if (pack_err && error == NULL) error = pack_err; } tog_free_refs(); return error; } static const struct got_error* win_draw_center(WINDOW *win, size_t y, size_t x, size_t maxx, int focus, const char *str) { size_t len; if (win == NULL) win = stdscr; len = strlen(str); x = x ? x : maxx > len ? (maxx - len) / 2 : 0; if (focus) wstandout(win); if (mvwprintw(win, y, x, "%s", str) == ERR) return got_error_msg(GOT_ERR_RANGE, "mvwprintw"); if (focus) wstandend(win); return NULL; } static const struct got_error * add_line_offset(off_t **line_offsets, size_t *nlines, off_t off) { off_t *p; p = reallocarray(*line_offsets, *nlines + 1, sizeof(off_t)); if (p == NULL) { free(*line_offsets); *line_offsets = NULL; return got_error_from_errno("reallocarray"); } *line_offsets = p; (*line_offsets)[*nlines] = off; ++(*nlines); return NULL; } static const struct got_error * max_key_str(int *ret, const struct tog_key_map *km, size_t n) { *ret = 0; for (;n > 0; --n, ++km) { char *t0, *t, *k; size_t len = 1; if (km->keys == NULL) continue; t = t0 = strdup(km->keys); if (t0 == NULL) return got_error_from_errno("strdup"); len += strlen(t); while ((k = strsep(&t, " ")) != NULL) len += strlen(k) > 1 ? 2 : 0; free(t0); *ret = MAX(*ret, len); } return NULL; } /* * Write keymap section headers, keys, and key info in km to f. * Save line offset to *off. If terminal has UTF8 encoding enabled, * wrap control and symbolic keys in guillemets, else use <>. */ static const struct got_error * format_help_line(off_t *off, FILE *f, const struct tog_key_map *km, int width) { int n, len = width; if (km->keys) { static const char *u8_glyph[] = { "\xe2\x80\xb9", /* U+2039 (utf8 <) */ "\xe2\x80\xba" /* U+203A (utf8 >) */ }; char *t0, *t, *k; int cs, s, first = 1; cs = got_locale_is_utf8(); t = t0 = strdup(km->keys); if (t0 == NULL) return got_error_from_errno("strdup"); len = strlen(km->keys); while ((k = strsep(&t, " ")) != NULL) { s = strlen(k) > 1; /* control or symbolic key */ n = fprintf(f, "%s%s%s%s%s", first ? " " : "", cs && s ? u8_glyph[0] : s ? "<" : "", k, cs && s ? u8_glyph[1] : s ? ">" : "", t ? " " : ""); if (n < 0) { free(t0); return got_error_from_errno("fprintf"); } first = 0; len += s ? 2 : 0; *off += n; } free(t0); } n = fprintf(f, "%*s%s\n", width - len, width - len ? " " : "", km->info); if (n < 0) return got_error_from_errno("fprintf"); *off += n; return NULL; } static const struct got_error * format_help(struct tog_help_view_state *s) { const struct got_error *err = NULL; off_t off = 0; int i, max, n, show = s->all; static const struct tog_key_map km[] = { #define KEYMAP_(info, type) { NULL, (info), type } #define KEY_(keys, info) { (keys), (info), TOG_KEYMAP_KEYS } GENERATE_HELP #undef KEYMAP_ #undef KEY_ }; err = add_line_offset(&s->line_offsets, &s->nlines, 0); if (err) return err; n = nitems(km); err = max_key_str(&max, km, n); if (err) return err; for (i = 0; i < n; ++i) { if (km[i].keys == NULL) { show = s->all; if (km[i].type == TOG_KEYMAP_GLOBAL || km[i].type == s->type || s->all) show = 1; } if (show) { err = format_help_line(&off, s->f, &km[i], max); if (err) return err; err = add_line_offset(&s->line_offsets, &s->nlines, off); if (err) return err; } } fputc('\n', s->f); ++off; err = add_line_offset(&s->line_offsets, &s->nlines, off); return err; } static const struct got_error * create_help(struct tog_help_view_state *s) { FILE *f; const struct got_error *err; free(s->line_offsets); s->line_offsets = NULL; s->nlines = 0; f = got_opentemp(); if (f == NULL) return got_error_from_errno("got_opentemp"); s->f = f; err = format_help(s); if (err) return err; if (s->f && fflush(s->f) != 0) return got_error_from_errno("fflush"); return NULL; } static const struct got_error * search_start_help_view(struct tog_view *view) { view->state.help.matched_line = 0; return NULL; } static void search_setup_help_view(struct tog_view *view, FILE **f, off_t **line_offsets, size_t *nlines, int **first, int **last, int **match, int **selected) { struct tog_help_view_state *s = &view->state.help; *f = s->f; *nlines = s->nlines; *line_offsets = s->line_offsets; *match = &s->matched_line; *first = &s->first_displayed_line; *last = &s->last_displayed_line; *selected = &s->selected_line; } static const struct got_error * show_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; const struct got_error *err; regmatch_t *regmatch = &view->regmatch; wchar_t *wline; char *line; ssize_t linelen; size_t linesz = 0; int width, nprinted = 0, rc = 0; int eos = view->nlines; if (view_is_hsplit_top(view)) --eos; /* account for border */ s->lineno = 0; rewind(s->f); werase(view->window); if (view->gline > s->nlines - 1) view->gline = s->nlines - 1; err = win_draw_center(view->window, 0, 0, view->ncols, view_needs_focus_indication(view), "tog help (press q to return to tog)"); if (err) return err; if (eos <= 1) return NULL; waddstr(view->window, "\n\n"); eos -= 2; s->eof = 0; view->maxx = 0; line = NULL; while (eos > 0 && nprinted < eos) { attr_t attr = 0; linelen = getline(&line, &linesz, s->f); if (linelen == -1) { if (!feof(s->f)) { free(line); return got_ferror(s->f, GOT_ERR_IO); } s->eof = 1; break; } if (++s->lineno < s->first_displayed_line) continue; if (view->gline && !gotoline(view, &s->lineno, &nprinted)) continue; if (s->lineno == view->hiline) attr = A_STANDOUT; err = format_line(&wline, &width, NULL, line, 0, INT_MAX, 0, view->x ? 1 : 0); if (err) { free(line); return err; } view->maxx = MAX(view->maxx, width); free(wline); wline = NULL; if (attr) wattron(view->window, attr); if (s->first_displayed_line + nprinted == s->matched_line && regmatch->rm_so >= 0 && regmatch->rm_so < regmatch->rm_eo) { err = add_matched_line(&width, line, view->ncols - 1, 0, view->window, view->x, regmatch); if (err) { free(line); return err; } } else { int skip; err = format_line(&wline, &width, &skip, line, view->x, view->ncols, 0, view->x ? 1 : 0); if (err) { free(line); return err; } waddwstr(view->window, &wline[skip]); free(wline); wline = NULL; } if (s->lineno == view->hiline) { while (width++ < view->ncols) waddch(view->window, ' '); } else { if (width < view->ncols) waddch(view->window, '\n'); } if (attr) wattroff(view->window, attr); if (++nprinted == 1) s->first_displayed_line = s->lineno; } free(line); if (nprinted > 0) s->last_displayed_line = s->first_displayed_line + nprinted - 1; else s->last_displayed_line = s->first_displayed_line; view_border(view); if (s->eof) { rc = waddnstr(view->window, "See the tog(1) manual page for full documentation", view->ncols - 1); if (rc == ERR) return got_error_msg(GOT_ERR_RANGE, "waddnstr"); } else { wmove(view->window, view->nlines - 1, 0); wclrtoeol(view->window); wstandout(view->window); rc = waddnstr(view->window, "scroll down for more...", view->ncols - 1); if (rc == ERR) return got_error_msg(GOT_ERR_RANGE, "waddnstr"); if (getcurx(view->window) < view->ncols - 6) { rc = wprintw(view->window, "[%.0f%%]", 100.00 * s->last_displayed_line / s->nlines); if (rc == ERR) return got_error_msg(GOT_ERR_IO, "wprintw"); } wstandend(view->window); } return NULL; } static const struct got_error * input_help_view(struct tog_view **new_view, struct tog_view *view, int ch) { struct tog_help_view_state *s = &view->state.help; const struct got_error *err = NULL; char *line = NULL; ssize_t linelen; size_t linesz = 0; int eos, nscroll; eos = nscroll = view->nlines; if (view_is_hsplit_top(view)) --eos; /* border */ s->lineno = s->first_displayed_line - 1 + s->selected_line; switch (ch) { case '0': case '$': case KEY_RIGHT: case 'l': case KEY_LEFT: case 'h': horizontal_scroll_input(view, ch); break; case 'g': case KEY_HOME: s->first_displayed_line = 1; view->count = 0; break; case 'G': case KEY_END: view->count = 0; if (s->eof) break; s->first_displayed_line = (s->nlines - eos) + 3; s->eof = 1; break; case 'k': case KEY_UP: if (s->first_displayed_line > 1) --s->first_displayed_line; else view->count = 0; break; case CTRL('u'): case 'u': nscroll /= 2; /* FALL THROUGH */ case KEY_PPAGE: case CTRL('b'): case 'b': if (s->first_displayed_line == 1) { view->count = 0; break; } while (--nscroll > 0 && s->first_displayed_line > 1) s->first_displayed_line--; break; case 'j': case KEY_DOWN: case CTRL('n'): if (!s->eof) ++s->first_displayed_line; else view->count = 0; break; case CTRL('d'): case 'd': nscroll /= 2; /* FALL THROUGH */ case KEY_NPAGE: case CTRL('f'): case 'f': case ' ': if (s->eof) { view->count = 0; break; } while (!s->eof && --nscroll > 0) { linelen = getline(&line, &linesz, s->f); s->first_displayed_line++; if (linelen == -1) { if (feof(s->f)) s->eof = 1; else err = got_ferror(s->f, GOT_ERR_IO); break; } } free(line); break; default: view->count = 0; break; } return err; } static const struct got_error * close_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; free(s->line_offsets); s->line_offsets = NULL; if (fclose(s->f) == EOF) return got_error_from_errno("fclose"); return NULL; } static const struct got_error * reset_help_view(struct tog_view *view) { struct tog_help_view_state *s = &view->state.help; if (s->f && fclose(s->f) == EOF) return got_error_from_errno("fclose"); wclear(view->window); view->count = 0; view->x = 0; s->all = !s->all; s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->matched_line = 0; return create_help(s); } static const struct got_error * open_help_view(struct tog_view *view, struct tog_view *parent) { const struct got_error *err = NULL; struct tog_help_view_state *s = &view->state.help; s->type = (enum tog_keymap_type)parent->type; s->first_displayed_line = 1; s->last_displayed_line = view->nlines; s->selected_line = 1; view->show = show_help_view; view->input = input_help_view; view->reset = reset_help_view; view->close = close_help_view; view->search_start = search_start_help_view; view->search_setup = search_setup_help_view; view->search_next = search_next_view_match; err = create_help(s); return err; } static const struct got_error * view_dispatch_request(struct tog_view **new_view, struct tog_view *view, enum tog_view_type request, int y, int x) { const struct got_error *err = NULL; *new_view = NULL; switch (request) { case TOG_VIEW_DIFF: if (view->type == TOG_VIEW_LOG) { struct tog_log_view_state *s = &view->state.log; err = open_diff_view_for_commit(new_view, y, x, s->selected_entry, view, s->repo); } else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_BLAME: if (view->type == TOG_VIEW_TREE) { struct tog_tree_view_state *s = &view->state.tree; err = blame_tree_entry(new_view, y, x, s->selected_entry, &s->parents, s->commit_id, s->repo); } else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_LOG: tog_base_commit.idx = -1; if (view->type == TOG_VIEW_BLAME) err = log_annotated_line(new_view, y, x, view->state.blame.repo, view->state.blame.id_to_log); else if (view->type == TOG_VIEW_TREE) err = log_selected_tree_entry(new_view, y, x, &view->state.tree); else if (view->type == TOG_VIEW_REF) err = log_ref_entry(new_view, y, x, view->state.ref.selected_entry, view->state.ref.repo); else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_TREE: if (view->type == TOG_VIEW_LOG) err = browse_commit_tree(new_view, y, x, view->state.log.selected_entry, view->state.log.in_repo_path, view->state.log.head_ref_name, view->state.log.repo); else if (view->type == TOG_VIEW_REF) err = browse_ref_tree(new_view, y, x, view->state.ref.selected_entry, view->state.ref.repo); else return got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); break; case TOG_VIEW_REF: *new_view = view_open(0, 0, y, x, TOG_VIEW_REF); if (*new_view == NULL) return got_error_from_errno("view_open"); if (view->type == TOG_VIEW_LOG) err = open_ref_view(*new_view, view->state.log.repo); else if (view->type == TOG_VIEW_TREE) err = open_ref_view(*new_view, view->state.tree.repo); else err = got_error_msg(GOT_ERR_NOT_IMPL, "parent/child view pair not supported"); if (err) view_close(*new_view); break; case TOG_VIEW_HELP: *new_view = view_open(0, 0, 0, 0, TOG_VIEW_HELP); if (*new_view == NULL) return got_error_from_errno("view_open"); err = open_help_view(*new_view, view); if (err) view_close(*new_view); break; default: return got_error_msg(GOT_ERR_NOT_IMPL, "invalid view"); } return err; } /* * If view was scrolled down to move the selected line into view when opening a * horizontal split, scroll back up when closing the split/toggling fullscreen. */ static void offset_selection_up(struct tog_view *view) { switch (view->type) { case TOG_VIEW_BLAME: { struct tog_blame_view_state *s = &view->state.blame; if (s->first_displayed_line == 1) { s->selected_line = MAX(s->selected_line - view->offset, 1); break; } if (s->first_displayed_line > view->offset) s->first_displayed_line -= view->offset; else s->first_displayed_line = 1; s->selected_line += view->offset; break; } case TOG_VIEW_LOG: log_scroll_up(&view->state.log, view->offset); view->state.log.selected += view->offset; break; case TOG_VIEW_REF: ref_scroll_up(&view->state.ref, view->offset); view->state.ref.selected += view->offset; break; case TOG_VIEW_TREE: tree_scroll_up(&view->state.tree, view->offset); view->state.tree.selected += view->offset; break; default: break; } view->offset = 0; } /* * If the selected line is in the section of screen covered by the bottom split, * scroll down offset lines to move it into view and index its new position. */ static const struct got_error * offset_selection_down(struct tog_view *view) { const struct got_error *err = NULL; const struct got_error *(*scrolld)(struct tog_view *, int); int *selected = NULL; int header, offset; switch (view->type) { case TOG_VIEW_BLAME: { struct tog_blame_view_state *s = &view->state.blame; header = 3; scrolld = NULL; if (s->selected_line > view->nlines - header) { offset = abs(view->nlines - s->selected_line - header); s->first_displayed_line += offset; s->selected_line -= offset; view->offset = offset; } break; } case TOG_VIEW_LOG: { struct tog_log_view_state *s = &view->state.log; scrolld = &log_scroll_down; header = view_is_parent_view(view) ? 3 : 2; selected = &s->selected; break; } case TOG_VIEW_REF: { struct tog_ref_view_state *s = &view->state.ref; scrolld = &ref_scroll_down; header = 3; selected = &s->selected; break; } case TOG_VIEW_TREE: { struct tog_tree_view_state *s = &view->state.tree; scrolld = &tree_scroll_down; header = 5; selected = &s->selected; break; } default: selected = NULL; scrolld = NULL; header = 0; break; } if (selected && *selected > view->nlines - header) { offset = abs(view->nlines - *selected - header); view->offset = offset; if (scrolld && offset) { err = scrolld(view, offset); *selected -= MIN(*selected, offset); } } return err; } static void list_commands(FILE *fp) { size_t i; fprintf(fp, "commands:"); for (i = 0; i < nitems(tog_commands); i++) { const struct tog_cmd *cmd = &tog_commands[i]; fprintf(fp, " %s", cmd->name); } fputc('\n', fp); } __dead static void usage(int hflag, int status) { FILE *fp = (status == 0) ? stdout : stderr; fprintf(fp, "usage: %s [-hV] command [arg ...]\n", getprogname()); if (hflag) { fprintf(fp, "lazy usage: %s path\n", getprogname()); list_commands(fp); } exit(status); } static char ** make_argv(int argc, ...) { va_list ap; char **argv; int i; va_start(ap, argc); argv = calloc(argc, sizeof(char *)); if (argv == NULL) err(1, "calloc"); for (i = 0; i < argc; i++) { argv[i] = strdup(va_arg(ap, char *)); if (argv[i] == NULL) err(1, "strdup"); } va_end(ap); return argv; } /* * Try to convert 'tog path' into a 'tog log path' command. * The user could simply have mistyped the command rather than knowingly * provided a path. So check whether argv[0] can in fact be resolved * to a path in the HEAD commit and print a special error if not. * This hack is for mpi@ <3 */ static const struct got_error * tog_log_with_path(int argc, char *argv[]) { const struct got_error *error = NULL, *close_err; const struct tog_cmd *cmd = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; struct got_object_id *commit_id = NULL, *id = NULL; struct got_commit_object *commit = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; char *commit_id_str = NULL, **cmd_argv = NULL; int *pack_fds = NULL; cwd = getcwd(NULL, 0); if (cwd == NULL) return got_error_from_errno("getcwd"); error = got_repo_pack_fds_open(&pack_fds); if (error != NULL) goto done; error = got_worktree_open(&worktree, cwd, NULL); if (error && error->code != GOT_ERR_NOT_WORKTREE) goto done; if (worktree) repo_path = strdup(got_worktree_get_repo_path(worktree)); else repo_path = strdup(cwd); if (repo_path == NULL) { error = got_error_from_errno("strdup"); goto done; } error = got_repo_open(&repo, repo_path, NULL, pack_fds); if (error != NULL) goto done; error = get_in_repo_path_from_argv0(&in_repo_path, argc, argv, repo, worktree); if (error) goto done; error = tog_load_refs(repo, 0); if (error) goto done; error = got_repo_match_object_id(&commit_id, NULL, worktree ? got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, GOT_OBJ_TYPE_COMMIT, &tog_refs, repo); if (error) goto done; if (worktree) { got_worktree_close(worktree); worktree = NULL; } error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&id, repo, commit, in_repo_path); if (error) { if (error->code != GOT_ERR_NO_TREE_ENTRY) goto done; fprintf(stderr, "%s: '%s' is no known command or path\n", getprogname(), argv[0]); usage(1, 1); /* not reached */ } error = got_object_id_str(&commit_id_str, commit_id); if (error) goto done; cmd = &tog_commands[0]; /* log */ argc = 4; cmd_argv = make_argv(argc, cmd->name, "-c", commit_id_str, argv[0]); error = cmd->cmd_main(argc, cmd_argv); done: if (repo) { close_err = got_repo_close(repo); if (error == NULL) error = close_err; } if (commit) got_object_commit_close(commit); if (worktree) got_worktree_close(worktree); if (pack_fds) { const struct got_error *pack_err = got_repo_pack_fds_close(pack_fds); if (error == NULL) error = pack_err; } free(id); free(commit_id_str); free(commit_id); free(cwd); free(repo_path); free(in_repo_path); if (cmd_argv) { int i; for (i = 0; i < argc; i++) free(cmd_argv[i]); free(cmd_argv); } tog_free_refs(); return error; } int main(int argc, char *argv[]) { const struct got_error *io_err, *error = NULL; const struct tog_cmd *cmd = NULL; int ch, hflag = 0, Vflag = 0; char **cmd_argv = NULL; static const struct option longopts[] = { { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0} }; char *diff_algo_str = NULL; const char *test_script_path; setlocale(LC_CTYPE, ""); /* * Override default signal handlers before starting ncurses. * This should prevent ncurses from installing its own * broken cleanup() signal handler. */ signal(SIGWINCH, tog_sigwinch); signal(SIGPIPE, tog_sigpipe); signal(SIGCONT, tog_sigcont); signal(SIGINT, tog_sigint); signal(SIGTERM, tog_sigterm); /* * Test mode init must happen before pledge() because "tty" will * not allow TTY-related ioctls to occur via regular files. */ test_script_path = getenv("TOG_TEST_SCRIPT"); if (test_script_path != NULL) { error = init_mock_term(test_script_path); if (error) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } } else if (!isatty(STDIN_FILENO)) errx(1, "standard input is not a tty"); #if !defined(PROFILE) if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd unveil", NULL) == -1) err(1, "pledge"); #endif while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) { switch (ch) { case 'h': hflag = 1; break; case 'V': Vflag = 1; break; default: usage(hflag, 1); /* NOTREACHED */ } } argc -= optind; argv += optind; optind = 1; optreset = 1; if (Vflag) { got_version_print_str(); return 0; } if (argc == 0) { if (hflag) usage(hflag, 0); /* Build an argument vector which runs a default command. */ cmd = &tog_commands[0]; argc = 1; cmd_argv = make_argv(argc, cmd->name); } else { size_t i; /* Did the user specify a command? */ for (i = 0; i < nitems(tog_commands); i++) { if (strncmp(tog_commands[i].name, argv[0], strlen(argv[0])) == 0) { cmd = &tog_commands[i]; break; } } } diff_algo_str = getenv("TOG_DIFF_ALGORITHM"); if (diff_algo_str) { if (strcasecmp(diff_algo_str, "patience") == 0) tog_diff_algo = GOT_DIFF_ALGORITHM_PATIENCE; if (strcasecmp(diff_algo_str, "myers") == 0) tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS; } tog_base_commit.idx = -1; tog_base_commit.marker = GOT_WORKTREE_STATE_UNKNOWN; if (cmd == NULL) { if (argc != 1) usage(0, 1); /* No command specified; try log with a path */ error = tog_log_with_path(argc, argv); } else { if (hflag) cmd->cmd_usage(); else error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv); } if (using_mock_io) { io_err = tog_io_close(); if (error == NULL) error = io_err; } endwin(); if (cmd_argv) { int i; for (i = 0; i < argc; i++) free(cmd_argv[i]); free(cmd_argv); } if (error && error->code != GOT_ERR_CANCELLED && error->code != GOT_ERR_EOF && error->code != GOT_ERR_PRIVSEP_EXIT && error->code != GOT_ERR_PRIVSEP_PIPE && !(error->code == GOT_ERR_ERRNO && errno == EINTR)) { fprintf(stderr, "%s: %s\n", getprogname(), error->msg); return 1; } return 0; } got-portable-0.119/tog/tog.10000664000175000017500000007017115066535722011273 .\" .\" Copyright (c) 2018 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt TOG 1 .Os .Sh NAME .Nm tog .Nd Git repository browser .Sh SYNOPSIS .Nm .Op Fl hV .Ar command .Op Ar arg ... .Pp .Nm .Ar path .Sh DESCRIPTION .Nm is an interactive read-only browser for Git repositories. This repository format is described in .Xr git-repository 5 . .Pp .Nm supports several types of views which display repository data: .Bl -tag -width Ds .It Log view Displays commits in the repository's history. This view is displayed initially if no .Ar command is specified, or if just a .Ar path is specified. .It Diff view Displays work tree changes or changes made in a particular commit. .It Blame view Displays the line-by-line history of a file. .It Tree view Displays the tree corresponding to a particular commit. .It Ref view Displays references in the repository. .El .Pp .Nm provides global and command-specific key bindings and options. Some command-specific key bindings may be prefixed with an integer, which is denoted by N in the descriptions below, and is used as a modifier to the operation as indicated. .Nm will echo digits to the screen when count modifiers are entered, and complete the sequence upon input of the first non-numeric character. Count modifiers can be aborted by entering an unmapped key. Once a compound command is executed, the operation can be cancelled with .Cm C-g or .Cm Backspace . .Pp Global options must precede the command name, and are as follows: .Bl -tag -width tenletters .It Fl h Display usage information. .It Fl V , -version Display program version and exit immediately. .El .Pp The global key bindings are: .Bl -tag -width Ds .It Cm H, F1 Display run-time help. Key bindings for the focussed view will be displayed. Pressing this again inside the help view will toggle the display of key bindings for all .Nm views. .It Cm Q Quit .Nm . .It Cm q Quit the view which is in focus. .It Cm Tab Switch focus between views. .It Cm F Toggle fullscreen mode for a split-screen view. .Nm will automatically use vertical split-screen views if the size of the terminal window is sufficiently large. .It Cm S Switch the current split-screen layout, and render all active views in this new layout. The split-screen layout can be either vertical or horizontal. If the terminal is not wide enough when switching to a vertical split, views will render in fullscreen. .It Cm - When in a split-screen view, decrease the size of the focussed split N increments (default: 1). .It Cm + When in a split-screen view, increase the size of the focussed split N increments (default: 1). .It Cm G Go to line N in the view (default: last line). .It Cm g Go to line N in the view (default: first line). .It Cm Right-arrow, l Scroll view to the right N increments (default: 1). .br Output moves left on the screen. .It Cm Left-arrow, h Scroll view to the left N increments (default: 1). .br Output moves right on the screen. .It Cm $ Scroll view to the rightmost position. .It Cm 0 Scroll view left to the start of the line. .El .Pp The commands for .Nm are as follows: .Bl -tag -width blame .It Xo .Cm log .Op Fl b .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc Display history of a repository. If a .Ar path is specified, show only commits which modified this path. If invoked in a work tree, the .Ar path is interpreted relative to the current working directory, and the work tree's path prefix is implicitly prepended. Otherwise, the path is interpreted relative to the repository root. .Pp If invoked in a work tree, the log entry of the work tree's base commit will be prefixed with one of the following annotations: .Bl -column YXZ description .It * Ta work tree's base commit and the base commit of all tracked files matches the branch tip .It \(a~ Ta work tree comprises mixed commits or its base commit is out-of-date .El .Pp This command is also executed if no explicit command is specified. .Pp The key bindings for .Cm tog log are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, >, Full stop, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, <, Comma, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the cursor to the newest commit. .It Cm End, * Move the cursor to the oldest commit. This will traverse all commits on the current branch which may take a long time depending on the number of commits in branch history. If needed, this operation can be cancelled with .Cm C-g or .Cm Backspace . .It Cm g Move the cursor to commit N (default: 1). .It Cm G Like .Cm g but defaults to the oldest commit. .It Cm Enter Open a .Cm diff view showing file changes made in the currently selected commit. If a commit is marked with the .Cm m key map, open a diff view showing file changes made between the marked commit and the currently selected commit. .It Cm m Mark or unmark the selected commit. When a commit is marked, pressing the .Cm enter key on another selected commit opens a .Cm diff view showing the changes between the marked commit and the currently selected commit. .It Cm T Open a .Cm tree view showing the tree for the currently selected commit. .It Cm Backspace Show log entries for the parent directory of the currently selected path. However when an active search is in progress or when additional commits are loaded, .Cm Backspace aborts the running operation. .It Cm / Prompt for a search pattern and start searching for matching commits. The search pattern is an extended regular expression which is matched against a commit's author name, committer name, log message, and commit ID. Regular expression syntax is documented in .Xr re_format 7 . .It Cm & Prompt for a pattern and limit the log view's list of commits to those which match the pattern. If no pattern is specified, i.e. the .Cm & prompt is immediately closed with the Enter key, then the pattern is cleared. Until the pattern is cleared, the limited list of commits replaces the full list of commits for all operations supported by the log view. For example, a search started with .Cm / will search the limited list of commits, rather than searching all commits. The pattern is an extended regular expression which is matched against a commit's author name, committer name, log message, and commit ID. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next commit which matches the current search pattern (default: 1). .br Searching continues until either a match is found or .Cm C-g or the .Cm Backspace key is pressed. .It Cm N Find the Nth previous commit which matches the current search pattern (default: 1). .br Searching continues until either a match is found or .Cm C-g or the .Cm Backspace key is pressed. .It Cm Ctrl+l Reload the .Cm log view with new commits found in the repository or new work tree changes. .It Cm B Reload the .Cm log view and toggle display of merged commits. The .Fl b option determines whether merged commits are displayed initially. .It Cm R Open a .Cm ref view listing all references in the repository. This can then be used to open a new .Cm log view for arbitrary branches and tags. .It Cm @ Toggle between showing the committer name and the author name. .El .Pp The options for .Cm tog log are as follows: .Bl -tag -width Ds .It Fl b Display individual commits which were merged into the current branch from other branches. By default, .Cm tog log shows the linear history of the current branch only. The .Cm B key binding can be used to toggle display of merged commits at run-time. .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm diff .Op Fl asw .Op Fl C Ar number .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar object1 Ar object2 | Ar path ... .Xc If invoked within a work tree without any arguments, display all local changes in the work tree. If one or more .Ar path arguments are specified, only show changes within the specified paths. .Pp Alternatively, if two object arguments are specified, display the differences between the two objects in the repository. Treat each of the two arguments as a reference, a tag name, an object ID, or a keyword and display differences between the corresponding objects. Both objects must be of the same type (blobs, trees, or commits). An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .Pp The key bindings for .Cm tog diff are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm a Toggle treatment of file contents as ASCII text even if binary data was detected. .It Cm Down-arrow, j, Ctrl-n Scroll down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Scroll up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Scroll down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Scroll up N pages (default: 1). .It Cm Ctrl+d, d Scroll down N half pages (default: 1). .It Cm Ctrl+u, u Scroll up N half pages (default: 1). .It Cm Home Scroll to the top of the view. .It Cm End Scroll to the bottom of the view. .It Cm g Scroll to line N (default: 1). .It Cm G Like .Cm g but defaults to the last line in the diff. .It Cm \&( Navigate to the Nth previous file in the diff (default: 1). .It Cm \&) Navigate to the Nth next file in the diff (default: 1). .It Cm \&{ Navigate to the Nth previous hunk in the diff (default: 1). .It Cm \&} Navigate to the Nth next hunk in the diff (default: 1). .It Cm \&[ Reduce diff context by N lines (default: 1). .It Cm \&] Increase diff context by N lines (default: 1). .It Cm <, Comma, K If the .Cm diff view was opened via the .Cm log view, move to the Nth previous (younger) commit. If the diff was opened via the .Cm blame view, move to the Nth previous line and load the corresponding commit (default: 1). .It Cm >, Full stop, J If the .Cm diff view was opened via the .Cm log view, move to the Nth next (older) commit. If the diff was opened via the .Cm blame view, move to the Nth next line and load the corresponding commit (default: 1). .It Cm p Write the currently viewed diff to a patch file in .Pa /tmp . The patch pathname is drawn to the status line. .It Cm / Prompt for a search pattern and start searching for matching lines. The search pattern is an extended regular expression. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next line which matches the current search pattern (default: 1). .It Cm N Find the Nth previous line which matches the current search pattern (default: 1). .It Cm w Toggle display of whitespace-only changes. .It Cm A Change the diff algorithm. Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). This is a global setting which also affects the .Cm blame view. .El .Pp The options for .Cm tog diff are as follows: .Bl -tag -width Ds .It Fl a Treat file contents as ASCII text even if binary data is detected. .It Fl C Ar number Set the number of context lines shown in the diff. By default, 3 lines of context are shown. .It Fl c Ar commit Show differences between commits in the repository. This option may be used up to two times. When used only once, show differences between the specified .Ar commit and its first parent commit. When used twice, show differences between the two specified commits. .Pp The expected argument is a commit ID hash, or an existing reference, tag name, or keyword, which is resolved to a commit ID. Unique abbreviated hash arguments are automatically expanded to a full hash. Both objects must be of the same type (i.e., blobs, trees, or commits). .Pp If the .Fl c option is used, all non-option arguments are interpreted as paths. If one or more such .Ar path arguments are provided, only show differences for the specified paths. .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .It Fl s Show changes staged with .Cm got stage instead of showing local changes in the work tree. This option is only valid when .Cm tog diff is invoked in a work tree with no .Fl c options. .It Fl w Ignore whitespace-only changes. .El .It Xo .Cm blame .Op Fl c Ar commit .Op Fl r Ar repository-path .Ar path .Xc Display line-by-line history of a file at the specified path. .Pp The key bindings for .Cm tog blame are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N pages (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N pages (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home Move the selection cursor to the first line of the file. .It Cm End Move the selection cursor to the last line of the file. .It Cm g Move the selection cursor to line N (default: 1). .It Cm G Like .Cm g but defaults to the last line in the file. .It Cm Enter Open a .Cm diff view for the currently selected line's commit. .It Cm c Reload the .Cm blame view with the version of the file as found in the currently selected line's commit. .It Cm p Reload the .Cm blame view with the version of the file as found in the parent commit of the currently selected line's commit. .It Cm C Reload the .Cm blame view with the previously blamed commit. .It Cm L Open a .Cm log view for the currently selected annotated line. .It Cm / Prompt for a search pattern and start searching for matching lines. The search pattern is an extended regular expression. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next line which matches the current search pattern (default: 1). .It Cm N Find the Nth previous line which matches the current search pattern (default: 1). .It Cm A Change the diff algorithm. Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). This is a global setting which also affects the .Cm diff view. .El .Pp The options for .Cm tog blame are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Xo .Cm tree .Op Fl c Ar commit .Op Fl r Ar repository-path .Op Ar path .Xc Display the repository tree. If a .Ar path is specified, show tree entries at this path. .Pp Displayed tree entries may carry one of the following trailing annotations: .Bl -column YXZ description .It @ Ta entry is a symbolic link .It / Ta entry is a directory .It * Ta entry is an executable file .It $ Ta entry is a Git submodule .El .Pp Symbolic link entries are also annotated with the target path of the link. .Pp The key bindings for .Cm tog tree are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the selection cursor to the first entry. .It Cm End, * Move the selection cursor to the last entry. .It Cm g Move the selection cursor to entry N (default: 1). .It Cm G Like .Cm g but defaults to the last entry. .It Cm Enter Enter the currently selected directory, or switch to the .Cm blame view for the currently selected file. .It Cm L Open a .Cm log view for the currently selected tree entry. .It Cm R Open a .Cm ref view listing all references in the repository. This can then be used to open a new .Cm tree view for arbitrary branches and tags. .It Cm Backspace Move back to the Nth parent directory (default: 1). .It Cm i Show object IDs for all objects displayed in the .Cm tree view. .It Cm / Prompt for a search pattern and start searching for matching tree entries. The search pattern is an extended regular expression which is matched against the tree entry's name. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next tree entry which matches the current search pattern (default: 1). .It Cm N Find the Nth previous tree entry which matches the current search pattern (default: 1). .El .Pp The options for .Cm tog tree are as follows: .Bl -tag -width Ds .It Fl c Ar commit Start traversing history at the specified .Ar commit . The expected argument is a commit ID, or a reference name or keyword which will be resolved to a commit ID. An abbreviated hash argument will be expanded to a full commit ID automatically, provided the abbreviation is unique. The keywords .Qq :base and .Qq :head resolve to the work tree's base commit and branch head, respectively. The former is only valid if invoked in a work tree, while the latter will resolve to the tip of the work tree's current branch if invoked in a work tree, otherwise it will resolve to the repository's HEAD reference. Keywords and references may be appended with .Qq :+ or .Qq :- modifiers and an optional integer N to denote the Nth descendant or antecedent by first parent traversal, respectively; for example, .Sy :head:-2 denotes the work tree branch head's 2nd generation ancestor, and .Sy :base:+4 denotes the 4th generation descendant of the work tree's base commit. Similarly, .Sy foobar:+3 will denote the 3rd generation descendant of the commit resolved by the .Qq foobar reference. A .Qq :+ or .Qq :- modifier without a trailing integer has an implicit .Qq 1 appended .Po e.g., .Sy :base:+ is equivalent to .Sy :base:+1 .Pc . .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .It Cm ref Op Fl r Ar repository-path Display references in the repository. .Pp The key bindings for .Cm tog ref are as follows (N denotes optional prefixed count modifier): .Bl -tag -width Ds .It Cm Down-arrow, j, Ctrl-n Move the selection cursor down N lines (default: 1). .It Cm Up-arrow, k, Ctrl-p Move the selection cursor up N lines (default: 1). .It Cm Page-down, Space, Ctrl+f, f Move the selection cursor down N pages (default: 1). .It Cm Page-up, Ctrl+b, b Move the selection cursor up N pages (default: 1). .It Cm Ctrl+d, d Move the selection cursor down N half pages (default: 1). .It Cm Ctrl+u, u Move the selection cursor up N half pages (default: 1). .It Cm Home, = Move the selection cursor to the first reference. .It Cm End, * Move the selection cursor to the last reference. .It Cm g Move the selection cursor to reference N (default: 1). .It Cm G Like .Cm g but defaults to the last reference. .It Cm Enter Open a .Cm log view which begins traversing history at the commit resolved via the currently selected reference. .It Cm T Open a .Cm tree view showing the tree resolved via the currently selected reference. .It Cm i Show object IDs for all non-symbolic references displayed in the .Cm ref view. .It Cm m Show last modified date of each displayed reference. .It Cm o Toggle display order of references between sort by name and sort by timestamp. .It Cm / Prompt for a search pattern and start searching for matching references. The search pattern is an extended regular expression which is matched against absolute reference names. Regular expression syntax is documented in .Xr re_format 7 . .It Cm n Find the Nth next reference which matches the current search pattern (default: 1). .It Cm N Find the Nth previous reference which matches the current search pattern (default: 1). .It Cm Ctrl+l Reload the list of references displayed by the .Cm ref view. .El .Pp The options for .Cm tog ref are as follows: .Bl -tag -width Ds .It Fl r Ar repository-path Use the repository at the specified path. If not specified, assume the repository is located at or above the current working directory. If this directory is a .Xr got 1 work tree, use the repository path associated with this work tree. .El .El .Sh ENVIRONMENT .Bl -tag -width TOG_VIEW_SPLIT_MODE .It Ev TOG_COLORS .Nm shows colorized output if this variable is set to a non-empty value. The default color scheme can be modified by setting the environment variables documented below. The colors available in color schemes are .Dq black , .Dq red , .Dq green , .Dq yellow , .Dq blue , .Dq magenta , .Dq cyan , and .Dq default which maps to the terminal's default foreground color. .It Ev TOG_COLOR_AUTHOR The color used to mark up author information. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_COMMIT The color used to mark up commit IDs. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_DATE The color used to mark up date information. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_DIFF_CHUNK_HEADER The color used to mark up chunk header lines in diffs. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_DIFF_META The color used to mark up meta data in diffs. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_DIFF_MINUS The color used to mark up removed lines in diffs. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_DIFF_PLUS The color used to mark up added lines in diffs. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_REFS_BACKUP The color used to mark up references in the .Dq refs/got/backup/ namespace. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_REFS_HEADS The color used to mark up references in the .Dq refs/heads/ namespace. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_REFS_REMOTES The color used to mark up references in the .Dq refs/remotes/ namespace. If not set, the default value .Dq yellow is used. .It Ev TOG_COLOR_REFS_TAGS The color used to mark up references in the .Dq refs/tags/ namespace. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_TREE_DIRECTORY The color used to mark up directory tree entries. If not set, the default value .Dq cyan is used. .It Ev TOG_COLOR_TREE_EXECUTABLE The color used to mark up executable file tree entries. If not set, the default value .Dq green is used. .It Ev TOG_COLOR_TREE_SUBMODULE The color used to mark up submodule tree entries. If not set, the default value .Dq magenta is used. .It Ev TOG_COLOR_TREE_SYMLINK The color used to mark up symbolic link tree entries. If not set, the default value .Dq magenta is used. .It Ev TOG_DIFF_ALGORITHM Determines the default diff algorithm used by .Nm . Supported diff algorithms are Myers (quick and dirty) and Patience (slow and tidy). Valid values for .Ev TOG_DIFF_ALGORITHM are .Dq patience and .Dq myers . If unset, the Patience diff algorithm will be used by default. .It Ev TOG_VIEW_SPLIT_MODE Determines the default layout of split-screen views. If set to .Dq h or .Dq H , .Nm will use horizontal split by default. Otherwise, vertical split will be used. The .Cm S key can be used to switch between vertical and horizontal split layout at run-time. .El .Sh EXIT STATUS .Ex -std tog .Sh SEE ALSO .Xr got 1 , .Xr git-repository 5 , .Xr re_format 7 .Sh AUTHORS .An Christian Weisgerber Aq Mt naddy@openbsd.org .An Josh Rickmar Aq Mt jrick@zettaport.com .An Joshua Stein Aq Mt jcs@openbsd.org .An Mark Jamsek Aq Mt mark@jamsek.dev .An Martin Pieuchot Aq Mt mpi@openbsd.org .An Omar Polo Aq Mt op@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Klemens Nanni Aq Mt kn@openbsd.org got-portable-0.119/tog/Makefile.am0000664000175000017500000000422015066536114012440 bin_PROGRAMS = tog include $(top_builddir)/Makefile.common tog_SOURCES = tog.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c tog_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = tog.1 EXTRA_DIST = tog.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lpthread -lm LDADD += $(libbsd_LIBS) $(libncurses_LIBS) $(libuuid_LIBS) $(zlib_LIBS) \ $(libutil_LIBS) $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) $(libncurses_CFLAGS) $(libuuid_CFLAGS) \ $(libmd_CFLAGS) got-portable-0.119/tog/Makefile.in0000664000175000017500000013426515066537210012464 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = tog$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = tog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_tog_OBJECTS = tog.$(OBJEXT) $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/dial.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fetch.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/keyword.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/utf8.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) tog_OBJECTS = $(am_tog_OBJECTS) tog_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/dial.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fetch.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/keyword.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/utf8.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ ./$(DEPDIR)/tog.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(tog_SOURCES) DIST_SOURCES = $(tog_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(libncurses_CFLAGS) \ $(libuuid_CFLAGS) $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ tog_SOURCES = tog.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/keyword.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c tog_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a man1_MANS = tog.1 EXTRA_DIST = tog.1 LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lpthread -lm \ $(libbsd_LIBS) $(libncurses_LIBS) $(libuuid_LIBS) $(zlib_LIBS) \ $(libutil_LIBS) $(libmd_LIBS) $(am__append_1) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tog/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tog/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && $(am__rm_f) $$files clean-binPROGRAMS: -$(am__rm_f) $(bin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/dial.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fetch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/keyword.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/utf8.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) tog$(EXEEXT): $(tog_OBJECTS) $(tog_DEPENDENCIES) $(EXTRA_tog_DEPENDENCIES) @rm -f tog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tog_OBJECTS) $(tog_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/dial.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fetch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/keyword.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/utf8.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tog.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/tog.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/dial.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fetch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/keyword.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f ./$(DEPDIR)/tog.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile include $(top_builddir)/Makefile.common # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/README.portable0000664000175000017500000002602415066536113012307 README.portable =============== This is the portable version of got[1] (Game of Trees), using autotools to provide the library checks required for GoT's dependencies. The following operating systems are supported: * FreeBSD * NetBSD * DragonFlyBSD * MacOS * Linux DEPENDENCIES ============ Note that the names of these libraries are indicative only; the names might vary. Linux: * `libncurses` (for tog(1)) * `libbsd` (BSD's arc4random routines) * `libmd` (SHA256 routines) * `libuuid` (for UUID generation) * `libz` (for Z compression) * `pkg-config` (for searching libraries) * `bison` (for configuration file grammar) * `libevent` (for gotwebd) * `libtls` (may be known as `libretls`) FreeBSD: * `automake` * `pkgconf` * `libretls` * `libevent` (for gotwebd) NetBSD: * `automake` * `libuuid` * `ncuresesw` * `libevent` (for gotwebd) * `libretls` DragonFlyBSD: * `automake` * `pkgconf` * `openssl` * `libevent` (for gotwebd) * `libretls` Darwin (MacOS): * `automake` * `bison` * `pkg-config` * `ncurses` * `openssl` * `ossp-uuid` * `libevent` (for gotwebd) * `libretls` TESTS (REGRESS) =============== To run the test suite: ``` $ make tests ``` The tests depend on git and the HTTP::Daemon Perl module. Got may have to be installed system-wide before the tests will run successfully because paths to helper programs, such as got-read-pack, are hard-coded in user-facing binaries, such as got and tog. Operations such as clone and send which use the network will be trying to connect to 127.0.0.1 over ssh, as the same user who invoked 'make tests'. The command 'ssh 127.0.0.1' must succeed without any interactive prompting. The host key may need to be manually accepted once before running tests. An SSH key can be installed in ~/.ssh/authorized_keys for authentication. The OpenBSD version of Got also has tests for gotd and gotwebd. These tests cannot be run in -portable yet. There are environment variables which control some test parameters: GOT_TEST_PACK=1 will force tests to use pack files instead of loose objects. GOT_TEST_PACK=ref-delta will force use of pack files with ref-deltas rather than offset-deltas. GOT_TEST_ALGO=sha256 will run tests with sha256 repositories. GOT_TEST_ROOT can be set to a path where temporary test data gets stored. This defaults to /tmp. Dependencies ============ * ed NOTE: THIS ONLY WORKS AFTER `make install` DUE TO HOW PATHS TO LIBEXEC HELPERS ARE HARD-CODED INTO THE BINARIES. INSTALLATION ============ ``` $ ./autogen.sh $ ./configure && make $ sudo make install ``` INSTALLING AND PACKAGING GITWRAPPER =================================== The gotd server has an optional companion tool called gitwrapper. A gotd server can be used without gitwrapper in the following cases: 1) The Git client's user account has gotsh configured as its login shell. 2) The Git client's user account sees gotsh installed under the names git-receive-pack and git-upload-pack, and these appear in $PATH before the corresponding Git binaries if Git is also installed. Setting up the user's $PATH in this way can require the use of SetEnv in sshd_config. The above cases can be too restrictive. For example, users who have regular shell access to the system may expect to be able to serve Git repositories from their home directories while also accessing repositories served by gotd. Once gitwrapper has been installed correctly it provides an out-of-the box experience where both gotd and Git "just work". However, this will require coordination with the system's Git installation and/or distribution package because the names of two specific Git programs will be overlapping: git-upload-pack and git-receive-pack If the gitwrapper tool will be used then it must replace git-receive-pack and git-upload-pack in /usr/bin. This is usually achieved by replacing the regular Git binaries in /usr/bin with symlinks to gitwrapper: ``` -rwxr-xr-x 1 root root 1019928 Aug 24 00:16 /usr/bin/gitwrapper lrwxrwxrwx 1 root root 10 Aug 20 12:40 /usr/bin/git-receive-pack -> gitwrapper lrwxrwxrwx 1 root root 10 Aug 20 12:40 /usr/bin/git-upload-pack -> gitwrapper ``` The Git binaries remain available in Git's libexec directory, which is set when Git gets compiled. On Debian it defaults to /usr/lib/git-core. This same path must be given to Got's configure script at build time to allow gitwrapper to find Git's binaries: ``` ./configure --with-gitwrapper-git-libexec-path=/usr/lib/git-core ``` Once gitwrapper is found in /usr/bin under the names git-receive-pack and git-upload-pack, any Git repositories listed in /etc/gotd.conf will be automatically served by gotd, and any Git repositories not listed in /etc/gotd.conf will be automatically served by regular Git's git-upload-pack and git-receive-pack. The client's login shell or $PATH no longer matter, and a peaceful co-existence of gotd and Git is possible. We recommend that distribution packagers take appropriate steps to package gitwrapper as a required dependency of gotd. It is also possible to install gitwrapper without installing gotd. As long as /etc/gotd.conf does not exist or no repositories are listed in /etc/gotd.conf there will be no visible change in run-time behaviour for Git users since gitwrapper will simply run the standard Git tools. In the OpenBSD ports tree both the regular git package and the gotd package are depending on gitwrapper, and the git package no longer installs the git-receive-pack and git-upload-pack programs in /usr/local/bin. BRANCHES + SUBMITTING PATCHES ============================= `got-portable` has two key branches: * `main` which tracks got upstream untainted. * `portable` which provides the portable version of GoT based from code on `main` Patches for portable code fixes should be based from the `portable` branch and sent to the mailing list for review [2] or sent to me directly (see CONTACT). Portable-specific patches should have a shortlog in the form of: ``` portable: AREA: description ``` Where `AREA` relates to the change in question (for example, `regress`, `libexec`, etc). In some cases, this can be omitted if it's a generic change. This helps to delineate `-portable` changes from upstream `got`. The read-only Github repository also runs CI checks using Cirrus-CI on Linux and FreeBSD. SYNCING UPSTREAM CHANGES WITH PORTABLE ====================================== The `-portable` GoT repository uses the following workflow: ``` Github (gh) GoT (upstream) ^ ^ | | | | | | | | +--------> GoT-portable <------+ ``` Here, `got-portable` is a clone of the `-portable` repository, locally on disk. There are two remotes set up within that repository, via `git-remote`: * `upstream` -- which points to the official GoT repository; * `gh` -- which points to the mirrored `-portable` repository so that CI can be run for cross-platform/test purposes [3] * `origin` -- our cloned copy from `-portable` Within the `-portable` repository are two key branches (there may be other topic branches which represent on-going work): * `main` -- this is the branch that tracks (without modification) those changes from `upstream`. This branch is continually reset to `upstream/main` whenever changes occur. * `portable` -- this is the *default* branch of the `-portable` repository which contains portable-specific changes to make `GoT` compile across different OSes. When updating `-portable` from upstream changes, the following actions happen: 1. Changes from `upstream` are fetched. If there are no new changes, there's nothing else to do. 2. Changes from `gh` are fetch so that the result can be pushed out to `gh`. 3. The difference between the local copy of `main` and `origin/main` is used to represent the set of commits which have *NOT* yet been merged to `-portable`. 4. A topic-branch called `syncup` is created from the HEAD of the `portable` branch to hold the to-be-cherry-picked commits from step 3. 5. These commits are then cherry-picked to the `syncup` branch. 6. If there's any conflicts, they must be resolved. 7. Once done, a sanity build is done in-situ to check there's nothing amiss. 8. If that succeeds, the `syncup` branch is merged to `portable` and pushed to `gh` for verification against CI. 9. If that fails, fixes continue and pushed up to `gh` as required. 10. Once happy, both the `main` and `portable` branches can be merged to `origin`. These steps are encapsulated in a script within `-portable`. [Link](../maintscripts/sync-upstream.sh) RELEASING A NEW VERSION ======================= Release for `-portable` try and align as close to upstream GoT as much as possible, even on the same day where that can happen. That being said, sometimes a release of `-portable` might happen outside of that cadence, where a `-portable`-specific issue needs addressing, for example. Before creating a new release, check the version of GoT as found in `util/got-portable-ver.sh` -- as `GOT_PORTABLE_VER`: ``` GOT_PORTABLE_VER=0.75 ``` Here, the *to be released* version of `got-portable` will be `0.75`. Typically, this version is incremented directly after a release, such that there's no need to change this value. The only exception would be if there were an out-of-band release to `-portable`. In such cases, that would take the form: ``` 0.75.1 ``` Where the suffix of `1`, `2`, etc., can be used to denote any sub-releases from the `0.75` version. The variable `GOT_RELEASE` needs be changed to `yes` so that the GOT_PORTABLE_VER is asserted correctly. Once the version is verified, the following should be run from the `portable` branch -- and the repository should not have any outstanding modifications to the source: ``` make clean ; ./autogen && ./configure && make distcheck ``` If this succeeds, the tarball is in the CWD, as: `got-portable-VERSION.tar.gz` This can then be copied to the `got-www` repository and uploaded, along with changing a couple of HTML pages therein to represent the new released version. Additionally, the CHANGELOG file can be copied to the `got-www` and committed. Once all of that has been done, the repository should be tagged to indicate the release, hence: ``` git tag -a 0.75 ``` This can then be pushed out to `gh` and `origin`. After that point, the version of `GOT_PORTABLE_VER` in `util/got-portable-ver.sh` should be changed to the next version, and `GOT_RELEASE` should be setg back to `no`. TODO ==== * configure.ac should start defining AC_ENABLE arguments to allow for finer-grained control of where to search for includes/libraries, etc. * review the compat/ code. Some of those functions are probably picked up in libbsd, so we should drop such implementations from compat/ where there's overlap between libbsd and what's natively available. CONTACT ======= Thomas Adam
thomas_adam (#gameoftrees on irc.libera.chat) [1] https://gameoftrees.org
[2] https://lists.openbsd.org/cgi-bin/mj_wwwusr?user=&passw=&func=lists-long-full&extra=gameoftrees [3] https://github.com/ThomasAdam/got-portable got-portable-0.119/CHANGES0000664000175000017500000027607215066536012010623 * got 0.119; 2025-09-29 - clean up gotwebd requests before freeing sockets; avoids deref of NULL sock - fix wrong process names in gotwebd error messages - use an absolute URL in redirects generated by gotwebd - fix an issue where histedit would not merge added files correctly - tweak gotwebd deferred accept handling to work more like httpd's - add a 'weblogin' command to gotsh for use with gotwebd user authentication - add user authentication support to gotwebd - make gotwebd IPC sockets use non-blocking I/O as intended to fix hang - prevent gotd looping on unhandled errors raised by accept() - fix gotsysd.conf "listen on" statement failing on non-existent sockets - pass gotwebd.conf's www user setting to every gotwebd child process * got 0.118; 2025-09-09 - security fix for -portable: gotwebd can be tricked into reading repositories outside its repos_path; bug introduced in got-0.111; OpenBSD is not affected - make 'tog diff' show the repository name in names of patches written to /tmp - plug memory leaks which were making gotwebd regress tests fail - fix parallel processing of requests in gotwebd, improving responsiveness - set gotwebd pledges according to address families of listening sockets - run gotwebd fcgi parameter parsing in a dedicated process under pledge "stdio" - make gotd commit notifications only show history which is unique to the branch - enable sftp/scp support in the sshd_config file generated by gotsysd - make gotsysd-managed repositories readable for the _gotd group * got 0.117; 2025-08-17 - regress: replace "sed -i" with ed(1) for portable in-place editing - ensure that error messages from gotsysd libexec helpers get logged - fix gotsysd using wrong auth and hmac labels in the generated gotd.conf - preserve bad symlinks across merges during rebase and histedit - improve binary files detection: detect any control characters, not just NUL - gotwebd: fix race condition resulting in trucated html with trailing garbage - make commit coloring faster and more accurate, producing smaller pack files - improve selection of pack files for pinning in the open pack file cache - regress: don't load global/home git configuration files while running tests - make 'got clone' set a got.conf default branch for fetching only, not sending * got 0.116; 2025-07-25 - make our pack-refs header format align with the expectations of git 2.50.0 - fix bogus "bad offset in pack file" errors wrongly raised by gotd - fix gotd branch protection rejecting commits that already exist on server - pick a default branch to clone when the server does not advertise HEAD symref - do not clobber changes staged via stage -p during "got revert" - enforce additional restrictions on reference names specified in gotsys.conf - change gotwebd favicons to show the smiley fish only - fix gotd reload when /etc/gotd-secrets.conf is used - fix bogus "raw object has unexpected size" errors during deltification - fix bug in delta block stretch size calculation resulting in invalid deltas - fix gotsysd behaviour when the anonymous user is removed from gotsys.conf - add support for email and http/json notifications to gotsysd and gotsys.conf * got 0.115; 2025-06-27 - make errors reported by gotsys-apply-conf actually visible - stop trying to start gotd from gotsys-apply-conf if gotd is not running - fix infinite loop in got_pack_repaint_parent_commits() and got-read-pack - fix creation of gotd.conf deny rules in gotsys-write-conf - add support for global repository access rules to gotsysd.conf - fix segfault due to double-free in got-read-gotconfig * got 0.114; 2025-06-23 - preserve author timestamps when rebasing commits - stop running ssh with -q by default; -q hides host key fingerprint errors - fix gotsys-read-conf crash when ssh key comments are missing in gotsys.conf - relax repository path permission checks in gotsys-repo-create - add gotsys apply -w option which waits until sysconf has been run - fix gotsysd getting stuck due to missing final messages from libexec helpers - plug a file descriptor leak in the gotsysd libexec process * got 0.113; 2025-06-05 - tweak 'got status' and 'got add' ignores handling for better git compatibility - improve redundant pack detection during 'gotadmin cleanup' - gotwebd: do not forget to initialize *ngroups argument for getgrouplist() - fix default access for root and _gotd when gotsysd runs without config file - fix bogus "unexpected privsep message" from gotsh during 'got send' - fix a race in gotd notification processing causing notify process to exit * got 0.112; 2025-05-14 - remove /tmp/got-importmsg temp files when import commit message is left empty - rely on secondary _gotwebd groups if repos_path is not owned by _gotwebd group - fix unrelated errors being reported if a histedit operation is aborted - implement support for protected references in gotsys.conf and gotsysd - plug memory leaks in some libexec helpers and in the gitconfig parser - stop needlessly opening the repository whenever a work tree is opened * got 0.111; 2025-04-22 - introduce gotsysd: configure gotd servers by committing to gotsys.git repo - make gotd run 'gotsys check' on gotsys.conf commits before accepting them - make gotd run 'gotsys apply' when the gotsys.git repo receives changes - add a missing malloc failure check to gotd's repo_write process - make got clone/fetch work against Git servers which do not speak English - stop processing more messages upon error in gotd repo_write process - close file descriptors passed to gotd_imsg_compose_event() on failure - potential fix for use-after-free in lib/repository.c's match_packed_object() - make gotd return an informative error when the connection limit is exceeded - in gotctl info, display the time when a client connection was created - add reload support to gotd, triggered via 'gotctl reload', not via SIGHUP! - test S_ISREG in parse_ref_file() explicitly rather than via getline(3) - release ref-file lock when fstat fails in parse_ref_file() - do not treat unhandled signals as a fatal error in gotwebd - fix an edge case of tog spinning when 'B' is pressed in log view - stop using got_repo_map_path() in gotwebd to fix spurious realpath(3) errors - avoid creation of pack_fds array when not needed, saving file descriptors - gotwebd now runs as the _gotwebd user by default, rather than "www" - gotwebd can now serve repositories outside the /var/www chroot directory - the gotwebd.conf repos_path directive is no longer relative to the chroot - get rid of the gotwebd-specific libexec helpers in /var/www/bin/gotwebd - improve gotwebd behaviour when sending data to already disconnected clients - plug some memory leaks in got-send-pack and got-fetch-pack - fix got-fetch-http performance when server sends chunked HTTP responses * got 0.110; 2025-02-20 - fix an endless loop in got-read-pack (regression from 0.109) - change gotwebd diff algorithm from Myers to Patience diff - gotd regress depends on p5-Net-Daemon now due to an added test case * got 0.109; 2025-02-14 - fix gotd failing to protect references when the client sends an empty pack - during pack generation, fix exclusion of commits via an ancestor commit - fix a bogus "received unexpected privsep message" error from gotsh - fix diffstat path order bug in field width computation - gotwebd: preserve 'folder=' parameter when following More links * got 0.108; 2025-01-22 - add ssh -i identity-file support to commands which use the network - make 'got import' output independent of readdir(3) entry order - avoid full file content comparisons in 'got status' for speed - tog: fix NULL deref when log view T keymap is used on worktree entry - tog: fix a deadlock (hang) in the log view implementation - tog: plug a memory leak - tog: do not exit if a tag pointing at a non-commit is selected in ref view - tog: do not mark an incorrect base commit in nested log views - tog: fix NULL deref when scrolling small tree views down - tog: avoid showing a negative log view entry index - tog: do not apply a pointless count modifier to the H, &, p keymaps - tog: do not make users wait for the worktree diff to quit out of tog - gotwebd: make parent process drop root privileges - gotwebd: drop read access to /var/www from parent process - gotwebd: rename "socket" processes to "server" - gotadmin cleanup: pack the repository before removing objects - gotadmin cleanup: do not delete directly referenced trees and blobs - gotadmin cleanup: do not delete objects reachable via nested tags - regress: skip test memleak_send_basic in sha256 mode; expected to fail - regress: make seq(1) invocations portable to fix test failures on linux - regress/gotwebd: implement paginated commits test * got 0.107; 2024-12-28 - gotwebd.css styling tweaks - hide ssh debug output during fetch/send -v, keep showing it at -vv and -vvv - discern mixed-commit worktree diffs with commit ID headers - gotwebd: avoid printf("%s", NULL) when path parameter is not in query - implement a regression test harness for gotwebd - fix free() called with bogus pointer in 'got fetch'; regression from 0.106 - ensure config privsep children get collected upon error to prevent zombies - fix some fprintf(3) failure checks - gotwebd: replace strftime(3) with asctime_r(3) for the sake of consistency - tweak gotwebd log message levels, and log requests in verbose (-v) mode - prevent out-of-bounds read during gotwebd fcgi record debugging - implement tog work tree diff support via log view and CLI - improve error reporting when 'got patch' encounters malformed patches - improve got_opentemp_named_fd error reporting by showing the path template - add ssh -J jumphost support to got and cvg commands which use the network - add regression tests checking for memory leaks with Otto malloc and ktrace - got tag: change -s signer to -S signer - got tag: provide one-line output mode via new -s option - tog: use wtimeout(3) instead of nodelay(3) to honour our display refresh rate - switch got_pathlist data store from TAILQ to RB-tree - plug many memory leaks, some of which affected gotwebd in particular * got 0.106; 2024-11-21 - prevent gotd from exiting with pending notifications if client disconnects - convert got to the new imsg API - gotwebd: improve performance of repository age calculations - gotwebd: ensure child processes inherit non-default config * got 0.105; 2024-11-14 - fix bogus "branch on server has different ancestry" errors from 'got send' - do not try to merge binary files during (un)stage -p and revert -p - fix gotd notifications about changes involving empty files - minor gotwebd.css styling changes - plug several memory and file-descriptor leaks * got 0.104; 2024-10-22 see git repository history for per-change authorship information - gotd.conf: document the macro syntax - tog: prevent a segfault upon unexpected object type in ref list view - fix pack file creation in the presence of tagged tag objects - plugged some memory leaks - fix a crash when unstaging a file which has been removed from disk - gotwebd: fix out of bounds access while handling the configuration * got 0.103; 2024-09-24 see git repository history for per-change authorship information - fix bug causing performance to degrade as more and more pack files appear - tog: add diff view 'p' keymap to write the diff to file - tog: display diffstat in diff view when diffing blobs or trees directly - gotwebd: show commit id prefix on briefs page - add support for HMAC digests to gotd HTTP notifications - move authentication credentials from gotd.conf(5) to gotd-secrets.conf(5) - fix spurious tog regression test failures on slower machines - restore abort() calls in lib/hash.c to quiet potential compiler warnings - gotwebd: unbreak listing of tags on the summary page (regression from 0.102) - gotwebd: minor tweaks to the HTML for ease of styling * got 0.102; 2024-08-14 see git repository history for per-change authorship information - support for sha256 repositories; the network protocol requires git(1) for now - gotwebd: add support for the "owner" file - gotwebd: fix the README link in the summary view - fix handling of .gitignore files containing empty lines - fix handling of files without trailing newline in histedit, rebase and merge - gotd: allow numeric UIDs in permit/deny rules, as intended - gotd: support numeric UIDs in the `user' directive - fix comment handling and explain quoting in the *.conf.5 man pages - tog: add ability to mark arbitrary commits to diff them - print file index and work tree version in got info * got 0.101; 2024-07-11 see git repository history for per-change authorship information - improve gotwebd.8 one-line description - adjust some SIZE_MAX bounds checks - fix histedit -e bug where reverting all the changes caused histedit -c cycles - show a more useful error when a reference name collides with another - improve error message shown by 'got send' when ancestry has diverged - fix wrong gotwebd default repository path in the manpage - tog: fix jumping to the next commit from the diff view with the J key - tog: fix horizontal scroll bug that draws a trailing '.' - gotwebd: plug file descriptor leak in error path - fix bug that prevented gotwebd from working without a config file * got 0.100; 2024-06-03 see git repository history for per-change authorship information - abort if we see a sha2 hash to quiet a potential compiler warning - switch to using readdir because readdir_r is deprecated - show hint about update -b if the user attempts to rebase a branch onto itself - in got.1 EXAMPLES, mention how files can be moved or renamed - fix running gotd regress in release tarball sources - in gotd.8 add an example which illustrates how to create repositories for gotd - don't leak the existence of gotd repositories to unrelated user accounts - fix empty notification messages with multiple gotd notification targets - display abbreviated commit/tag IDs in email notification subject lines - fix Date header generated by got-notify-email - regress: make server tests more robust against race hazard - regress: replace userinfo(8) with the more common getent(1) - fix wrong errno check in bufio_close_sync(), i.e. got-fetch-http - bufio: crank BIO_CHUNK up to 64k for improved http fetch performance - gotwebd.conf: remove `listen on socket off' and `unix_socket off' options - gotwebd.conf: make `listen' a top-level statement - gotwebd.conf: remove unix_socket_name option - gotwebd.conf: allow changing the user ID which gotwebd runs as - gotd/gotwebd: unify log.c - gotwebd: use less temporary files in /tmp - gotd/gotwebd: hide log_info() behind -v and log_debug behind -vv options - fix confusing error message from 'got commit' upon uncommitable paths - gotwebd: use the last matching fastcgi parameter if multiple parameters match - gotwebd: remove previd and prevset query string parameter, they were unused - plug 'got diff obj1 obj2' line metadata memory leak - fix interop with servers that do not use Git protocol sidebands, such as git9 - reintroduce the 'got init' command as an alternative to 'gotadmin init' * got 0.99; 2024-05-05 see git repository history for per-change authorship information - make 'got fetch' work with URLs which refer to $HOME via a tilde: ~user - replace strftime %G-%m-%d with %F to prevent 2024-12-30 -> 2025-12-30 - fix spurious errors from got-fetch-http when server has no more data to send - prevent gotd notification process from exiting due to EPIPE - fix I/O hangs with TLS in got-notify-http - document http and https protocol support in got.conf(5), too - fix an fd leak in gotd's notify process causing endless CPU spin - back out got stage -R option addition; deemed too inconvenient in practice - fix got-fetch-http GET request URL; add leading slash and avoid double slashes - allow custom GOT_TEST_HTTP_PORT when running regression tests - gotwebd: add magic ".git" handling; try foo.git if repository foo is not found - expose authenticated gotd user account in HTTP notifications - gotd.conf(5) HTTP/JSON documentation fixes - fix endless loop upon Ctrl-D (EOF) input during got stage/unstage/revert -p - make gotd notifications work when 'git push' is used instead of 'got send' - make got stage -p behave the same way in interactive and -F modes for 'q' - fix lingering gotd processes from clients closing connections early - regress: prevent spurious failure of gotd test_clone_basic_access_denied - fix an issue where 'git fetch' would error or hang against gotd - use polling read in got_pkt_readn() to avoid endless hangs in gotsh * got 0.98; 2024-04-23 see git repository history for per-change authorship information - speed up got tag -l by caching timestamps in got_ref_cmp_tags() - provide a macro for vi(1) path for use by -portable at compile time - avoid a rename/stat race when gotd installs a new pack and then uses it - make 'got ref -l' output consistent when packed references exist - make 'got ref -l' work consistently when a reference argument is given - add initial support for notifications to gotd(8), via email and http/json - display process title in syslog when a gotd child process exits - hide a pointless end-of-file error on imsg pipe in libexec helpers - plug a memory leak in 'got blame' - add support for topological sorting to the commit graph - add log -t option which enables topological sorting of commits - make 'got rebase' find a merge base with topological sorting if needed - call unveil(2) earlier during import, commit, histedit, and tag commands - make 'got status' display interrupted rebase, histedit, and merge operations - got.1: escape Eq since it's a GNU roff macro, to fix rendering in -portable - regress: use seq instead of jot, for portability reasons - get rid of unnecessary "dns inet" pledge promises while fetching via git:// - add http clone/fetch support using a new got-fetch-http helper - drop git+ssh protocol name from documentation; Git has done the same - require -R option for staging or unstaging directory contents - got patch: fix applying on empty files * got 0.97; 2024-03-11 see git repository history for per-change authorship information - improve error messages shown upon execv failure - fix 'gotadmin pack' crash upon Ctrl-C due to invalid imsg_free() - significantly speed up deltification of large files - improve error handling in got_privsep_recv_imsg() * got 0.96; 2024-02-13 see git repository history for per-change authorship information - gotwebd: add foldable commit briefs - gotwebd: fix (again) the styling for the next/prev buttons - gotwebd: add knob for the number of tags and commits in the summary page - gotwebd: remove PAGE handling - gotwebd: retire max_repos setting - gotwebd: guard against missig folder and file parameter in BLOB and BLAME - gotwebd: improve copy-paste from BLOB pages - gotwebd: fix colour of target lines in dark mode CSS - gotwebd.conf.5: show defaults, improve EXAMPLES - gotwebd.8: improve EXAMPLES sections - fix logging during gotwebd shutdown - plug several memory leaks in tog - plug object id queue leak when iterating pack index files - ensure tmp file is closed and fix UB in diff error path - do not crash when a meta-data file in the .got directory is empty - make the gotd auth process provide the user's account name for later use - avoid opening objects in the gotd session process for no reason - use imsg_get_fd() instead of imsg->fd everywhere - tolerate remotes without urls in git config file for interop with git-annex - plug some fd leaks in the fdopen{,dir} error paths - log -b: handle merge commits unrelated to requested changed path history - fix use of uninitialized variable in update_blob() - plug memory leak in got_pack_dump_delta_chain_to_file() - never write accum_buf on error in got_pack_dump_delta_chain_to_file() * got 0.95; 2023-12-08 see git repository history for per-change authorship information - plug memory leaks in checkout, update, and status commands - gotwebd: repair the "chroot" option in /etc/gotwebd.conf; regression from 0.94 - gotwebd: add breadcumbs to navigate paths in tree/blob/commits/blame views - gotwebd: add a dark mode, enabled based on web-browser preferences - gotwebd: add History/Blob/Raw-File links to blob and blame views - gotwebd: adjust blob line numbers for text-mode browsers - gotwebd: make the blame view work in text-mode browsers - gotwebd: add a Patch action to serve diffs in plain text - gotwebd: add Patch and Tree links to the diff view - gotwebd: display README files in tree views - gotwebd: display a tree-listing and README files in the summary view - gotwebd: render less tags in the summary page to make space for other content - gotwebd: swap order of tags and branch listings on the summary page - gotwebd: display 'More' link instead of 'prev/next' links in the tag listing * got 0.94; 2023-11-29 see git repository history for per-change authorship information - in diff error message, say what was being diffed - gotwebd.css: vertically align briefs age and author - honor fetch_all_branches configuration again - tog: switch back to patience diff algorithm by default for pretty diffs - gotwebd: render all the datetimes in a time tag - slightly reword 'got merge' documentation to hopefully be more clear - make 'tog diff' release the work-tree lock earlier - got patch: handle embedded NULs in lines of patch files with binary data - simplify usage of the 'mesg' histedit script command - fix some fd leaks in error paths and avoid some double-close() - use ibuf_fd_set() instead of reaching into the ibuf struct - gotwebd: remove dead ipproto handling in host() and host_if() - allow setting variables in gotd.conf syntax - fix gotwebd unveil permissions; gotwebd now runs entirely read-only - reduce gotwebd pledges to the minimum currently required - gotwebd.conf: drop support for inferring listen addresses via interface names - gotwebd.conf: use listen * instead of listen "" to listen on any address - gotwebd: get rid of got_sockaddr.[ch] usage to help -portable - allow gotd repo read/write processes to max out data-size resource limits - gotwebd: replace proc.c with much simpler code - gotwebd: don't chdir to / before spawning the child processes - remove the quite ineffective gotwebd repository cache to fix stability issues - fix memory leak on error in got_privsep_recv_painted_commits() - gotwebd: fix broken signal catching - detect concurrent changes to the set of pack files while matching object IDs * got 0.93; 2023-09-18 see git repository history for per-change authorship information - show out-of-memory errors from zlib inflate() and deflate() calls - make 'got fetch' and 'got send' release the work tree lock earlier - tog: add basic regress for log limit and log search - fix "no git repository found" on locked work trees; regression from 0.91 - gotwebd: CSS improvements, looks much better in text-based browsers - gotwebd: don't lose track of the current file during commit log pagination - gotwebd: move buffering from the fastcgi layer to the template layer - got diff: fix "No newline at end of file" showing up where not expected - make 'got send' detect connections unexpectedly closed by server - fix detection of modified files in fresh work trees created with checkout -E - gotd: fix bogus "gotsh: operation timed out" errors; regression from 0.92 * got 0.92; 2023-08-29 see git repository history for per-change authorship information - allow modified files to be deleted during merges if content exists in repo - disallow overlapping repo and work tree in 'got checkout' - speed up opening of the work tree's file-index - speed up deltification by resizing block hash tables less often - add support for commit keywords to 'got log -x' - fix 'got log -dPp' diffstat duplication bug - improve out-of-date reporting accuracy in 'got branch -l' output - document that the log -d option implies log -P - prevent file-index corruption via deletion of missing locally-added files - prevent a double-free in got_worktree_commit - fix regression from 0.76: 'got diff' output matches /usr/bin/diff -p again - gotsh: do not set POLLOUT flag if there is no data to send, for portability - gotd: stop logging "unexpected end of file" when client decides to disconnect - make gotd flush pending messages before disconnecting the client upon success - gotwebd: fix bogus modification times displayed when show_repo_age is off - tog: show work tree base commit marker in the log view - tog: fix an infinite loop that could be triggered via log view search - plug a memory leak in tog's blame view - tog regress: prevent crash in ncurses when Ctrl-C is used to cancel test runs - tog regress: fix occasional failures due to commit timestamp mismatch - regress: nix 'set -A' kshism from tests for portability * got 0.91; 2023-07-19 see git repository history for per-change authorship information - use _POSIX_HOST_NAME_MAX from for portability - add merge -M option which tells 'got merge' not to fast-forward a reference - make gitwrapper ignore "permission denied" errors for repository paths - add cvg(1), a CVS-like Git client; still WIP and not installed by default yet - add initial implementation of 'gotadmin dump' which creates Git bundle files - add initial implementation of 'gotadmin load' which loads Git bundle files - gotadmin cleanup: consider object reachability while cleaning packfiles - gotadmin cleanup: don't delete pack files that are too young - prevent useless EEXIST errors filling up the global custom error array - abort histedit if the user quits the editor without saving the script - fix double-free in tog blame view error path - add support for keywords as arguments to got and tog * got 0.90; 2023-06-23 see git repository history for per-change authorship information - fix segfault in 'got diff' when a root commit is passed to -c - make 'got status' error out as intended when invoked in a repository - make 'got tree /' succeed in a work tree - make 'got add *' more forgiving about versioned paths on the command line - make 'got merge' forward branches if there are no changes to merge - prevent 'got merge' from creating commits on branches outside "refs/heads/" - got, tog: show reference names that begin with the prefix "HEAD" as intended - gotd: unveil repositories read-only in session process while serving fetches - gotd: avoid a "failed to push some refs" error from no-op 'git push' - gotd: avoid re-writing existing ref files when a ref-update is a no-op - gotd: show relevant commit hashes in error message if incoming pushes collide - gotd: wait asynchronously for child process termination - gotwebd: avoid the slowness of needlessly traversing full commit history - gotwebd.conf: disallow 1 for max_commits_display and report range errors - gotwebd.conf: disallow yes/no for booleans to avoid accidental "on" vs. "no" - gotwebd: avoid "gotweb_render_index: repo.git: unexpected end of file" error - gotwebd: simplify the matching of requests against servers in gotwebd.conf - ignore files with invalid reference names while reading references from disk - teach 'gotadmin cleanup' to remove redundant pack files - grab gc.pid.lock file during cleanup operation to block 'git gc' from running * got 0.89; 2023-06-05 see git repository history for per-change authorship information - gotd: return early after disconnect on auth event error instead of crashing - make 'got patch' display statistics about files with conflicts and rejects - make 'got diff' not treat \r\n line endings as special - fix test failures in test_blame_lines_shifted_skip on certain times of day - show reference labels next to commit messages in tog log view - some gotwebd refactoring related to handling of file descriptors - gotwebd: lower log priority of unexpected disconnections - gotwebd: avoid needless double fseek() - fix the size of gotwebd's tempfiles array; exposed by errors from ftruncate() - simplify ancestry checks in checkout, update, rebase, and merge commands - make gitwrapper not fail if programs it wants to run do not exist on disk - stop showing backup references in the tog log and diff views - consistently use ten Xs in mkstemp(3) templates - only delete empty directories which appear in arguments to 'got rm' - simplify parsing of host names and IP addresses in gotwebd's parse.y - make 'got merge' refuse to run if a merge is in progress - make 'got merge -c' fail even if new changes only affect unrelated paths * got 0.88; 2023-04-29 see git repository history for per-change authorship information - tog: always use alternate charset for vertical/horizontal line - several tog regression test suite improvements - run the tog tests as part of the default regress set - tog: resize log view if toggling fullscreen from child view - when finding changed paths iterate tree entries in on-disk order for speed - cache fulltext data in delta cache to improve speed with long delta chains - gotwebd: fix logic error in gotweb_render_index * got 0.87; 2023-04-19 see git repository history for per-change authorship information - add gitwrapper(1) - tog: resume blame and diff search from the first line - fix crash in got log due to NULL-deref in got_object_blob_close - add support for protecting references against 'got send -f' to gotd - fix spurious empty packfile error from gotd when rewinding a branch - tog: implement automated test harness - update the base commit ID of unmodified files if the blob ID matches - fix rebase/histedit -a leaving some files on the temporary branch - make 'got revert' and 'got rm' work on non-existent directories - got: flush stdout before printing the error in main() - when aborting rebase/histedit/merge, unlink files added by merged changes - fix 'got commit' using a bad parent commit ID when worktree is out-of-date - allow no-op merge commits to be created - fix sending merge commits - show how to fetch a pull request in got.1 pull request example section * got 0.86; 2023-03-12 see git repository history for per-change authorship information - fix race condition on NFS where log-message file's modify time may change - fix gotd sending too large pack files in some cases - support histedit fold operations which delete a file and then add it again - make diffing files which changed into dirs and vice-versa possible - handle files changing into directories during 'got update' - add quoting to repository path sent to server for git-shell compatibility - gotwebd: handle short reads and timeouts - gotwebd: provide gotweb_render_page() entrypoint for all pages - gotwebd: reply with non-200 HTTP status code on error * got 0.85; 2023-03-07 see git repository history for per-change authorship information - gotwebd: add missing colon in diff view (patch by Josiah Frentsos) - more preparation for eventual sha256 object ID support - add test coverage for more tree conflict cases during merges - fall back to vi(1) instead of ed(1) if neither EDITOR nor VISUAL are set - in got.1, clarify what users are expected to do during 'histedit -e' - gotd requires a config file; don't fail silently when it cannot be read - regress: replace unportable ln -h option with rm && ln - regress: make cmdline tests POSIX /bin/sh compatible - gotd: remove more (all?) double process names in log - don't pass -d to yacc during the build (patch by Josiah Frentsos) - regress: override locale settings to force the "C" locale - regress: replace "sed -i" with ed(1) for portable in-place editing - fix gotd sometimes reading reused deltas from wrong pack file * got 0.84; 2023-02-22 too many changes to list all here; see git repository history for more; and see git repository history for per-change authorship information - add 'got histedit -d' flag to drop all commits - show worktree UUID in backout/cherrypick -l output - several changes in preparation for eventual SHA256 object ID support - make 'got rebase' work when the to-be-rebased branch has no parent commit - fix bad line-wrapping in tog ref and tree views - add horizontal scrolling support to tog ref and tree views - create .pack and .idx files with filemode 0444, like Git does - make 'got fetch' fetch the work tree's current branch as an implicit fallback - improve 'got fetch' behaviour when work tree's branch is not on server - gotwebd: fix briefs/tags navigation overlap - drop double process name from some gotd logs - tog: fix high CPU usage issue after starting search (reported by Mikhail) - fix gotd exiting with abnormal error during client connection teardown - fix gotd segfault in libevent while disconnecting clients - tweak 'got commit' log-message validation: now checks timestamp and size > 0 - gotwebd: abort blame if the client disconnects midway through - make 'got fetch -b branch' only fetch the named branch - got/tog/gotadmin: call pledge(2) earlier where possible - no longer error out if redundant "got commit -A $GOT_AUTHOR" option is used - add 'gotadmin pack' -D flag to force generation of ref-deltas in pack files - make 'got fetch' update cached HEAD symref if it has changed in remote repo - add commit/histedit/merge/rebase -C option to commit unresolved conflicts - make 'got status' check for merge conflict markers on newly added lines only - fix read/write out of bounds in gitconfig file parser (reported by James Cook) - fix "got fetch" hanging if remote repo is out-of-date (reported by James Cook) - ignore patterns with trailing "/" now match directories (suggested by Lucas) - make 'got merge' honour author setting in gitconfig (reported by James Cook) - sync default values shown in gotwebd.conf(5) EXAMPLES section - fix parsing of indented comments in gitconfig file (reported by James Cook) - fix tog diff between arbitrary commits; regression from 0.80 * got 0.83; 2023-01-30 - fix usage display error in got merge command (patch by Mikhail) - fix missing commits in pack files created with packed object enumeration - avoid traversing enumerated commits more than once in got-read-pack - fix ulimit-related test failures on sparc64 (tracey) - got commit editor now shows log messages from backout and cherrypick (jamsek) - new cherrypick/backout -l option to show recorded log messages (jamsek) - new cherrypick/backout -X option to discard recorded log messages (jamsek) - gotd: implement the delete-refs capability (op) - fix histedit -m on a commit which only changes filemode bits - gotsh.1: show how to set up anonymous public read-only repository access * got 0.82; 2023-01-23 - fix comparison in tree object parser always evaluating to false (jamsek) - add missing bounds-check in gitproto ref-line tokenizer - gotd.8 and gotwebd.8 man page improvements (patch by Josiah Frentsos) - make gotd session process accept just one flush packet at a time - sort ENVIRONMENT entries in got.1 and tog.1 (op) - only forward implicit flush packets from gotsh if they are expected - return GOT_ERR_EOF from pkt.c if a read attempt indicates EOF - treat read errors from client socket in gotsh as fatal errors - gotwebd: refactor gotweb_render_content_type/_file (op) - gotwebd: turn gotweb_get_time_str into gotweb_render_age (op) - gotwebd: don't list references per-commit in got_get_repo_commits (op) - gotwebd: avoid history traversal in briefs/commits, kill "prev" button (op) - gotd: disconnect on client EOF error to avoid stale connections (op) - gotsh: validate with parse_command before connecting (op) - add a test for ssh connections to gotsh without a repo path argument (op) - gotsh: avoid a temporary buffer for the socket path (op) - gotsh: move apply_unveil right after the first pledge (op) - fix tog refreshing the screen more often than intended (jamsek) - tog: show action report on user-toggleable event (patch by Mikhail, jamsek) - don't print empty line when exiting tog (jamsek) - got: don't leak pathlist in commit and revert commands (jamsek) - gotd: fix wrong PIDs for parent and child processes shown in logs * got 0.81; 2023-01-18 - gotd: print configuration errors without -d (op) - gotd: move nrepos check to parse_config (op) - gotd: move socket path check to parse.y and error from the main process (op) - fix an issue where multiple ref-updates are rejected by gotd - fix an issue where gotd fails to accept multiple have-lines from clients - regress: replace typeset with printf for shell portability (naddy) - fix spurious "gotsh: unexpected flush packet" error when client is up-to-date - gotd: fix "bad packfile with zero objects" error while creating branches - document the gotd -n option * got 0.80; 2023-01-17 too many changes to list all here; see git repository history for more - implement per-repository read/write authorization rules in gotd - add a gotd "listen" process which watches the unix socket - add a gotd "session" process, split off from the parent process - switch gotd from chroot(2) to unveil(2) - run gotd authentication in a separate child process - enforce a per-uid connection limit in the gotd listen process - introduce connection options to gotd.conf - gotd: allow to express timeouts using minutes/hours (op) - switch gotd.conf syntax from 'unix_socket' to 'listen on' - remove the gotsh group requirement from gotd; any user can now connect - expose 'gotctl info' output only to the root user - remove support for showing client capabilities in 'gotctl info' - farewell, gotweb. you served us well. rm gotweb (tracey) - lots of gotwebd refactoring (op) - gotwebd: use a templating system to render HTML (op) - gotwebd: add an RSS feed for the tags (op) - gotwebd: remove erratic horizontal scrolling (op) - gotwebd.conf: use `listen on socket' syntax for UNIX sockets too (op) - gotwebd: render BLOB inline, add BLOBRAW for serving raw blobs (op) - gotwebd: css: fix horizontal overflow in blob and blame pages (op) - gotwebd: urlencode also the double quote character (op) - gotwebd: make commit page more like `got log' / tog (op) - cope with deleted references when reloading the tog log view - tog: fix typo that breaks log search when in hsplit (jamsek) - tog: always echo input prompt to bottom left of screen (jamsek) - make 'tog log' display the committer handle by default, '@' switches to author - tog: add mutt-like =/* keymaps as home/end aliases (patch by Mikhail) - implement diffstat display for got log, got diff, and tog diff (jamsek) - show from: and via: headers on consecutive lines in 'got log' and 'tog log' - show full URL during got clone/fetch/send (op) - make 'got send' print errors reported by the server (op) - fix 'got rebase' not detecting an out-of-date work tree in some cases - reduce max amount of tags stored in object cache to avoid high memory usage - avoid copying reused deltas to delta cache file; copy from pack file instead - got patch: handle the removal of binary files (op) - fix uninitialised variables in libexec helpers (jamsek) - got: minor refactor of got_pathlist_free() API (jamsek) - fix indexing of pack files which contain ref-deltas * got 0.79; 2022-11-08 - repair build on OpenBSD/sparc64 (patch by Ted Bullock) - fix crash in gotd if client gets disconnected on error (reported by Mikhail) - fix crash in got-send-pack when server does not announce any capabilities - make gotd work as intended on an empty repository - prevent freeing of bogus pointers in got_inflate_end() and got_deflate_end() - reduce delta cache size to avoid running out of memory on large pack files - add missing free of delta buffers in several error paths - make 'got clone -b' work for repositories which lack a valid HEAD reference - use sub-second precision when checking for objects/pack/ modification - fix capabilities announced by gotsh when no references exist in repository * got 0.78; 2022-11-03 - gotsh.1: Use Sx for referencing EXAMPLES (patch by Josiah Frentsos) - change got_pack_parse_offset_delta tslen argument to size_t (op) - fix regression test failures with Git 2.30.5 / 2.38.1 or later installed - fix gotd(8) usage() string (patch by Josiah Frentsos) - regress/rebase.sh: remove accidentally included absolute path to "got" (naddy) - fix off_t type mismatches in printf format string arguments (naddy, op) - fix spelling of "FastCGI" (patch by Josiah Frentsos) - add missing `goto done;' on error path of read_raw_delta_data() (op) - add bounds check when reading a delta offset from a packed object (op) - check size before calling mmap(2) (op) - sort getopt() option lists and switch statements (patch by Josiah Frentsos) - make got.conf(5) warn about remotes configured in locally-shared repositories - add missing check for errors from got_gotconfig_read() in open_worktree() - plug a memory leak on error in got_gotconfig_read() - convert pack filesize variables to off_t for large packs on 32-bit arch (op) - remove sendfd pledge promise from gotd repo_read and repo_write processes - add gotctl(8); initially supported commands are 'info' and 'stop' - respect umask when creating or changing files and directories (op) - fix typo which caused a double-free in gotd repo_write_shutdown() - got-fetch-pack: fix wrong memmove length leading to dubious checksum failures - avoid incomplete writes of pack file data in gotsh and got-send-pack - add a test suite for gotd(8); check basic clone and send functionality - require space between commit author name and email, for Git compatibility - gotwebd: avoid 500 error code if erroring out in plaintext mode (landry) - gotwebd: add respect_exportok flag, defaulting to off (landry) - respect open files resource limit when sizing pack cache; regression from 0.71 - provide a diff of changes in a temp file while editing a commit log message - fix memory and file descriptor leak for raw objects; regression from 0.77 - remove casts which made older gcc versions unhappy - fix free of wrong address on error in gotweb's parse.y * got 0.77; 2022-10-24 - disallow integrating into references outside refs/heads/ (jrick) - gotwebd.conf: add syntax for defining macros and document them (op) - simplify the way 'got patch' opens a tempfile when reading from stdin - lots of refactoring to allow gotd(8) code to run without libexec helpers - more refactoring to allow gotd(8) to stream packfile data on network sockets - add missing error checking around some unlink(2) syscalls - don't crash if delta cache is missing while combining deltas; for dev builds - allow got_object_parse_tree() to reuse entries buffer allocations for speed - show a more useful error if the size of a packed object won't fit in 64 bits - switch integers used for counting objects while indexing packs to unsigned - refresh cached list of pack index paths while searching a packed object - introduce gotd(8) and gotsh(1); WIP and not yet provided in binary packages - close parent's end of imsg pipe before waiting for a child process to exit - fix detection of SIGTERM in tog; this signal was accidentally being ignored - avoid printing harmless errors that can occur when tog exits due to Ctrl-C * got 0.76; 2022-09-23 - gotwebd documentation fixes - tog: extend log view author highlight colour to full field width (jamsek) - tog: make headline highlight extend the full view width (jamsek) - make got_commit_graph_iter_next use caller-provided storage for the id (op) - tog: add new log view limit feature to filter commits (patch by Mikhail + op) - tog: respect current cursor position during log search (patch by Mikhail) - tog: implement runtime help accessible via H,F1 keymaps (jamsek) - add gotadmin init -b to specify repo head ref (jamsek) - ensure got patch respects x-bit perms for new files (jamsek) - gotwebd: drop needless NULL check (op) - show file mode for new added files in work tree diffs (jamsek) - fix wrong function prototypes shown in diff hunk headers (thj@freebsd, jamsek) * got 0.75; 2022-09-07 too many changes to list all here; see git repository history for more - unlink temporary files created during ssh signature verification - add gotwebd, a fast-cgi server and successor of gotweb (tracey) - lots of release-preparation work on gotwebd (naddy, op, tracey, stsp) - cast argument of type rlim_t to unsigned long long to match the %llu (naddy) - tog: add key to toggle author/committer in log view (op) - make our email address parsing closer to Git's parsing rules (op) - got commit: add -A flag to specify the author of a patch (op) - tog: alias J and K to > and < keybindings for diff view (patch by Mikhail) - fix 'got cat' printing commit author instead of committer (op) - tog: add 'L' key to blame view; opens log view for the annotated line (jamsek) - don't chug along if repo format version is unsupported (florian) - fix dead stores to variables, found with LLVM's scan-build (florian) - fix uninitialized error return (florian) - make sure got_repo_pack_fds_close() frees a malloc'ed pointer (florian) - prevent memory leak when asprintf fails (florian) - prevent use-after-free of packed_refs_path in error path (florian) - got_repo_pack_fds_close: don't close(0) (patch by Lucas) - reset committer's name+email during rebase and histedit - tog: fix unintentional move of cursor after closing child views (jamsek) - tog: uppercase all the key maps which open new views (jamsek) - make 'got histedit' fetch author info from Git configuration as a fallback - fix 'got patch -R' when using diff3 merge (op) - add GOT_IGNORE_GITCONFIG env var to force ignoring of Git config files - fix off_t type mismatches (naddy) - got patch: error if patchfile isn't a regular file (op) - make 'got patch' apply pledge(2) earlier (op) - got/tog diff: fix accounting for line-endings in files containing CRLF (op) - got patch: add -c flag to apply at a specified commit (op) - fix two missing error checks in tog (found by florian with scan-build) - remove pointless repo_close + leaked error (found by florian with scan-build) - tog: add n{G,g} key map to jump to line n like less(1) (jamsek) - diff: re-alloc arrays in larger chunks for up to 3x more performance (jamsek) - fix whitespace-related issues when 'got patch' is matching a hunk (op) - tog: add keymaps to jump to next/prev file/hunk in the diff view (jamsek) - fix 'got tag' not tagging the work tree's current branch by default - tog log: don't block while loading commits after 'G' key was pressed (jamsek) - man pages: group options in accordance to style(9) (patch by Josiah Frentsos) - man pages: Replace 'Ar sign' with 'Cm sign' (patch by Josiah Frentsos) - don't add trailing \0 to signed tag objects; fixes interop with Github (jrick) - use Xo/Xc in the man pages (patch by Josiah Frentsos) - fix diffing two blobs by object ID with 'got diff' (jamsek) - refresh pack-index path list if mtime of the objects/pack directory changed - diff3: switch diff output mode from "edscript" to "plain" (patch by Tom Jones) - use the faster plain-diff headers-only mode for diff3 - do not segfault while verifying "lightweight" tags (jrick) - don't search through ignored paths and files on commit (sdk) - plug a lot of memory leaks (op) - forbid rebase of references outside the "refs/heads/" namespace - fflush(stdout) after asking questions; improves got-portable behaviour (op) - fix bug where 'got branch -lt' produced duplicate listings of a branch - tog: ensure stdin is a tty to guard against 'tog < /dev/null' etc. (jamsek) * got 0.74; 2022-07-14 - cast printf argument of type time_t to long long to match the %lld (naddy) - add missing revoked_signers grammar to got.conf(5) (jrick) - move 'got init' command to 'gotadmin init' - regress test SSH key revocations (jrick) - long overdue update of AUTHORS lists in man pages - add signer_id option to got.conf(5) (jrick) - delta_cache.c needs to include ; unbreaks -portable build on ubuntu - regress: use bs=1M for dd, not bs=1m; fixes -portable test failure on ubuntu - fix buf_alloca error handling (op) - some privsep.c refactoring and cleanup (op) - tog: implement global 'S' key map to switch split mode (jamsek) - tog: implement +/- keymaps to resize the focussed split (jamsek) - make 'tog log' error out in shallow Git repositories instead of hanging - tog: enable moving to prev/next blame line in diff view (jamsek) - improve documentation of the histedit 'mesg' command - histedit script: allow mesg command only after pick or edit commands (op) - for linux, fix usage of pipe(2) during SSH signing and verification (jrick) * got 0.73; 2022-07-04 - got patch: use diff3 to merge changes if possible (op) - tog: alias C-b/C-f to scroll page back/forward with b/f (jamsek) - tog: make SPACE page down in all views (naddy) - tog: allow prefixing movement keys with count modifier (jamsek) - always show commit or tree IDs in diff header, in order to help 'got patch' - build non-release builds with -Wwrite-strings (op) - got patch: handle git-style diffs for the 3-way merge too (op) - implement support for commit coloring in got-read-pack for speed - move got_opentemp out of open_blob and blame.c for future gotwebd (tracey) - move got_opentemp out of diff.c and diffreg.c for future gotwebd - tog: refactor log cursor movement in preparation for horizontal split (jamsek) - tog: implement support for horizontal splitscreens (jamsek) - switch 'tog diff' and 'tog blame' to Myers diff by default for speed - make the diff algorithm used by 'tog diff' and 'tog blame' configurable - make the patch parser look for the next "diff" header for robustness (op) - got patch: don't loose the x bit when merging with diff3 (op) - got patch: handle mangled whitespace (op) - fix "imsg_add TREE_ENTRY: Result too large" error on i386 (semarie, op) - create and verify tags signed by SSH keys (jrick) - tog: add C-g/backspace key map to abort compound commands (jamsek) - rename got.conf(5) fetch-all-branches to fetch_all_branches for consistency - rename got.conf(5) mirror-references to mirror_references for consistency - use pipe() which is a more portable syscall than pipe2() (jrick) - got patch: check for specific chars instead of using isspace(3) (op) * got 0.72; 2022-06-18 - fix "bad offset in pack file" error due to uninitialized variable (op) - initialize all variables used for sending privsep messages to zero (op) - tog: reset search state after Ctrl-L to fix a use-after-free (op) - fix unexpected imsg error after incomplete enumeration in got-read-pack - tog: heed selection cursor position while searching (patch by Mikhail) * got 0.71; 2022-06-17 - got patch: fail when reading empty hunks (op) - got patch: switch from fseek() to fseeko(), use unary minus (naddy) - got patch: avoid open/sync/close of the fileindex over and over again (op) - make got_privsep_recv_tree() reject trees with less than zero entries - plug memory leak in an error path of got_privsep_recv_tree() - prevent an out-of-bounds access in got_privsep_recv_tree() - parse tree entries into an array instead of a pathlist for speed - batch up tree entries in imsg instead of sending one imsg per tree entry - imsg_add() frees its msg argument on error; avoid double-free in error paths - avoid malloc/free for duplicate check in got_pathlists_insert() - plug a small memleak on error in got_pack_create() - fix paths stored in pack meta data, improving file deltification - store a path hash instead of a verbatim path in pack meta data - reduce the amount of memory used for caching deltas during deltification - shrink struct got_pack_meta a bit by removing the have_reused_delta flag - use random seeds for murmurhash2 (op) - fix bug in findwixt() which caused pack files with missing parent commits - avoid looping over deltas twice in dump_delta_chain_to_{file,mem}() - open tempfiles needed for delta application upfront, for future gotwebd - reduce GOT_PACK_CACHE_SIZE to 32 to accommodate for previous tempfile change - tog: override SIGTERM and SIGINT handlers to avoid ncurses cleanup() handler - move creation of tempfiles outside of lib/diff.c - tests: don't pass $ret to test_done on failure when it's known to be zero (op) - tests: set `ret' in a few places where it was forgotten (op) - convert delta cache to a hash table - implicitly unstage changes when staging the reverse of a staged diff (op) - implement object enumeration support in got-read-pack for speed - add one-line output mode to got log with -s flag (patch by Evan Silberman) - rename the former got log -s (search) flag to got log -S - make it possible to match committed patches with got log -p -S pattern - tog: add key bindings for half-page scroll (patch by Mikhail, Mark Jamsek) - make got log -S match author name and commit ID, like tog search does (op) - got patch: ensure new and old paths are NUL-terminated (op) - got patch: guard against invalid (negative) line offsets (op) - got patch: use ints for line offsets instead of longs (op) - remove redundant datalen checks before calling recv_imsg_error (op) - use strndup instead of malloc+memcpy in privsep.c (op) - do stricter validation of data received from libexec helpers (op) - move got_opentempfd() out of got_repo_open(), for future gotwebd (tracey) - fix D_GOTWWW default path; gotweb can now run without a config file again - add horizontal scrolling to tog diff, blame, and log views (Mark Jamsek) - show last-modified date in the "tog ref" view if 'm' is pressed (Mark Jamsek) - make tog horizontal scrolling work with unicode (with op@) * got 0.70; 2022-05-10 - avoid subtraction of values larger than int in qsort(3) comparison callbacks - make 'got patch' handle git-style rename diffs - store deltas in compressed form while packing, both in memory and cache file - avoid O(N) loops over object ID lists while packing - run the search for deltas to reuse in got-read-pack directly, for speed - hook send.sh cmdline tests into 'make regress', this was overlooked earlier - fix regression from 0.69 where packing tags fails if zero commits are packed - map delta cache file into memory if possible while writing a pack file * got 0.69; 2022-04-24 - plug a memory leak in got_fetch_pack() (patch by Mikhail) - plug a memory leak in list_refs() (op) - link libexec helpers against _p libraries when building with 'make PROFILE=1' - regress: use test(1) -eq and -ne to compare integers, reduce quoting (naddy) - got patch: add -p option to strip path components (op) - stop relying on commit cache for good performance of got_object_id_by_path() - leave work tree in usable state after 'got rebase' fails path-prefix checks - make gotadmin pack -x option work with tag arguments - make 'got cat' not search for a work tree if the -r option is used - make 'got tag' unlock work tree earlier to allow other parallel commands - add a -q (quiet) option to 'gotadmin pack' - sort references by date for packing to process newer commits first - fix double-free in an error case of cmd_checkout() - make sure callers of got_object_idset_add() free data (tb) - speed up initial stage of packing by adding a "skip" commit color - regress: redirect jot(1) output instead of looping over it (op) - reimplement object-ID set data structure on top of a hash table - inline struct got_object_id in struct got_object_qid for speed - got patch: resolve paths from the current working directory (op) - got patch: add -R option to reverse a patch (op) * got 0.68; 2022-03-22 - explicitly include for be32toh() (naddy) - apply time-based rate-limiting to send-/fetch-/index-pack progress output - make the URI parser tolerate trailing slashes at the end of the input URI - add 'got patch' command for applying unified diffs (op) - handle reference arguments which look like short object IDs (with naddy) - make got log, diff, blame, tree, and cat unlock the work tree earlier - fix 'got status' with an obstructed file given as argument (found by op) - cache a list of known pack index files when the repository is opened - print additional progress information while packing - const-ify data tables which contain only constants (naddy) - fix gotweb build failure with -Werror due to write-only variable warnings - move got_errors[] table into a single compilation unit, error.c (naddy) - explicitly include for close(2) (naddy) - fix potential NULL deref in error path of got_object_idset_remove() - man pages: fix missing commas between subordinate and main clauses (naddy) - fix a bug where 'gotadmin pack' packed too many objects unless -a was used - gotweb: fix free() on uninitialized variable upon error during blame * got 0.67; 2022-02-18 - compress delta data from delta_cache directly into pack file - show rebase and histedit backups in tog ref view - gotweb: unbreak index page when pack files are missing (tracey) - make 'got rm' behave like rm(1) for paths found missing on disk - make 'got rm' report an "unexpected status" error for unversioned files - fix double-free and double-close issues in error paths of got_packidx_open() - fix 'got status' showing unversioned directories on NFS (found by Ted Bullock) - fix loose object file header parser for zero-length headers - improve 'got add' error message if file does not exist (found by Timo Myyrä) - improve error message due to malformed `author' in got.conf (omar) - fix infinite loop triggered by pack files >= 4GB in size (found by semarie) - set zlib output buffer length properly after resizing the output buffer - improve error reporting for invalid numbers given on command line (omar) - fix 'got diff' on files which match an ignore pattern (found by omar) - reduce minimum deltification chunk size to 32 (suggested by ori) - use murmurhash instead of sha1 for deltification blocks (suggested by ori) - shrink the width of formatted output fields to their expected size (naddy) - reuse existing deltas when creating pack files - fix fd leak in got_fetch_pack (omar) - fix imsg_clear calls after imsg_flush failures (omar) - display GMT offset in 'got cat' command (jrick) - const-ify command and option tables (naddy) * got 0.66; 2022-01-11 - only open raw objects if necessary while writing out pack file data - map raw object files into memory while packing if possible - encode short deltas in memory instead of writing them to a temporary file - add missing checks for reads beyond the mapped memory area of a pack file - fix file corruption regression in 'got checkout' from 0.65 (reported by naddy) * got 0.65; 2022-01-06 - fix 32-bit size_t multiplication overflow in meyrs diff code - ignore the return value of closefrom(2) (patch by Anna a.k.a. CyberTailor) - sort paths in got log -Pp and tog's diff view the same way as in the diff - fix NULL dereference in 'got clone' if server sends an empty pack file - tog: make searches start from the current position in all views - tog: clear search highlighting when reloading view (naddy) - set close-on-exec flag on files opened by main process (suggested by millert) - use 'gotadmin pack' when running tests with GOT_TEST_PACK=1, not 'git repack' - fix bogus "object not found" errors when specified object ID begins with 00 - avoid creation of new temporary files whenever a packed object is read - use time-based rate-limiting for gotadmin progress output - print status output even when 'gotadmin cleanup' finds no objects to remove - tog: fix a scrolling problem when diffing binary files * got 0.64; 2021-11-23 - try only 3 delta base candidates instead of 10 to speed up packing - use up to 128 delta chain elements again; creates smaller packs at same speed - remove unused variables to fix LLVM 13 warnings (naddy) - make 'got rebase' switch the work tree if no commits need rebasing (jrick) - fix man page HTML rendering for command aliases (kn) - let gotadmin find the repository automatically if invoked in a work tree - preserve binary files during updates and merges instead of leaving them empty - allow sorting references by timestamp in tog ref view - add got ref -t option to sort listed references by modification time - add got branch -t option to sort listed branches by modification time - regress: make test operands POSIX compliant (thomas_adam) * got 0.63; 2021-10-17 - fix 'got send -T' regression if tag already exists on server (found by Omar) - fix another regression where a 3-way merge would segfault (naddy) - tog: add Ctrl-n/Ctrl-p for scrolling one line down/up (patch by Omar Polo) - always initialize output parameter "n" of get_line() in diff3.c - set oldo.to in diff3.c's duplicate() even if the file contains no newlines * got 0.62; 2021-10-16 - man pages: document command aliases in tmux(1) style, add tags (kn) - ignore unversioned files while aborting rebase, histedit, merge or operations - let 'got fetch' send all references to the server to avoid redundant downloads - plug memory leaks in got-fetch-pack and got-send-pack - provide lib/Makefile to enable tags file generation (kn) - add support for multiple path arguments to 'got diff' - fix merging of lines inserted at the top of a file (reported by Omar Polo) - display the requested object type in "object not found" error messages - implement 'got diff -c' for diffing commits with optional filtering by path - speed up 'got histedit -l' and 'got rebase -l' - fix merging of files which contain a dot on a line by itself - sort and de-duplicate work tree path command line arguments (suggested by kn) - fix pack index cache element rotation; keep often used entries near the front - use a bloom filter to avoid pointless pack index searches - do not skip ignored directories in 'got status' if they contain tracked files - FreeBSD's ed(1) does not accept "0i"; use the equivalent "1i" instead (naddy) - speed up pack file creation a little by caching raw objects - limit delta chain length in newly created pack files to 32 deltas - while packing, store encoded deltas in temporary files instead of in memory - sync with OpenBSD parse.y (naddy) - make 'gotadmin indexpack' unveil the repository read/write, not read-only - plug memory leak in an error path of read_packed_object() * got 0.61; 2021-10-03 - fix list of 'got status' options in the got.1 man page - tog: use sched_yield(2) for better portability (patch by Quentin Rameau) - fix histedit_no_op test which was failing randomly (patch by Lucas) - fix 'got send' with tree objects which contain symlinks (reported by Omar) - tog: show parent commit IDs of merge commits in the diff view - add a 'got merge' command for creating merge commits - fix 'got update' of an added + obstructed file - mark some function parameters 'const', as they should be (patch by Omar Polo) - add 'static' qualifier to local functions in got-read-pack (again Omar Polo) - fix some integers that had a slightly wrong type (again by Omar Polo) - match printf specifiers and (cast) types for portability (naddy) - don't change bad symlinks into regular files during merges - handle errno variations upon open(2) failure with O_NOFOLLOW for portability - garbage-collect unused "dist" target from subdirectory Makefiles (naddy) - match the unsigned char type used by the zlib interface (naddy) - fix unsigned/signed char mismatch in parse.y (naddy) - fix 'got fetch' downloading too many objects in some cases - interrupt 'got rebase' upon missing/unversioned/not-deleted files - interrupt 'got histedit' upon missing/unversioned/not-deleted files - pull in a type fix from the OpenBSD parse.y template (naddy) - explicitly set the default branch name after 'git init' in regress tests - add histedit -e option which runs the 'edit' script command for every commit - skip ignored directories during 'got status' disk crawl * got 0.60; 2021-09-15 - fix another instance of 'got send' sending branches the server already has - make 'got send' regression tests run 'git fsck' on all involved repositories - shell code fixes in regress tests for portability (naddy) * got 0.59; 2021-09-14 - fix copy-pasto in got.conf man page - add -q quiet mode to checkout and update (tracey) - make 'got send' send commits which are referenced only by tags (found by Omar) - add -S option to 'got status' for suppressing certain status codes (tracey) - make 'got checkout' display the checked out reference and commit ID - make 'got update' display the worktree's branch name upon success * got 0.58; 2021-09-11 - tog: support navigating to first/last line of tree and ref views (naddy) - tog: jump directly to first log item instead of traversing the list (naddy) - tog: when jumping to bottom of the log view, go from tail backwards (naddy) - make "got branch -d" print reference name and value (naddy) - move code duplicated by got-send-pack and got-fetch-pack to common files - assert against accidentally overflowing argv[] in got_dial_ssh() (naddy) - make 'gotadmin info' display separate send/fetch URLs if they differ - fix a null-pointer deref in 'got fetch -d' (reported by Omar Polo) * got 0.57; 2021-09-03 - remove superfluous strdup(3) from parse.y files (Martin Vahlensieck) - adapt regress tests which handle UTC dates (naddy) - make 'got send' actually heed branch {} options in got.conf(5) as intended - disable ignore lists during status walks used by rebase and histedit - tog: add support for navigating to first/last line of blame view (naddy) - fix bogus error when 'got cherrypick' merged changes into locally added file - remove ancestry checks to make 'got cherrypick' and 'got backout' run faster - limit checks for merge conflicts to files affected by the merge to be faster - fix 'got send' adding too many objects to the pack file in some cases * got 0.56; 2021-08-30 - prevent a race where 'gotadmin cleanup' deletes concurrently created objects - plug a small memory leak in tog's show_diff_view() function - fix a use-after-free in get_changed_paths() in got and tog - use less memory allocations when formatting log messages - make got_deltify() rellocate the deltas array less often - plug a memory leak in an error path of got_deltify() - fix miscalculation of the final pack file size reported by got_pack_create() - fix the error message shown when the server sends a bad ref line - prevent NULL deref in got-fetch-pack if server does not announce capabilities - add a missing bounds-check in got-fetch-pack when parsing server response - fix, again, use of POSIX [ s1 = s2 ] syntax instead of [ s1 == s2 ] (naddy) - add 'got send' for sending changes to remote repositories (with naddy, tracey) - allow deletion of refs/remotes/ branches with got branch -d - add missing "return 1" to failure handling in the regress scripts (naddy) - make realloc_ids() malloc-like and do not overallocate (naddy) - fix seek to incorrect offset in the delta base when creating deltas - use gmtime_r(3) to display timestamps in UTC as intended (found by naddy) - add keys for navigating to first/last item of tog log and diff views (jasper) * got 0.55; 2021-07-26 - display recovery steps in the lonely pack index error message - fix double-free that occurred upon exit from 'tog tree'; found by naddy - don't scan pack index offsets for large values if pack file is < 2GB - new -X option for removing backups created by got rebase and got histedit - add 'got fetch -X' option for deleting references created by 'got fetch' - make 'got ref -d' print reference name and value like the new -X options do * got 0.54; 2021-07-08 - fix imsg header includes in pack_create.c - explicitly include endian.h for be32toh() in repository_admin.c (naddy) - switch from SIMPLEQ to equivalent STAILQ macros (naddy) - fix logic error in gotweb navigation for commits, briefs, and tags (tracey) - fix bugs where files skipped by 'got update' could not be updated again - fix out-of-bounds access in 'gotadmin pack' - fix unintended redundant recallocarray() calls done by 'gotadmin pack' - cache object type in memory to speed up packing of objects referenced by tags - fix, again, use of POSIX [ s1 = s2 ] syntax instead of [ s1 == s2 ] (naddy) - new 'gotadmin cleanup' command for removing unreferenced loose objects - handle pack index files which lack a corresponding pack file - make 'got add' always require the -I option in order to add ignored files - write lines instead of just one character at a time in diff_output_lines() - verify object ID checksums while loose objects are being accessed * got 0.53; 2021-06-22 - do not update symlinks which are already up-to-date - add a gotadmin utility with info, pack, indexpack, and listpack commands - fix 3-way merge of files which lack a final \n - make double-quotes appear in rendered got.1 man page as intended (Nam Nguyen) - gotweb: render error page instead of returning error 500 (tracey) - avoid an error in tog(1) while the terminal window is being resized - plug a memory leak in got_ref_list_free() - catch invalid reference names passed to 'got ref -l' - fix a memory leak in dial_git() (naddy) - fix unrelated changes being merged by got cherrypick/backout/rebase/histedit - go back to Patience diff for merging during cherrypick/backout/histedit/rebase - fix file descriptor leak in got_repo_close() (tracey) - fix hang in commit regress test if $VISUAL is set in the environment (tracey) - use socketpair(2) instead of pipe(2) for better portability to Linux - make it possible to profile gotweb and document how profiling works - fix memory and fd leaks in got_pack_stop_privsep_child() (tracey) - fix bogus 'permission denied' error when a file at work tree root is removed - port packfile creation code over from git9 - new -I option for 'got status' to show files which match an ignore pattern * got 0.52; 2021-04-05 - fix error checking in dial_ssh() - increase pack index cache size from 16 to 64 to improve performance - fix off-by-one in got_repo_cache_pack() causing the wrong pack to be evicted - cap pack file cache size at 1/8 of the current open file descriptor limit - when reading a pack index byte-swap fields at compile-time where possible - diff: reduce duplicate code (kn) - fix "mandoc -T lint" WARNINGS and ERRORS, add missing word (kn) - fix open file descriptor leak in error path of read_object_header_privsep() * got 0.51; 2021-03-23 - deltify.c: explicitly include for be64toh() - rebase/histedit -l: error out if no backups for the requested branch exist - fix use of uninitialized stat buffer during status crawl (found by naddy) * got 0.50; 2021-03-22 - use Myers diff instead of Patience diff when merging files with diff3 - port file deltification code from git9; a prerequisite for writing pack files - implement raw object data access; another prerequisite for writing pack files - improve got log -x documentation (jrick) - improve got ref -d documentation - fix strftime(3) short buffer checks (jrick) - ensure that old commits remain referenced after rebase and histedit - new got rebase -l option which lists past rebase operations - new got histedit -l option which lists past histedit operations * got 0.49; 2021-02-11 - implicitly mark all files in work tree as up-to-date after 'got integrate' - tog: fix behaviour if 'n' is pressed before search is started (found by naddy) - in 'got clone', allow -l together with -q, for consistency with 'got fetch' - add 'got commit -F' option to commit with a log message stored in a file - simplify error message shown when 'got rebase' has nothing to do - tolerate tag objects which lack tagger timestamp information (found by naddy) - got info: fix a pasto in an error message (naddy) - include remote branches in the output of 'got branch -l' (suggested by helg) * got 0.48; 2021-01-22 - use POSIX [s1 = s2] syntax instead of [s1 == s2] (patch by Ryo ONODERA) - tog log: terminate author field at '>' in case there is no '@' (naddy) - replace fparseln(3) with getline(3), for better portability (naddy) - make 'got clone' pin the fetched branch in got.conf(5) - allow the 'got fetch' -l option together with the -q option - store branches passed via 'got clone -b' in got.conf(5) and git-config(1) - work around spurious ACK responses from git servers in got-fetch-pack - add a 'fetch-all-branches' configuration setting to got.conf(5) - add a 'reference' directive to remote repositories in got.conf(5) - fix 'got up -c commit path' deleting unrelated files (found by Timo Myyrä) - fix 'tog blame' segfault upon empty input file (found by naddy) - let 'got clone' write gitconfig directives that match the generated got.conf - fix a use after free in got_worktree_close() (naddy) - make fclose(3) failure checks consistent; check 'fclose() == EOF' everywhere - make close(2) failure checks consistent; check 'close() == -1' everywhere - fix missing close(2) error check in got_worktree_close() * got 0.47; 2020-12-27 - update got.1 CAVEATS section; prompted by feedback from otto@ - fix assignment to wrong pointer in got_ref_dup() - fix performance on repositories with many references (e.g. freebsd src.git): o implement an object ID map for reference lists o use reflist object id maps in got log, tog log, and tog diff (with naddy) o switch reflist to TAILQ; insert elements more efficiently for sorted input * got 0.46; 2020-12-21 - reset tog blame view's scroll position if line count shrinks too much (naddy) - replace unprintable characters with '.' before passing them to curses (naddy) - allow editing of log message comments with 'got histedit' - implicitly mark all files in work tree as up-to-date after rebase/histedit - add fd field to got_repository, modify got_packidx_open to use fds (yzhong) - more size_t for loop indices to avoid signedness warnings; by emaste@freebsd - fix path existence check in got_object_tree_path_changed (reported by jrick) - fix parsing of tag objects which lack a tag message; found in u-boot.git repo - do not mix up repos if tog's -r option is used in a work tree (with naddy) - avoid signed vs unsigned comparisons in fetch.c (with millert) - introduce got_custom_error array to support multiple errors in flight - switch to strerror_r(3) in error.c for thread-safety * got 0.45; 2020-12-13 - new diff implementation from git.gameoftrees.org/diff.git (with neels) - use Patience diff algorithm with fallback to Myers diff - new blame algorithm which compares commit N-1 to N (with neels) - handle binary files in got/tog diff commands; add -a options to force text - consistently label removed files as "/dev/null" in diff headers - prevent potential fclose(NULL) in error path of diff_blobs() - use size_t for loop indices to avoid signedness warnings (by emaste@freebsd) - in tests, replace echo with printf and stop option processing via "--" (naddy) - fix test failure of test_tree_submodule_of_same_repo for packed repos (yzhong) - add fd to got_worktree, modify got_fileindex_entry_update to use fds (yzhong) - add histedit -f flag for folding shortcut (jrick) - prevent log message loss of folded commits during histedit - tog: plug two memory leaks in draw_file() - tog: show current/total line numbers in diff view header - tog: highlight matched search terms in diff and blame views - tog: call pthread_cond_destroy(cond) just once when closing log view (naddy) - tog: reset diff view's scroll position if diff context shrinks too much - tog: make tog diff accept reference and tag arguments; add -w and -C options - tog: new 'tog ref' subcommand which displays references in the repository - tog: fix entry selection when moving to the parent in tree view (naddy) - tog: fix page-down/page-up scrolling in the tree view (with naddy) - tog: trim redundant parameters from many functions, and tidy up code (naddy) - tog: log view now requests more commits when the window expands (naddy) - tog: call pledge(2) directly in main() instead of per-command - tog: fix bug on FreeBSD where pressing 'q' in a child view caused tog to exit - tog: fix move to next/prev commit in diff view if log is not displayed (naddy) - tog: make ^L in the log view stick to branches/tags selected via -c option - tog: make tree view keep track of branches/tags specified via -c - tog: fix crashes when the log view reloads displayed data - tog: resize events go to child views as well as parent views (found by naddy) - tog: move the tree view's selection cursor up if terminal shrinks too much - tog: fix display of lines that end in "\r\n" (problem found by jrick) - tog: accommodate newer ncurses where panel_userptr() returns const (naddy) - tog: use getline(3) instead of fparseln(3) for better portability * got 0.44; 2020-11-10 - detect unknown repository format extensions such as Git's sha256 extension - prevent a NULL dereference if 'got log -p' runs against a root commit - fix permissions mode bits for fetched pack files; patch by Alisdair MacLeod - use fchmod(2) instead of chmod(2) (semarie, naddy) - initialize sb.st_mode after stat(2) failure in got_worktree_resolve_path() - clear staged file type in file index entries whenever staged status is cleared - unlink temporary files in error cases of install_blob() - fix replacing a file with a symlink during merges; problem found by jrick - fix parsing of 'ON' keyword in gotweb parse.y; patch by Martin Vahlensieck - remove unused variable in gotweb.c; patch by Martin Vahlensieck * got 0.43; 2020-10-21 - do not treat the -h and -V flags as errors (naddy) - allow regress test data to be stored in locations other than /tmp - unveil repositories read-write when adding tags with 'got tag' - rewrite test argument parsing with the POSIX getopts shell built-in (naddy) - in tests, accommodate ls -l implementations that print "total 0" (naddy) - fix a bug where 'got status' showed an unchanged empty file as changed - handle non-const basename(3) and dirname(3) for POSIX compatibility - properly handle nonexistent remote repository names given to 'got fetch' * got 0.42; 2020-09-30 - add "branch" keyword to got.conf which specifies a list of branches to fetch - rework got's commit-time log message modification check - fix potential type mismatches between format specifiers and arguments (naddy) - prefer the BSD extension to reset getopt over the GNU one (naddy) - fix 'bad path' error from 'got clone' by unveiling the repository path again * got 0.41; 2020-09-25 - make 'got ref -d' delete both loose and packed representations of the ref - make dangling symbolic references show up in 'got ref -l' - fix handling of slashes in got.conf repository paths (found by naddy) - hide remote HEAD refs in gotweb in order to match got and tog output - make 'got histedit' collapse folded add+delete operations (found by jrick) - fix matching the first object ID listed in a pack index (found by jrick) - let 'got clone' try to connect to server before creating repository contents - fix default branch name written to Git config file by 'got clone' - allow an interrupted 'got clone' to be resumed by 'got fetch' - handle failed connection attempts to git:// servers (patch by jrick) - make gotweb work in subdirectories of the web space (found by uwerler) * got 0.40; 2020-09-21 - do not rely on to pull in (naddy) - remove unused #includes from the new got-read-gotconfig/parse.y (naddy) - document our default choice of text editor (suggested by Ricky Cintron) - in tests, replace ksh syntax with POSIX arithmetic expressions (naddy) - fix got.conf overriding GOT_AUTHOR even if no author is set in got.conf - in tests, expand arguments in shell script for POSIX compatibility (naddy) - fix crash in got_free_gotconfig() - in cmd_checkout() handle basename(3) modifying its argument for portability - print newline to clear the bottom line when tog exits (naddy) - install got-read-gotconfig into gotweb's chroot environment * got 0.39; 2020-09-14 - add -q option to tests for quiet output and use it for 'make regress' - document how to re-create a corrupt or missing file index in got-worktree(5) - fix some memory leaks in tog (tracey) - add workaround for a performance issue when 'tog diff' shows a large diff - add -s option to 'got status' which acts as a status code filter - add -s option to 'got remove' which deletes files in a particular status - plug a memory leak in got_privsep_recv_tree() in error case - in got_object_commit_get_logmsg(), handle log messages which lack '\n' - do not rely on to pull in (naddy) - use POSIX standard endian functions and include (naddy) - add got.conf(5) configuration file - use modern POSIX timestamp fields in struct stat (naddy) - use plain write() in place of dprintf() with a pre-formatted string (naddy) - stop including directly (naddy) - switch regress function declarations from ksh to POSIX shell syntax (naddy) * got 0.38; 2020-08-02 - add support for managing symbolic links under version control - new -S option for 'got commit' and 'got stage' to skip symlink safety checks - add a 'got info' command which displays work tree meta-data - display more context in "no such entry found in tree" error messages - fix spurious 'got cherrypick' error with a path prefix and an empty tree - fix committing file additions from a work tree with a path prefix - fix build error with clang 10 due to missing for-loop block grouping (naddy@) - make 'got log' -R and -P options work in combination * got 0.37; 2020-07-23 - cope with directory entries returned from readdir(3) with type DT_UNKNOWN - fix merging with files that do not contain a newline character - heed .{cvs,git}ignore if a path is given on the 'got status' command line - plug memory leak that occurred when files were deleted during checkout/update - add new parse.y code for future use and restructure gotweb's parse.y - fix an error return in gotweb (by Martin Vahlensieck) - document how to use commit messages prepared in a file (by Scott Bennett) - make 'got/tog tree' show symlink targets like 'ls -lF' does: link@ -> target - allow creation of commits which carry unmodified submodule tree entries along - some error, usage, and progress message improvements * got 0.36; 2020-05-05 - fix "no such entry found in tree" error with got log -p and an added path - show a list of paths changed in a commit with 'got log -P' and in tog - prevent false positive tree entry differences due to bogus file mode bits - write directory tree entry mode bits in the same way as Git does (0040000) * got 0.35; 2020-04-25 - don't pass "-p 22" to ssh; makes ssh_config's Port option work (semarie) - fix a file index corruption problem with 'got rebase' (found by tracey) - fix 'got log -r' loading refs from the wrong repo if invoked in a work tree - filter out "remotes/*/HEAD" references in got/tog log output * got 0.34; 2020-04-19 - make use of new convenience API functions of kcgi 0.12 in gotweb - make 'got update' skip conflicted files (prevents loss of local changes) - show a summary of conflicts and related problems after updating/merging files - add 'got log' -x option to stop logging when a specific commit was traversed - add 'got log' -R option to reverse commit display order - clarify wording in got.1 related to local changes/commits/branches - show bad object ID in "object not found" error messages where possible * got 0.33; 2020-04-14 - normalize tree entry modes to 0100644 or 0100755 when writing tree objects - fix "searching..." displayed in tog log view while merely scrolling down - in got.1, clarify how 'got update' deals with local (aka uncommitted) changes * got 0.32; 2020-03-28 - be nice to unaware users who attempt to use got commands in a Git work tree - show 'searching...' during 'tog log' search even if no new commits are loaded - display "no matches found" if no commit matches a 'tog log' search - display "no more matches" if 'tog log' search cannot find any more matches - make 'tog log' consistently scroll a page upon page-down key (found by naddy) - make 'got fetch' create or restore remote HEAD reference if it is missing - make 'got fetch -d' delete branches from both refs/heads and refs/remotes * got 0.31; 2020-03-25 - take status line into account during page up/down in 'tog log' (naddy) - make 'got tree' use the current branch if invoked in a work tree (tracey) - compute pack file's checksum during download and check it in got-fetch-pack - make got-index-pack compute and verify the pack file's checksum as well - stop verifying pack file checksum in the main process during clone/fetch - fix bogus 'reference HEAD not found' error (reported by Matthias aka _xhr_) - make 'got clone' create refs/remotes/origin/HEAD, as 'git clone' does - make 'got fetch' handle updates to refs/remotes/*/HEAD * got 0.30; 2020-03-22 - add support for git and git+ssh network protocols (patch by ori@) - add 'got clone' and 'got fetch' commands - don't error out if rebase sees no merged paths; elide the commit instead - prevent 'got commit' from committing empty sub-directories (found by tracey) - allow limiting the output of 'got ref -l' to a single ref or a namespace - add -c option to 'got ref' which now expects just one argument after options - plug a memory leak in got-read-pack - remove 'Next' link from tags on gotweb summary page if no tags exist (tracey) * got 0.29; 2020-03-06 - trim directories in got remove -R (tracey) - prevent commits from being listed more than once in a histedit script - fix histedit 'rebase commit ID mismatch' error when splitting a commit - be helpful when users try to check out work trees without a known branch - map 'tog path' to 'tog log path' if possible (requested by mpi) - when "bad path" errors occur always show the path in question - show merged commit ID upon merge conflict during rebase and histedit * got 0.28; 2020-02-25 - improve man page documentation of rebase and histedit - disallow 'got rebase' while a histedit operation is in progress - switch 'got tag' commit argument to a new -c option - let 'got branch' switch and update the work tree - improve documentation of -r flags in tog man page (naddy) - add 'got histedit -m' option which makes it easy to edit log messages - switch 'tog diff' repository path argument to a new -r option (naddy) - fix 'tog diff object1 object2' when run inside a work tree (naddy) - document semantics of got log and tog log path arguments - add ^B/^F key bindings (page up/down) to 'tog blame' and 'tog tree' (naddy) - disable compiler warnings in release builds to avoid -Werror build breakage * got 0.27; 2020-02-21 - fix gotweb build with -O2 on sparc64 (tracey; reported by kmos) - add next/prev navigation to gotweb commit briefs and commits pages (tracey) - add new gotweb tags page and ability to navigate all tags (tracey) - ensure gotweb's libexec helpers inherit build flags from parent directories - allow 'got ref' to manipulate refs which do not have a slash in their name - add an optional path argument to 'tog tree' - fix misplaced tog search prompt in split-screen views * got 0.26; 2020-02-17 - initial release of gotweb(8), a repository server for web browsers (tracey) - fix a segfault in 'got backout' (tracey, reported by semarie) - switch 'tog tree' repository path argument to a new -r option - fix 'got blame' and 'tog blame' on files added on worktree's current branch - enable searching in tog diff view with the '/' key (tracey) - ignore EROFS during checkout for repositories on read-only filesystems - do not open log message editor if there are no changes during 'histedit -c' - display branch name and first commit to be edited at top of histedit script - fix bug where 'got revert -R' failed on added subtrees - fix bug where 'got log PATH' failed to map PATH into the repository - make 'tog log' show linear history by default; add -b option and B key - make 'got log' show linear history by default; remove -f and add -b option - do not display unversioned files during 'got revert -R' - tweak default colors for directories and symlinks in 'tog tree' - sleep for one nanosecond after syncing the file index to disk - fix 'tog log -c' with tags * got 0.25; 2020-01-14 - fix suspending and resuming tog with Ctrl-Z and fg (reported by naddy@) - fix 'tog tree' usage displayed in error case (patch by naddy@) - support Git-style "lightweight" tags as arguments for 'got diff' - handle Git-style "lightweight" tags in got tag -l - make got and tog accept a --version argument (prompted by tedu@) - add -E option to 'got checkout' allowing use of a non-empty work tree path - make 'tog log PATH' fail when a non-existent path is specified - fix out of bounds access (patch by Martin ) - fix switching to tog's tree view when logging a path (reported by naddy@) * got 0.24; 2020-01-08 - do not open and close pack index files needlessly - fix 'got log' and 'tog log' performance issue when lots of tags exist - do history traversal in got-read-pack to improve 'got blame' performance - plug memory leaks in got-read-commit, got-read-tree, and got-read-pack - fix reading reference deltas with GOT_PACK_NO_MMAP builds - disable got-read-pack's delta cache in GOT_NO_OBJ_CACHE builds - make it possible to run regress tests with packed repositories - more portable string comparison in Makefile.inc (patch by Edgar Pettijohn) - prevent rebase with an out-of-date work tree - make 'got checkout' and 'got update' work with read-only repositories * got 0.23; 2019-12-16 - prevent status crawl from racing with paths changing in the filesystem - add -k option to 'got remove' to keep files on disk (Tracey Emery) - add -R option to 'got remove' for recursive deletion (Tracey Emery) - add -I option to 'got add' to disregard ignore patterns (Tracey Emery) - show numeric dates in ISO-8601/xkcd-1179 format in 'tog log' and 'got blame' * got 0.22; 2019-12-01 - allow empty diff context context (-C0) in 'got diff' (kn@) - add '-s search-pattern' option to 'got log' (kn@) - forward rebased branch if there are no commits to rebase, instead of error - parse remote repository URLs from gitconfig - actually forbid new reference names with a leading '-', as intended - convert tree entries from SIMPLEQ to an array for better performance - compile static binaries in PROFILE build * got 0.21; 2019-11-25 - add -R option to 'got add' for recursive addition (patch by Tracey Emery) - reduce the amount of memcpy() and strdup() while parsing tree entries - fix tog display issue caused by Tab in commit messages; reported by mpi@ - cache delta data buffers in an LRU cache to improve performance - add -c option to 'got branch', replacing the optional second argument * got 0.20; 2019-11-09 - fix reading pack files larger than 2GB - try not to hide errors from helper programs when got exits - use less empty padding space after author name in 'tog log' - rename 'got init' and 'got import' default branch to "main" (patch by kmos@) * got 0.19; 2019-11-08 - add optional colorized display mode to tog - make 'tog log' show abbreviated commit IDs if the window is large enough - fix staging of multiple files with -p - show commit date's century in 'got blame' output (patch by Tracey Emery) * got 0.18; 2019-10-21 - always show the input path when realpath(3) returns an error - preserve log message when an error occurs during commit, tag, or import - ignore empty files in refs directory instead of throwing errors - show file mode differences (executable bit) when diffing in-repository trees - fix handling of executable-bit changes during update, commit, and status - improve tog's responsiveness after loading hundreds of thousands of commits - fix tog performance bug which made searching through commits very slow - add 'got integrate' command for merging a branch back to its parent branch - show content from the merge-base file in 3-way merge conflicts, if available - improved indication of 3-way merge inputs in conflict marker labels - handle read errors in got_packidx_init_hdr (found by jj@ with scan-build) - remove worklist code; it was only used to unlink files already unlinked - show bad reference names in error messages to make such errors more clear - add -w (ignore whitespace) option to 'got diff' - improved coding style and error handling in diff3 code * got 0.17; 2019-10-06 - make 'got branch' without args show work tree's branch (requested by benno) - show temporary branch in 'got branch -l' during rebase and histedit - refresh references when 'tog log' view is refreshed with Ctrl+L - make 'got status' read .gitignore files; support **/ and /**/ in patterns - handle empty trees during 'import' and 'checkout' (issue reported by sthen) - show only whitelisted commit headers in 'got log' (semarie) - properly handle getline(3) return type as ssize_t (hiltjo) * got 0.16; 2019-09-23 - replace fgetln(3) with getline(3) for portability (patch by Steven McDonald) - fix implicit time.h includes (patch by Steven McDonald) - fix tiny memory leaks and other minor bugs found by jj@ with scan-build - fix missing error checks (found by jj@ with scan-build and by Steven McDonald) - avoid a couple of potential NULL derefs (found by jj@ with scan-build) - fix cosmetic display issues involving \n and TABs in tog(1) * got 0.15; 2019-09-08 - use author name/email from ~/.gitconfig if GOT_AUTHOR is not set - obtain repo format version and commit author name/email from .git/config - fix line-wrap for lines spanning the terminal in tog diff view - make 'got status' ignore inaccessible directories (reported by semarie) - unstage may need to write to repository; fix unveil(2) call accordingly - fix modified files not shown by 'got status' after committing staged changes * got 0.14; 2019-09-03 - fix tag_list test failure on single-day-digit dates (patch by Evan Silberman) - prevent theoretical double-free with non-OpenBSD asprintf (found by jasper@) - fix NULL deref in got_error_from_errno via got_error_uuid (found by jasper@) - make tog release its work tree lock before going into main loop - 'got stage' writes to repository, fix unveil(2) call accordingly * got 0.13; 2019-08-30 - fix several possible leaks, use after frees, and NULL derefs (hiltjo) - tog: mbs2ws: fix sizeof of element for memory allocation (hiltjo) - fix deletion of branches stored in packed-refs - fix 'got log path' in a work tree with a path prefix (with Evan Silberman) * got 0.12; 2019-08-26 - add support for path arguments to 'got cat' - make 'got log -p path' display patches for the specified path only - allow creating branches based on commit IDs - prevent deletion of the work tree's current branch - detect and ignore Git submodules - indicate non-existent path arguments in 'got status' - make 'got diff' error for non-existent path arguments - make 'got tag -l' list tags by time stamp in descending order - fix reading pack index files with large offsets (patch by Hiltjo Posthuma) * got 0.11; 2019-08-23 - add 'got tag' command - add 'got cat' command - support quick cancellation in 'tog blame' view - fix search prompt location in split-screen tog views * got 0.10; 2019-08-21 - fix and simplify blame algorithm * got 0.9; 2019-08-19 - fix blame bug where lines were annotated with wrong commit - man page spelling fixes (patch by Hiltjo Posthuma) - fix uninitialized 'editor' variable (found by Hiltjo Posthuma) - make 'got revert' ignore unversioned files instead of aborting (semarie@) - fix "last commit cannot be folded" histedit check with reordered commits * got 0.8; 2019-08-16 - write tree entries the way git likes it to prevent git index corruption - make 'got blame' show line numbers, dates, and author names - add GOT_LOG_DEFAULT_LIMIT env var for setting a got log -l default * got 0.7; 2019-08-13 - properly parse timestamps in commit objects as UTC (patch by Hiltjo Posthuma) - strip Git GPG signatures from log messages - fix regression: don't try to parse "lightweight" tags as real tag objects * got 0.6; 2019-08-13 - 'got log' and 'tog log' now display tags in addition to branch references - 'got ref' can now be used to create symbolic references - use instead of (patch by Thomas Klausner) - fix crash if 'got rebase' has no commits to rebase (with semarie@) - annotate symlinks with @ in 'got tree' and 'tog tree' * got 0.5; 2019-08-12 - fix blame with single-commit history and with files without \n - fix crashes in tog when blame returns no results on a file (found by otto@) - man page improvements (bentley@) * got 0.4; 2019-08-11 - add support for tag objects to 'got diff' - fix tog log -r option (patch by semarie@) - fix use of potentially out-of-date errno values (patch by Hiltjo Posthuma) - fix getline(3) return value check (patch by Hiltjo Posthuma) - use Oo/Oc/Op instead of plain brackets in man pages (patch by bentley@) - fix spurious failures of test_revert_patch_one_change due to race condition * got 0.3; 2019-08-10 - fix bug where 'revert -p' would delete all lines following a reverted change - fix merge bug inherited from OpenRCS, affecting lines with leading . - fix man page installation during manual 'make install' from plain tarball * got 0.2; 2019-08-09 - improve error message if helper binaries fail to unveil(2) - add support for tags to -c options of some got commands - attempt to reject GOT_AUTHOR values without an email address because git is unable to parse resulting commit objects - fix build on OpenBSD/sparc64 (gcc) * got 0.1; 2019-08-09 initial release; see git repository history for changes up to this point got-portable-0.119/configure0000775000175000017500000132611315066537205011535 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.72 for got-portable 0.119. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case e in #( e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else case e in #( e) exitcode=1; echo positional parameters were not saved. ;; esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else case e in #( e) as_have_required=no ;; esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi ;; esac fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed 'exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and thomas@xteddy.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi ;; esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' t clear :clear s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='got-portable' PACKAGE_TARNAME='got-portable' PACKAGE_VERSION='0.119' PACKAGE_STRING='got-portable 0.119' PACKAGE_BUGREPORT='thomas@xteddy.org' PACKAGE_URL='' ac_unique_file="lib/rcsutil.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= enable_option_checking=no ac_func_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS CVG_ENABLED_FALSE CVG_ENABLED_TRUE AM_LDFLAGS AM_CFLAGS AM_CPPFLAGS libncurses_LIBS libncurses_CFLAGS LIBNCURSES_LIBS LIBNCURSES_CFLAGS LIBPANELW_LIBS LIBPANELW_CFLAGS libtls_LIBS libtls_CFLAGS LIBTLS_LIBS LIBTLS_CFLAGS libcrypto_LIBS libcrypto_CFLAGS LIBCRYPTO_LIBS LIBCRYPTO_CFLAGS libmd_LIBS libmd_CFLAGS LIBMD_LIBS LIBMD_CFLAGS libbsd_LIBS libbsd_CFLAGS LIBBSD_LIBS LIBBSD_CFLAGS zlib_LIBS zlib_CFLAGS ZLIB_LIBS ZLIB_CFLAGS libuuid_LIBS libuuid_CFLAGS LIBUUID_LIBS LIBUUID_CFLAGS LIBEVENT_LIBS LIBEVENT_CFLAGS libevent_LIBS libevent_CFLAGS LIBEVENT_CORE_LIBS LIBEVENT_CORE_CFLAGS libutil_LIBS HAVE_IMSG_FALSE HAVE_IMSG_TRUE HAVE_LINUX_LANDLOCK_FALSE HAVE_LINUX_LANDLOCK_TRUE HOST_DRAGONFLYBSD_FALSE HOST_DRAGONFLYBSD_TRUE HOST_OPENBSD_FALSE HOST_OPENBSD_TRUE HOST_NETBSD_FALSE HOST_NETBSD_TRUE HOST_DARWIN_FALSE HOST_DARWIN_TRUE HOST_LINUX_FALSE HOST_LINUX_TRUE HOST_FREEBSD_FALSE HOST_FREEBSD_TRUE PLATFORM libresolv_LIBS HAVE_B64_FALSE HAVE_B64_TRUE HAVE_CLOSEFROM_FALSE HAVE_CLOSEFROM_TRUE HAVE_SIPHASH_FALSE HAVE_SIPHASH_TRUE HAVE_SETPROCTITLE_FALSE HAVE_SETPROCTITLE_TRUE LIBOBJS HAVE_GETOPT_FALSE HAVE_GETOPT_TRUE HAVE_SHA2_FALSE HAVE_SHA2_TRUE PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG RANLIB ac_ct_AR AR YFLAGS YACC LN_S CPP GITWRAPPER_LIBEXEC_PATHC GOTD_EMPTY_PATHC subdirs host_os host_vendor host_cpu host build_os build_vendor build_cpu build am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC GOT_RELEASE am__xargs_n am__rm_f_notfound AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_cvg with_gotd_empty_path with_gitwrapper_git_libexec_path ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP YACC YFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR LIBEVENT_CORE_CFLAGS LIBEVENT_CORE_LIBS LIBEVENT_CFLAGS LIBEVENT_LIBS LIBUUID_CFLAGS LIBUUID_LIBS ZLIB_CFLAGS ZLIB_LIBS LIBBSD_CFLAGS LIBBSD_LIBS LIBMD_CFLAGS LIBMD_LIBS LIBCRYPTO_CFLAGS LIBCRYPTO_LIBS LIBTLS_CFLAGS LIBTLS_LIBS LIBPANELW_CFLAGS LIBPANELW_LIBS LIBNCURSES_CFLAGS LIBNCURSES_LIBS' ac_subdirs_all='template' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: '$ac_option' Try '$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF 'configure' configures got-portable 0.119 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, 'make install' will install all the files in '$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify an installation prefix other than '$ac_default_prefix' using '--prefix', for instance '--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/got-portable] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of got-portable 0.119:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-cvg EXPERIMENTAL: cvg - cvs-like-git Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gotd-empty-path gotd empty path --with-gitwrapper-git-libexec-path git libexec path for gitwrapper Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor YACC The 'Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: 'bison -y', 'byacc', 'yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of '-d' given by some make applications. PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path LIBEVENT_CORE_CFLAGS C compiler flags for LIBEVENT_CORE, overriding pkg-config LIBEVENT_CORE_LIBS linker flags for LIBEVENT_CORE, overriding pkg-config LIBEVENT_CFLAGS C compiler flags for LIBEVENT, overriding pkg-config LIBEVENT_LIBS linker flags for LIBEVENT, overriding pkg-config LIBUUID_CFLAGS C compiler flags for LIBUUID, overriding pkg-config LIBUUID_LIBS linker flags for LIBUUID, overriding pkg-config ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config ZLIB_LIBS linker flags for ZLIB, overriding pkg-config LIBBSD_CFLAGS C compiler flags for LIBBSD, overriding pkg-config LIBBSD_LIBS linker flags for LIBBSD, overriding pkg-config LIBMD_CFLAGS C compiler flags for LIBMD, overriding pkg-config LIBMD_LIBS linker flags for LIBMD, overriding pkg-config LIBCRYPTO_CFLAGS C compiler flags for LIBCRYPTO, overriding pkg-config LIBCRYPTO_LIBS linker flags for LIBCRYPTO, overriding pkg-config LIBTLS_CFLAGS C compiler flags for LIBTLS, overriding pkg-config LIBTLS_LIBS linker flags for LIBTLS, overriding pkg-config LIBPANELW_CFLAGS C compiler flags for LIBPANELW, overriding pkg-config LIBPANELW_LIBS linker flags for LIBPANELW, overriding pkg-config LIBNCURSES_CFLAGS C compiler flags for LIBNCURSES, overriding pkg-config LIBNCURSES_LIBS linker flags for LIBNCURSES, overriding pkg-config Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF got-portable configure 0.119 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 ;; esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR # ------------------------------------------------------------------ # Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR # accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR. ac_fn_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack as_decl_name=`echo $2|sed 's/ *(.*//'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { #ifndef $as_decl_name #ifdef __cplusplus (void) $as_decl_use; #else (void) $as_decl_name; #endif #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_check_decl # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else case e in #( e) eval "$4=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) eval "$3=yes" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 printf %s "checking for int$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main (void) { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else case e in #( e) break ;; esac fi done ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 printf %s "checking for uint$2_t... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if eval test \"x\$"$3"\" = x"no" then : else case e in #( e) break ;; esac fi done ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (void); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else case e in #( e) eval "$3=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else case e in #( e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status ;; esac fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by got-portable $as_me 0.119, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See 'config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (char **p, int i) { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* C89 style stringification. */ #define noexpand_stringify(a) #a const char *stringified = noexpand_stringify(arbitrary+token=sequence); /* C89 style token pasting. Exercises some of the corner cases that e.g. old MSVC gets wrong, but not very hard. */ #define noexpand_concat(a,b) a##b #define expand_concat(a,b) noexpand_concat(a,b) extern int vA; extern int vbee; #define aye A #define bee B int *pvA = &expand_concat(v,aye); int *pvbee = &noexpand_concat(v,bee); /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' /* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif // See if C++-style comments work. #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Work around memory leak warnings. free (ia); // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' /* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" as_fn_append ac_header_c_list " vfork.h vfork_h HAVE_VFORK_H" as_fn_append ac_func_c_list " fork HAVE_FORK" as_fn_append ac_func_c_list " vfork HAVE_VFORK" as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H" as_fn_append ac_func_c_list " getpagesize HAVE_GETPAGESIZE" # Auxiliary files required by this configure script. ac_aux_files="ar-lib config.guess config.sub compile missing install-sh" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}/etc" # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else case e in #( e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; esac fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.17' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir ;; esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sleep supports fractional seconds" >&5 printf %s "checking whether sleep supports fractional seconds... " >&6; } if test ${am_cv_sleep_fractional_seconds+y} then : printf %s "(cached) " >&6 else case e in #( e) if sleep 0.001 2>/dev/null then : am_cv_sleep_fractional_seconds=yes else case e in #( e) am_cv_sleep_fractional_seconds=no ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_sleep_fractional_seconds" >&5 printf "%s\n" "$am_cv_sleep_fractional_seconds" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking filesystem timestamp resolution" >&5 printf %s "checking filesystem timestamp resolution... " >&6; } if test ${am_cv_filesystem_timestamp_resolution+y} then : printf %s "(cached) " >&6 else case e in #( e) # Default to the worst case. am_cv_filesystem_timestamp_resolution=2 # Only try to go finer than 1 sec if sleep can do it. # Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, # - 1 sec is not much of a win compared to 2 sec, and # - it takes 2 seconds to perform the test whether 1 sec works. # # Instead, just use the default 2s on platforms that have 1s resolution, # accept the extra 1s delay when using $sleep in the Automake tests, in # exchange for not incurring the 2s delay for running the test for all # packages. # am_try_resolutions= if test "$am_cv_sleep_fractional_seconds" = yes; then # Even a millisecond often causes a bunch of false positives, # so just try a hundredth of a second. The time saved between .001 and # .01 is not terribly consequential. am_try_resolutions="0.01 0.1 $am_try_resolutions" fi # In order to catch current-generation FAT out, we must *modify* files # that already exist; the *creation* timestamp is finer. Use names # that make ls -t sort them differently when they have equal # timestamps than when they have distinct timestamps, keeping # in mind that ls -t prints the *newest* file first. rm -f conftest.ts? : > conftest.ts1 : > conftest.ts2 : > conftest.ts3 # Make sure ls -t actually works. Do 'set' in a subshell so we don't # clobber the current shell's arguments. (Outer-level square brackets # are removed by m4; they're present so that m4 does not expand # ; be careful, easy to get confused.) if ( set X `ls -t conftest.ts[12]` && { test "$*" != "X conftest.ts1 conftest.ts2" || test "$*" != "X conftest.ts2 conftest.ts1"; } ); then :; else # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". printf "%s\n" ""Bad output from ls -t: \"`ls -t conftest.ts[12]`\""" >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "ls -t produces unexpected output. Make sure there is not a broken ls alias in your environment. See 'config.log' for more details" "$LINENO" 5; } fi for am_try_res in $am_try_resolutions; do # Any one fine-grained sleep might happen to cross the boundary # between two values of a coarser actual resolution, but if we do # two fine-grained sleeps in a row, at least one of them will fall # entirely within a coarse interval. echo alpha > conftest.ts1 sleep $am_try_res echo beta > conftest.ts2 sleep $am_try_res echo gamma > conftest.ts3 # We assume that 'ls -t' will make use of high-resolution # timestamps if the operating system supports them at all. if (set X `ls -t conftest.ts?` && test "$2" = conftest.ts3 && test "$3" = conftest.ts2 && test "$4" = conftest.ts1); then # # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, # because we don't need to test make. make_ok=true if test $am_try_res != 1; then # But if we've succeeded so far with a subsecond resolution, we # have one more thing to check: make. It can happen that # everything else supports the subsecond mtimes, but make doesn't; # notably on macOS, which ships make 3.81 from 2006 (the last one # released under GPLv2). https://bugs.gnu.org/68808 # # We test $MAKE if it is defined in the environment, else "make". # It might get overridden later, but our hope is that in practice # it does not matter: it is the system "make" which is (by far) # the most likely to be broken, whereas if the user overrides it, # probably they did so with a better, or at least not worse, make. # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html # # Create a Makefile (real tab character here): rm -f conftest.mk echo 'conftest.ts1: conftest.ts2' >conftest.mk echo ' touch conftest.ts2' >>conftest.mk # # Now, running # touch conftest.ts1; touch conftest.ts2; make # should touch ts1 because ts2 is newer. This could happen by luck, # but most often, it will fail if make's support is insufficient. So # test for several consecutive successes. # # (We reuse conftest.ts[12] because we still want to modify existing # files, not create new ones, per above.) n=0 make=${MAKE-make} until test $n -eq 3; do echo one > conftest.ts1 sleep $am_try_res echo two > conftest.ts2 # ts2 should now be newer than ts1 if $make -f conftest.mk | grep 'up to date' >/dev/null; then make_ok=false break # out of $n loop fi n=`expr $n + 1` done fi # if $make_ok; then # Everything we know to check worked out, so call this resolution good. am_cv_filesystem_timestamp_resolution=$am_try_res break # out of $am_try_res loop fi # Otherwise, we'll go on to check the next resolution. fi done rm -f conftest.ts? # (end _am_filesystem_timestamp_resolution) ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_filesystem_timestamp_resolution" >&5 printf "%s\n" "$am_cv_filesystem_timestamp_resolution" >&6; } # This check should not be cached, as it may vary across builds of # different projects. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). am_build_env_is_sane=no am_has_slept=no rm -f conftest.file for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi test "$2" = conftest.file ); then am_build_env_is_sane=yes break fi # Just in case. sleep "$am_cv_filesystem_timestamp_resolution" am_has_slept=yes done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_build_env_is_sane" >&5 printf "%s\n" "$am_build_env_is_sane" >&6; } if test "$am_build_env_is_sane" = no; then as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1 then : else case e in #( e) ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! ;; esac fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was 's,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else case e in #( e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ *'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS ;; esac fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use plain mkdir -p, # in the hope it doesn't have the bugs of ancient mkdir. MKDIR_P='mkdir -p' fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else case e in #( e) cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make ;; esac fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AM_DEFAULT_VERBOSITY=1 # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else case e in #( e) if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } AM_BACKSLASH='\' am__rm_f_notfound= if (rm -f && rm -fr && rm -rf) 2>/dev/null then : else case e in #( e) am__rm_f_notfound='""' ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking xargs -n works" >&5 printf %s "checking xargs -n works... " >&6; } if test ${am_cv_xargs_n_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 3" then : am_cv_xargs_n_works=yes else case e in #( e) am_cv_xargs_n_works=no ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_xargs_n_works" >&5 printf "%s\n" "$am_cv_xargs_n_works" >&6; } if test "$am_cv_xargs_n_works" = yes then : am__xargs_n='xargs -n' else case e in #( e) am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "" "$am__xargs_n_arg"; done; }' ;; esac fi if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='got-portable' VERSION='0.119' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi ac_config_headers="$ac_config_headers include/got_compat.h" printf "%s\n" "#define VERSION $VERSION" >>confdefs.h printf "%s\n" "#define GOT_VERSION VERSION" >>confdefs.h printf "%s\n" "#define GOT_VERSION_NUMBER VERSION" >>confdefs.h DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. # So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else case e in #( e) ac_file='' ;; esac fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See 'config.log' for more details" "$LINENO" 5; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) # catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will # work properly (i.e., refer to 'conftest.exe'), while it won't with # 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); if (!f) return 1; return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use '--host'. See 'config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext \ conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else case e in #( e) printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See 'config.log' for more details" "$LINENO" 5; } ;; esac fi rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes else case e in #( e) ac_cv_safe_to_define___extensions__=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 #include mbstate_t x; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes printf "%s\n" "#define _MINIX 1" >>confdefs.h printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h else case e in #( e) MINIX= ;; esac fi if test $ac_cv_safe_to_define___extensions__ = yes then : printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h fi # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac subdirs="$subdirs template" # Check whether --enable-cvg was given. if test ${enable_cvg+y} then : enableval=$enable_cvg; fi # Override gotd's empty_path location. # Check whether --with-gotd-empty-path was given. if test ${with_gotd_empty_path+y} then : withval=$with_gotd_empty_path; GOTD_EMPTY_PATHC=$withval fi # Override where git's libexec helpers are located for gitwrapper. # Check whether --with-gitwrapper-git-libexec-path was given. if test ${with_gitwrapper_git_libexec_path+y} then : withval=$with_gitwrapper_git_libexec_path; GITWRAPPER_LIBEXEC_PATHC=$withval fi # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" # YACC override YACC_OVERRIDE="yes" # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else case e in #( e) ac_compiler_gnu=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else case e in #( e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 ;; esac fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC ;; esac fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else case e in #( e) if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" ;; esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 ;; esac fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else case e in #( e) # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else case e in #( e) # Broken: fails on valid input. continue ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else case e in #( e) # Passes both tests. ac_preproc_ok=: break ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP ;; esac fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else case e in #( e) # Broken: fails on valid input. continue ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else case e in #( e) # Passes both tests. ac_preproc_ok=: break ;; esac fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else case e in #( e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See 'config.log' for more details" "$LINENO" 5; } ;; esac fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else case e in #( e) cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make ;; esac fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test -z "$YACC"; then YACC_OVERRIDE="no" for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 printf "%s\n" "$YACC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" fi if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${ARFLAGS=cr} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 printf %s "checking the archiver ($AR) interface... " >&6; } if test ${am_cv_ar_interface+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_ar_try='$AR $ARFLAGS libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else case e in #( e) if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi ;; esac fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else case e in #( e) case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi if test "$YACC_OVERRIDE" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"Using YACC set from environment: $YACC\"" >&5 printf "%s\n" "$as_me: \"Using YACC set from environment: $YACC\"" >&6;} fi # Checks for header files. ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = xyes then : printf "%s\n" "#define HAVE_GETOPT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" if test "x$ac_cv_header_langinfo_h" = xyes then : printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "libutil.h" "ac_cv_header_libutil_h" "$ac_includes_default" if test "x$ac_cv_header_libutil_h" = xyes then : printf "%s\n" "#define HAVE_LIBUTIL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/landlock.h" "ac_cv_header_linux_landlock_h" "$ac_includes_default" if test "x$ac_cv_header_linux_landlock_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_LANDLOCK_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes then : printf "%s\n" "#define HAVE_LOCALE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_in_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "paths.h" "ac_cv_header_paths_h" "$ac_includes_default" if test "x$ac_cv_header_paths_h" = xyes then : printf "%s\n" "#define HAVE_PATHS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" if test "x$ac_cv_header_poll_h" = xyes then : printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha.h" "ac_cv_header_sha_h" "$ac_includes_default" if test "x$ac_cv_header_sha_h" = xyes then : printf "%s\n" "#define HAVE_SHA_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha1.h" "ac_cv_header_sha1_h" "$ac_includes_default" if test "x$ac_cv_header_sha1_h" = xyes then : printf "%s\n" "#define HAVE_SHA1_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha2.h" "ac_cv_header_sha2_h" "$ac_includes_default" if test "x$ac_cv_header_sha2_h" = xyes then : printf "%s\n" "#define HAVE_SHA2_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sha256.h" "ac_cv_header_sha256_h" "$ac_includes_default" if test "x$ac_cv_header_sha256_h" = xyes then : printf "%s\n" "#define HAVE_SHA256_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default" if test "x$ac_cv_header_stddef_h" = xyes then : printf "%s\n" "#define HAVE_STDDEF_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes then : printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes then : printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" if test "x$ac_cv_header_sys_poll_h" = xyes then : printf "%s\n" "#define HAVE_SYS_POLL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/queue.h" "ac_cv_header_sys_queue_h" "$ac_includes_default" if test "x$ac_cv_header_sys_queue_h" = xyes then : printf "%s\n" "#define HAVE_SYS_QUEUE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/tree.h" "ac_cv_header_sys_tree_h" "$ac_includes_default" if test "x$ac_cv_header_sys_tree_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TREE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "tls.h" "ac_cv_header_tls_h" "$ac_includes_default" if test "x$ac_cv_header_tls_h" = xyes then : printf "%s\n" "#define HAVE_TLS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "util.h" "ac_cv_header_util_h" "$ac_includes_default" if test "x$ac_cv_header_util_h" = xyes then : printf "%s\n" "#define HAVE_UTIL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" if test "x$ac_cv_header_wchar_h" = xyes then : printf "%s\n" "#define HAVE_WCHAR_H 1" >>confdefs.h fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | sed "$as_sed_sh"` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 printf %s "checking for $ac_hdr that defines DIR... " >&6; } if eval test \${$as_ac_Header+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main (void) { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$as_ac_Header=yes" else case e in #( e) eval "$as_ac_Header=no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi eval ac_res=\$$as_ac_Header { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_hdr" | sed "$as_sed_cpp"` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char opendir (void); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else case e in #( e) ac_cv_search_opendir=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char opendir (void); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else case e in #( e) ac_cv_search_opendir=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" # This test program should *not* compile successfully. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { (void) strchr; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else case e in #( e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the # off chance that they somehow elicit warnings. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include extern void ac_decl (int, char *); int main (void) { (void) ac_decl (0, (char *) 0); (void) ac_decl; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' else case e in #( e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; esac fi break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac ac_fn_check_decl "$LINENO" "F_CLOSEM" "ac_cv_have_decl_F_CLOSEM" "#include #include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_F_CLOSEM" = xyes then : HAVE_FCNTL_CLOSEM printf "%s\n" "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /proc/pid/fd directory" >&5 printf %s "checking for /proc/pid/fd directory... " >&6; } if test -d "/proc/$$/fd" ; then printf "%s\n" "#define HAVE_PROC_PID 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether program_invocation_short_name is defined" >&5 printf %s "checking whether program_invocation_short_name is defined... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { program_invocation_short_name = "test"; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1" >>confdefs.h else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Look for prctl(PR_SET_NAME). ac_fn_check_decl "$LINENO" "PR_SET_NAME" "ac_cv_have_decl_PR_SET_NAME" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_PR_SET_NAME" = xyes then : printf "%s\n" "#define HAVE_PR_SET_NAME 1" >>confdefs.h fi if test "x$ac_cv_header_sha2_h" = xyes || \ test "x$ac_cv_header_sha256_h" = xyes; then HAVE_SHA2_TRUE= HAVE_SHA2_FALSE='#' else HAVE_SHA2_TRUE='#' HAVE_SHA2_FALSE= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getopt has optreset support" >&5 printf %s "checking whether getopt has optreset support... " >&6; } if test ${ac_cv_have_getopt_optreset+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { extern int optreset; optreset = 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_have_getopt_optreset="yes" else case e in #( e) ac_cv_have_getopt_optreset="no" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_getopt_optreset" >&5 printf "%s\n" "$ac_cv_have_getopt_optreset" >&6; } if test "x$ac_cv_have_getopt_optreset" = "xyes"; then HAVE_GETOPT_TRUE= HAVE_GETOPT_FALSE='#' else HAVE_GETOPT_TRUE='#' HAVE_GETOPT_FALSE= fi if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then printf "%s\n" "#define HAVE_GETOPT_OPTRESET 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct pollfd" "fd" "ac_cv_member_struct_pollfd_fd" " #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif " if test "x$ac_cv_member_struct_pollfd_fd" = xyes then : printf "%s\n" "#define HAVE_STRUCT_POLLFD_FD 1" >>confdefs.h fi # Checks for typ edefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes then : printf "%s\n" "#define HAVE__BOOL 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99 or later" >&5 printf %s "checking for stdbool.h that conforms to C99 or later... " >&6; } if test ${ac_cv_header_stdbool_h+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* "true" and "false" should be usable in #if expressions and integer constant expressions, and "bool" should be a valid type name. Although C99 requires bool, true, and false to be macros, C23 and C++11 overrule that, so do not test for that. Although C99 requires __bool_true_false_are_defined and _Bool, C23 says they are obsolescent, so do not require them. */ #if !true #error "'true' is not true" #endif #if true != 1 #error "'true' is not equal to 1" #endif char b[true == 1 ? 1 : -1]; char c[true]; #if false #error "'false' is not false" #endif #if false != 0 #error "'false' is not equal to 0" #endif char d[false == 0 ? 1 : -1]; enum { e = false, f = true, g = false * true, h = true * 256 }; char i[(bool) 0.5 == true ? 1 : -1]; char j[(bool) 0.0 == false ? 1 : -1]; char k[sizeof (bool) > 0 ? 1 : -1]; struct sb { bool s: 1; bool t; } s; char l[sizeof s.t > 0 ? 1 : -1]; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ bool m[h]; char n[sizeof m == h * sizeof m[0] ? 1 : -1]; char o[-1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See https://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html https://lists.gnu.org/r/bug-coreutils/2005-11/msg00161.html */ bool p = true; bool *pp = &p; int main (void) { bool ps = &s; *pp |= p; *pp |= ! p; /* Refer to every declared value, so they cannot be discarded as unused. */ return (!b + !c + !d + !e + !f + !g + !h + !i + !j + !k + !l + !m + !n + !o + !p + !pp + !ps); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_stdbool_h=yes else case e in #( e) ac_cv_header_stdbool_h=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 printf "%s\n" "$ac_cv_header_stdbool_h" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" case $ac_cv_c_int64_t in #( no|yes) ;; #( *) printf "%s\n" "#define int64_t $ac_cv_c_int64_t" >>confdefs.h ;; esac ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes then : else case e in #( e) printf "%s\n" "#define mode_t int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : else case e in #( e) printf "%s\n" "#define off_t long int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default " if test "x$ac_cv_type_pid_t" = xyes then : else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ LLP64 #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' else case e in #( e) ac_pid_type='__int64' ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else case e in #( e) printf "%s\n" "#define size_t unsigned int" >>confdefs.h ;; esac fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes then : else case e in #( e) printf "%s\n" "#define ssize_t int" >>confdefs.h ;; esac fi ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) printf "%s\n" "#define uint16_t $ac_cv_c_uint16_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT32_T 1" >>confdefs.h printf "%s\n" "#define uint32_t $ac_cv_c_uint32_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT64_T 1" >>confdefs.h printf "%s\n" "#define uint64_t $ac_cv_c_uint64_t" >>confdefs.h ;; esac ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) printf "%s\n" "#define _UINT8_T 1" >>confdefs.h printf "%s\n" "#define uint8_t $ac_cv_c_uint8_t" >>confdefs.h ;; esac # Check for ifgroupreq which is only available on BSD. ac_fn_c_check_type "$LINENO" "struct ifgroupreq" "ac_cv_type_struct_ifgroupreq" "$ac_includes_default" if test "x$ac_cv_type_struct_ifgroupreq" = xyes then : printf "%s\n" "#define HAVE_STRUCT_IFGROUPREQ 1" >>confdefs.h fi # Check for sockaddr_storage. On some systems, ss_len is filled out, although # this is not mandated by POSIX, and hence systems such as linux, don't have # it. ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" " #include #include " if test "x$ac_cv_type_struct_sockaddr_storage" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h fi # Same thing as sockaddr_storage above, only now check if the member exists in # the struct as well. ac_fn_c_check_member "$LINENO" "struct sockaddr_storage" "ss_len" "ac_cv_member_struct_sockaddr_storage_ss_len" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_storage_ss_len" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h fi # Both checks above will result in: # # HAVE_STRUCT_SOCKADDR_AS_LEN # SS_LEN # # Either being defined or not. # Look for library needed for flock. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing flock" >&5 printf %s "checking for library containing flock... " >&6; } if test ${ac_cv_search_flock+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char flock (void); int main (void) { return flock (); ; return 0; } _ACEOF for ac_lib in '' bsd do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_flock=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_flock+y} then : break fi done if test ${ac_cv_search_flock+y} then : else case e in #( e) ac_cv_search_flock=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_flock" >&5 printf "%s\n" "$ac_cv_search_flock" >&6; } ac_res=$ac_cv_search_flock if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # Checks for library functions. ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done if test "x$ac_cv_func_fork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 printf %s "checking for working fork... " >&6; } if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* By R. Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes else case e in #( e) ac_cv_func_fork_works=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 printf %s "checking for working vfork... " >&6; } if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #include #ifdef HAVE_VFORK_H # include #endif static void do_nothing (int sig) { (void) sig; } /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void sparc_address_test (int arg) { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main (void) { pid_t parent = getpid (); pid_t child; sparc_address_test (0); /* On Solaris 2.4, changes by the child to the signal handler also munge signal handlers in the parent. To detect this, start by putting the parent's handler in a known state. */ signal (SIGTERM, SIG_DFL); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* Alter the child's signal handler. */ if (signal (SIGTERM, do_nothing) != SIG_DFL) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child munge the parent's signal handler? */ || signal (SIGTERM, SIG_DFL) != SIG_DFL /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes else case e in #( e) ac_cv_func_vfork_works=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_VFORK 1" >>confdefs.h else printf "%s\n" "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for declarations of fseeko and ftello" >&5 printf %s "checking for declarations of fseeko and ftello... " >&6; } if test ${ac_cv_func_fseeko_ftello+y} then : printf %s "(cached) " >&6 else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __hpux && !defined _LARGEFILE_SOURCE # include # if LONG_MAX >> 31 == 0 # error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" # endif #endif #include /* for off_t */ #include int main (void) { int (*fp1) (FILE *, off_t, int) = fseeko; off_t (*fp2) (FILE *) = ftello; return fseeko (stdin, 0, 0) && fp1 (stdin, 0, 0) && ftello (stdin) >= 0 && fp2 (stdin) >= 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_fseeko_ftello=yes else case e in #( e) ac_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -D_LARGEFILE_SOURCE=1" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __hpux && !defined _LARGEFILE_SOURCE # include # if LONG_MAX >> 31 == 0 # error "32-bit HP-UX 11/ia64 needs _LARGEFILE_SOURCE for fseeko in C++" # endif #endif #include /* for off_t */ #include int main (void) { int (*fp1) (FILE *, off_t, int) = fseeko; off_t (*fp2) (FILE *) = ftello; return fseeko (stdin, 0, 0) && fp1 (stdin, 0, 0) && ftello (stdin) >= 0 && fp2 (stdin) >= 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_fseeko_ftello="need _LARGEFILE_SOURCE" else case e in #( e) ac_cv_func_fseeko_ftello=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fseeko_ftello" >&5 printf "%s\n" "$ac_cv_func_fseeko_ftello" >&6; } if test "$ac_cv_func_fseeko_ftello" != no then : printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h fi if test "$ac_cv_func_fseeko_ftello" = "need _LARGEFILE_SOURCE" then : printf "%s\n" "#define _LARGEFILE_SOURCE 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 printf %s "checking whether lstat correctly handles trailing slash... " >&6; } if test ${ac_cv_func_lstat_dereferences_slashed_symlink+y} then : printf %s "(cached) " >&6 else case e in #( e) rm -f conftest.sym conftest.file echo >conftest.file if test "$as_ln_s" = "ln -s" && ln -s conftest.file conftest.sym; then if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on glibc systems. *-gnu*) ac_cv_func_lstat_dereferences_slashed_symlink=yes ;; # If we don't know, assume the worst. *) ac_cv_func_lstat_dereferences_slashed_symlink=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { struct stat sbuf; /* Linux will dereference the symlink and fail, as required by POSIX. That is better in the sense that it means we will not have to compile and use the lstat wrapper. */ return lstat ("conftest.sym/", &sbuf) == 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_lstat_dereferences_slashed_symlink=yes else case e in #( e) ac_cv_func_lstat_dereferences_slashed_symlink=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi else # If the 'ln -s' command failed, then we probably don't even # have an lstat function. ac_cv_func_lstat_dereferences_slashed_symlink=no fi rm -f conftest.sym conftest.file ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_lstat_dereferences_slashed_symlink" >&5 printf "%s\n" "$ac_cv_func_lstat_dereferences_slashed_symlink" >&6; } test $ac_cv_func_lstat_dereferences_slashed_symlink = yes && printf "%s\n" "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h if test "x$ac_cv_func_lstat_dereferences_slashed_symlink" = xno; then case " $LIBOBJS " in *" lstat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS lstat.$ac_objext" ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 printf %s "checking for GNU libc compatible malloc... " >&6; } if test ${ac_cv_func_malloc_0_nonnull+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ | hpux* | solaris* | cygwin* | mingw* | windows* | msys* ) ac_cv_func_malloc_0_nonnull=yes ;; # If we don't know, assume the worst. *) ac_cv_func_malloc_0_nonnull=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { void *p = malloc (0); int result = !p; free (p); return result; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_malloc_0_nonnull=yes else case e in #( e) ac_cv_func_malloc_0_nonnull=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes then : printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h else case e in #( e) printf "%s\n" "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac printf "%s\n" "#define malloc rpl_malloc" >>confdefs.h ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 printf %s "checking for working mmap... " >&6; } if test ${ac_cv_func_mmap_fixed_mapped+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. linux*) ac_cv_func_mmap_fixed_mapped=yes ;; # If we don't know, assume the worst. *) ac_cv_func_mmap_fixed_mapped=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. */ #include #include #ifndef getpagesize /* Prefer sysconf to the legacy getpagesize function, as getpagesize has been removed from POSIX and is limited to page sizes that fit in 'int'. */ # ifdef _SC_PAGESIZE # define getpagesize() sysconf (_SC_PAGESIZE) # elif defined _SC_PAGE_SIZE # define getpagesize() sysconf (_SC_PAGE_SIZE) # elif HAVE_GETPAGESIZE int getpagesize (); # else # ifdef HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif #endif int main (void) { char *data, *data2, *data3; const char *cdata2; long i, pagesize; int fd, fd2; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) return 1; for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) return 2; if (write (fd, data, pagesize) != pagesize) return 3; close (fd); /* Next, check that the tail of a page is zero-filled. File must have non-zero length, otherwise we risk SIGBUS for entire page. */ fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd2 < 0) return 4; cdata2 = ""; if (write (fd2, cdata2, 1) != 1) return 5; data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); if (data2 == MAP_FAILED) return 6; for (i = 0; i < pagesize; ++i) if (*(data2 + i)) return 7; close (fd2); /* 'return 8;' not currently used. */ /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) return 9; if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) return 10; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) return 11; /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) return 12; if (read (fd, data3, pagesize) != pagesize) return 13; for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) return 14; close (fd); free (data); free (data3); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_mmap_fixed_mapped=yes else case e in #( e) ac_cv_func_mmap_fixed_mapped=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 printf "%s\n" "$ac_cv_func_mmap_fixed_mapped" >&6; } if test $ac_cv_func_mmap_fixed_mapped = yes; then printf "%s\n" "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 printf %s "checking for GNU libc compatible realloc... " >&6; } if test ${ac_cv_func_realloc_0_nonnull+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : case "$host_os" in # (( # Guess yes on platforms where we know the result. *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ | hpux* | solaris* | cygwin* | mingw* | windows* | msys* ) ac_cv_func_realloc_0_nonnull=yes ;; # If we don't know, assume the worst. *) ac_cv_func_realloc_0_nonnull=no ;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { void *p = realloc (0, 0); int result = !p; free (p); return result; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_realloc_0_nonnull=yes else case e in #( e) ac_cv_func_realloc_0_nonnull=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 printf "%s\n" "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes then : printf "%s\n" "#define HAVE_REALLOC 1" >>confdefs.h else case e in #( e) printf "%s\n" "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac printf "%s\n" "#define realloc rpl_realloc" >>confdefs.h ;; esac fi ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_strerror_r" = xyes then : ac_have_decl=1 else case e in #( e) ac_have_decl=0 ;; esac fi printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_strerror_r = yes; then # For backward compatibility's sake, define HAVE_STRERROR_R. # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well # as AC_CHECK_DECLS_ONCE.) printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 printf %s "checking whether strerror_r returns char *... " >&6; } if test ${ac_cv_func_strerror_r_char_p+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char buf[100]; char x = *strerror_r (0, buf, sizeof buf); char *p = strerror_r (0, buf, sizeof buf); return !p || x; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_strerror_r_char_p=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; } if test $ac_cv_func_strerror_r_char_p = yes; then printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5 printf %s "checking for working strnlen... " >&6; } if test ${ac_cv_func_strnlen_working+y} then : printf %s "(cached) " >&6 else case e in #( e) if test "$cross_compiling" = yes then : # Guess no on AIX systems, yes otherwise. case "$host_os" in aix*) ac_cv_func_strnlen_working=no;; *) ac_cv_func_strnlen_working=yes;; esac else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { #define S "foobar" #define S_LEN (sizeof S - 1) /* At least one implementation is buggy: that of AIX 4.3 would give strnlen (S, 1) == 3. */ int i; for (i = 0; i < S_LEN + 1; ++i) { int expected = i <= S_LEN ? i : S_LEN; if (strnlen (S, i) != expected) return 1; } return 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_strnlen_working=yes else case e in #( e) ac_cv_func_strnlen_working=no ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strnlen_working" >&5 printf "%s\n" "$ac_cv_func_strnlen_working" >&6; } test $ac_cv_func_strnlen_working = no && case " $LIBOBJS " in *" strnlen.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strnlen.$ac_objext" ;; esac ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" if test "x$ac_cv_func_dup2" = xyes then : printf "%s\n" "#define HAVE_DUP2 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" if test "x$ac_cv_func_flock" = xyes then : printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" if test "x$ac_cv_func_localtime_r" = xyes then : printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memchr" "ac_cv_func_memchr" if test "x$ac_cv_func_memchr" = xyes then : printf "%s\n" "#define HAVE_MEMCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" if test "x$ac_cv_func_memmove" = xyes then : printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" if test "x$ac_cv_func_memset" = xyes then : printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mergesort" "ac_cv_func_mergesort" if test "x$ac_cv_func_mergesort" = xyes then : printf "%s\n" "#define HAVE_MERGESORT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkdir" "ac_cv_func_mkdir" if test "x$ac_cv_func_mkdir" = xyes then : printf "%s\n" "#define HAVE_MKDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "munmap" "ac_cv_func_munmap" if test "x$ac_cv_func_munmap" = xyes then : printf "%s\n" "#define HAVE_MUNMAP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" if test "x$ac_cv_func_realpath" = xyes then : printf "%s\n" "#define HAVE_REALPATH 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "regcomp" "ac_cv_func_regcomp" if test "x$ac_cv_func_regcomp" = xyes then : printf "%s\n" "#define HAVE_REGCOMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "rmdir" "ac_cv_func_rmdir" if test "x$ac_cv_func_rmdir" = xyes then : printf "%s\n" "#define HAVE_RMDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" if test "x$ac_cv_func_setlocale" = xyes then : printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = xyes then : printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresgid" "ac_cv_func_setresgid" if test "x$ac_cv_func_setresgid" = xyes then : printf "%s\n" "#define HAVE_SETRESGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid" if test "x$ac_cv_func_setresuid" = xyes then : printf "%s\n" "#define HAVE_SETRESUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" if test "x$ac_cv_func_setproctitle" = xyes then : printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = xyes then : printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strchr" "ac_cv_func_strchr" if test "x$ac_cv_func_strchr" = xyes then : printf "%s\n" "#define HAVE_STRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strcspn" "ac_cv_func_strcspn" if test "x$ac_cv_func_strcspn" = xyes then : printf "%s\n" "#define HAVE_STRCSPN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" if test "x$ac_cv_func_strdup" = xyes then : printf "%s\n" "#define HAVE_STRDUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes then : printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strncasecmp" "ac_cv_func_strncasecmp" if test "x$ac_cv_func_strncasecmp" = xyes then : printf "%s\n" "#define HAVE_STRNCASECMP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup" if test "x$ac_cv_func_strndup" = xyes then : printf "%s\n" "#define HAVE_STRNDUP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strrchr" "ac_cv_func_strrchr" if test "x$ac_cv_func_strrchr" = xyes then : printf "%s\n" "#define HAVE_STRRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strspn" "ac_cv_func_strspn" if test "x$ac_cv_func_strspn" = xyes then : printf "%s\n" "#define HAVE_STRSPN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strstr" "ac_cv_func_strstr" if test "x$ac_cv_func_strstr" = xyes then : printf "%s\n" "#define HAVE_STRSTR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtol" "ac_cv_func_strtol" if test "x$ac_cv_func_strtol" = xyes then : printf "%s\n" "#define HAVE_STRTOL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul" if test "x$ac_cv_func_strtoul" = xyes then : printf "%s\n" "#define HAVE_STRTOUL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes then : printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wcwidth" "ac_cv_func_wcwidth" if test "x$ac_cv_func_wcwidth" = xyes then : printf "%s\n" "#define HAVE_WCWIDTH 1" >>confdefs.h fi ac_fn_check_decl "$LINENO" "RB_GENERATE_STATIC" "ac_cv_have_decl_RB_GENERATE_STATIC" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_RB_GENERATE_STATIC" = xyes then : found_sys_tree_h=yes else case e in #( e) found_sys_tree_h=no ;; esac fi if test "x$ac_cv_func_setproctitle" = xyes; then HAVE_SETPROCTITLE_TRUE= HAVE_SETPROCTITLE_FALSE='#' else HAVE_SETPROCTITLE_TRUE='#' HAVE_SETPROCTITLE_FALSE= fi if test "x$ac_cv_func_sysconf" = xyes; then printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h fi # Siphash support. ac_fn_c_check_func "$LINENO" "SipHash" "ac_cv_func_SipHash" if test "x$ac_cv_func_SipHash" = xyes then : printf "%s\n" "#define HAVE_SIPHASH 1" >>confdefs.h fi if test "x$ac_cv_func_SipHash" = xyes; then HAVE_SIPHASH_TRUE= HAVE_SIPHASH_FALSE='#' else HAVE_SIPHASH_TRUE='#' HAVE_SIPHASH_FALSE= fi # Check for functions with a compatibility implementation. ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = xyes then : printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" asprintf.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS asprintf.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom" if test "x$ac_cv_func_closefrom" = xyes then : printf "%s\n" "#define HAVE_CLOSEFROM 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" closefrom.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS closefrom.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes then : printf "%s\n" "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" explicit_bzero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS explicit_bzero.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "fmt_scaled" "ac_cv_func_fmt_scaled" if test "x$ac_cv_func_fmt_scaled" = xyes then : printf "%s\n" "#define HAVE_FMT_SCALED 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" fmt_scaled.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS fmt_scaled.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "freezero" "ac_cv_func_freezero" if test "x$ac_cv_func_freezero" = xyes then : printf "%s\n" "#define HAVE_FREEZERO 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" freezero.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS freezero.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "getdtablecount" "ac_cv_func_getdtablecount" if test "x$ac_cv_func_getdtablecount" = xyes then : printf "%s\n" "#define HAVE_GETDTABLECOUNT 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" getdtablecount.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getdtablecount.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline" if test "x$ac_cv_func_getline" = xyes then : printf "%s\n" "#define HAVE_GETLINE 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" getline.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getline.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "getprogname" "ac_cv_func_getprogname" if test "x$ac_cv_func_getprogname" = xyes then : printf "%s\n" "#define HAVE_GETPROGNAME 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" getprogname.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getprogname.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "recallocarray" "ac_cv_func_recallocarray" if test "x$ac_cv_func_recallocarray" = xyes then : printf "%s\n" "#define HAVE_RECALLOCARRAY 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes then : printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes then : printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strlcat.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strlcpy.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup" if test "x$ac_cv_func_strndup" = xyes then : printf "%s\n" "#define HAVE_STRNDUP 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strndup.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strndup.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" if test "x$ac_cv_func_strnlen" = xyes then : printf "%s\n" "#define HAVE_STRNLEN 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strnlen.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strnlen.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strsep" "ac_cv_func_strsep" if test "x$ac_cv_func_strsep" = xyes then : printf "%s\n" "#define HAVE_STRSEP 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strsep.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strsep.$ac_objext" ;; esac ;; esac fi ac_fn_c_check_func "$LINENO" "strtonum" "ac_cv_func_strtonum" if test "x$ac_cv_func_strtonum" = xyes then : printf "%s\n" "#define HAVE_STRTONUM 1" >>confdefs.h else case e in #( e) case " $LIBOBJS " in *" strtonum.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strtonum.$ac_objext" ;; esac ;; esac fi if test "x$ac_cv_func_closefrom" = xyes; then HAVE_CLOSEFROM_TRUE= HAVE_CLOSEFROM_FALSE='#' else HAVE_CLOSEFROM_TRUE='#' HAVE_CLOSEFROM_FALSE= fi # Always use our getopt because 1) glibc's doesn't enforce argument order 2) # musl does not set optarg to NULL for flags without arguments (although it is # not required to, but it is helpful) 3) there are probably other weird # implementations. case " $LIBOBJS " in *" getopt.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getopt.$ac_objext" ;; esac # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop" >&5 printf %s "checking for b64_ntop... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else case e in #( e) found_b64_ntop=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="" if test "x$found_b64_ntop" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop with -lresolv" >&5 printf %s "checking for b64_ntop with -lresolv... " >&6; } LIBS="-lresolv" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else case e in #( e) found_b64_ntop=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for b64_ntop with -lnetwork" >&5 printf %s "checking for b64_ntop with -lnetwork... " >&6; } LIBS="-lresolv -lnetwork" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main (void) { b64_ntop(NULL, 0, NULL, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : found_b64_ntop=yes else case e in #( e) found_b64_ntop=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $found_b64_ntop" >&5 printf "%s\n" "$found_b64_ntop" >&6; } libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xyes; then HAVE_B64_TRUE= HAVE_B64_FALSE='#' else HAVE_B64_TRUE='#' HAVE_B64_FALSE= fi if test "x$found_b64_ntop" = xyes; then printf "%s\n" "#define HAVE_B64_NTOP 1" >>confdefs.h else case " $LIBOBJS " in *" base64.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS base64.$ac_objext" ;; esac fi # Check the platform we're compiling on. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking platform" >&5 printf %s "checking platform... " >&6; } case "$host_os" in *linux*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: linux" >&5 printf "%s\n" "linux" >&6; } PLATFORM=linux ;; *freebsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: freebsd" >&5 printf "%s\n" "freebsd" >&6; } PLATFORM=freebsd ;; *darwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: darwin" >&5 printf "%s\n" "darwin" >&6; } PLATFORM=darwin ;; *netbsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: netbsd" >&5 printf "%s\n" "netbsd" >&6; } PLATFORM=netbsd ;; *openbsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: openbsd" >&5 printf "%s\n" "openbsd" >&6; } PLATFORM=openbsd ;; *dragonfly*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: dragonfly" >&5 printf "%s\n" "dragonfly" >&6; } PLATFORM=dragonflybsd ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5 printf "%s\n" "unknown" >&6; } PLATFORM=unknown ;; esac if test "$PLATFORM" = "freebsd"; then HOST_FREEBSD_TRUE= HOST_FREEBSD_FALSE='#' else HOST_FREEBSD_TRUE='#' HOST_FREEBSD_FALSE= fi if test "$PLATFORM" = "linux"; then HOST_LINUX_TRUE= HOST_LINUX_FALSE='#' else HOST_LINUX_TRUE='#' HOST_LINUX_FALSE= fi if test "$PLATFORM" = "darwin"; then HOST_DARWIN_TRUE= HOST_DARWIN_FALSE='#' else HOST_DARWIN_TRUE='#' HOST_DARWIN_FALSE= fi if test "$PLATFORM" = "netbsd"; then HOST_NETBSD_TRUE= HOST_NETBSD_FALSE='#' else HOST_NETBSD_TRUE='#' HOST_NETBSD_FALSE= fi if test "$PLATFORM" = "openbsd"; then HOST_OPENBSD_TRUE= HOST_OPENBSD_FALSE='#' else HOST_OPENBSD_TRUE='#' HOST_OPENBSD_FALSE= fi if test "$PLATFORM" = "dragonflybsd"; then HOST_DRAGONFLYBSD_TRUE= HOST_DRAGONFLYBSD_FALSE='#' else HOST_DRAGONFLYBSD_TRUE='#' HOST_DRAGONFLYBSD_FALSE= fi # On OpenBSD, these functions are already defined, yet looking for them in # this way on OpenBSD breaks inclusion. # FIXME: this needs addressing. if test "x$PLATFORM" != "xopenbsd"; then ac_fn_c_check_func "$LINENO" "SHA256Update" "ac_cv_func_SHA256Update" if test "x$ac_cv_func_SHA256Update" = xyes then : printf "%s\n" "#define HAVE_SHA256UPDATE 1" >>confdefs.h fi fi # Look for yacc. if test "YACC_OVERRIDE" = "yes" && test -n "$YACC" \ && ! command -v "$YACC" >/dev/null 2>&1; then as_fn_error $? "\"yacc not found: $YACC\"" "$LINENO" 5 fi if test x"$PLATFORM" = "xdarwin"; then # Check for and/or set HOMEBREW_PREFIX. brew is a common way of # installing applications. The other is MacPorts. # # Before Apple Silicon existed (M1 onward), the paths for applications # installed via homebrew was typically /usr/local. However, with M1 # onward, this changed to a different path. # # Rather than hardcode this, check for HOMEBREW_PREFIX in the # environment if it's already set, and use it. Otherwise, check for # brew(1) and use that. If that fails, default to /usr/local # # This also means that MacPorts should continue to work. # # But with MacPorts, we should also check --prefix, and use that if it # has been supplied. # # In both cases, the variable HOMEBREW_PREFIX is used for both. HB_PREFIX="" FOUND_BISON="no" GNUBISON="" if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE"; then # HOMEBREW_PREFIX not set, check for brew(1) if command -v brew >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX set via 'brew --prefix'\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX set via 'brew --prefix'\"" >&6;} export HOMEBREW_PREFIX="$(brew --prefix)" fi if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE" then # Default. if test -z "${prefix}" -o "${prefix}" = "NONE"; then export HOMEBREW_PREFIX="/usr/local" HB_PREFIX="/usr/local" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX defaulting to $HB_PREFIX\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX defaulting to $HB_PREFIX\"" >&6;} else HB_PREFIX="$(eval echo ${prefix})" if test "$HB_PREFIX" = "NONE"; then HB_PREFIX="/opt/local" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX using --prefix\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX using --prefix\"" >&6;} fi export HOMEBREW_PREFIX="$HB_PREFIX" fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX\"" >&5 printf "%s\n" "$as_me: \"HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX\"" >&6;} if test "$YACC_OVERRIDE" = "no" && \ ! test -x "${HOMEBREW_PREFIX}/opt/bison/bin/bison"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}\" " >&5 printf "%s\n" "$as_me: WARNING: \"*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}\" " >&2;} FOUND_BISON="no" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"Trying ${HB_PREFIX}/opt/bison/bin/bison\"" >&5 printf "%s\n" "$as_me: WARNING: \"Trying ${HB_PREFIX}/opt/bison/bin/bison\"" >&2;} if test -x "${HB_PREFIX}/opt/bison/bin/bison"; then export HOMEBREW_PREFIX="/usr/local" FOUND_BISON="yes" GNUBISON="${HB_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no"; then HB_PREFIX="/opt/local" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"Trying ${HB_PREFIX}/bin/bison\"" >&5 printf "%s\n" "$as_me: WARNING: \"Trying ${HB_PREFIX}/bin/bison\"" >&2;} if test -x "${HB_PREFIX}/bin/bison"; then export HOMEBREW_PREFIX="${HB_PREFIX}" GNUBISON="${HB_PREFIX}/bin/bison" FOUND_BISON="yes" fi fi else FOUND_BISON="yes" GNUBISON="${HOMEBREW_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no" && test "$YACC_OVERRIDE" = "no"; then as_fn_error $? "\"*** Couldn't find GNU BISON ***\"" "$LINENO" 5 fi # Override YACC here to point to the GNU version of bison. if test "$YACC_OVERRIDE" = "yes"; then export YACC="$YACC -y" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \"Found GNU Bison as: $GNUBISON\"" >&5 printf "%s\n" "$as_me: \"Found GNU Bison as: $GNUBISON\"" >&6;} export YACC="${GNUBISON} -y" fi export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/ncurses/lib -L${HOMEBREW_PREFIX}/opt/openssl@3/lib $LDFLAGS" export CPPFLAGS="-I${HOMEBREW_PREFIX}/opt/ncurses/include -I${HOMEBREW_PREFIX}/opt/openssl@3/include $CPPFLAGS" export PKG_CONFIG_PATH="${HOMEBREW_PREFIX}/opt/ncurses/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig" fi # Landlock detection. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for landlock" >&5 printf %s "checking for landlock... " >&6; } if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then HAVE_LINUX_LANDLOCK_TRUE= HAVE_LINUX_LANDLOCK_FALSE='#' else HAVE_LINUX_LANDLOCK_TRUE='#' HAVE_LINUX_LANDLOCK_FALSE= fi if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Clang sanitizers wrap reallocarray even if it isn't available on the target # system. When compiled it always returns NULL and crashes the program. To # detect this we need a more complicated test. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working reallocarray" >&5 printf %s "checking for working reallocarray... " >&6; } if test "$cross_compiling" = yes then : case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { return (reallocarray(NULL, 1, 1) == NULL); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) case " $LIBOBJS " in *" reallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working recallocarray" >&5 printf %s "checking for working recallocarray... " >&6; } if test "$cross_compiling" = yes then : case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { return (recallocarray(NULL, 1, 1, 1) == NULL); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) case " $LIBOBJS " in *" recallocarray.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS recallocarray.$ac_objext" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi # Look for imsg_init in libutil. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing imsg_init" >&5 printf %s "checking for library containing imsg_init... " >&6; } if test ${ac_cv_search_imsg_init+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char imsg_init (void); int main (void) { return imsg_init (); ; return 0; } _ACEOF for ac_lib in '' util do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_imsg_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_imsg_init+y} then : break fi done if test ${ac_cv_search_imsg_init+y} then : else case e in #( e) ac_cv_search_imsg_init=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_imsg_init" >&5 printf "%s\n" "$ac_cv_search_imsg_init" >&6; } ac_res=$ac_cv_search_imsg_init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_imsg_init=yes else case e in #( e) found_imsg_init=no ;; esac fi if test "x$found_imsg_init" = "xyes"; then HAVE_IMSG_TRUE= HAVE_IMSG_FALSE='#' else HAVE_IMSG_TRUE='#' HAVE_IMSG_FALSE= fi if test "x$found_imsg_init" = "xyes"; then printf "%s\n" "#define HAVE_IMSG 1" >>confdefs.h libutil_LIBS="$ac_cv_search_imsg_init" fi # libevent (for gotwebd). Lifted from tmux. # Look for libevent. Try libevent_core or libevent with pkg-config first then # look for the library. found_libevent=no pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libevent_core >= 2" >&5 printf %s "checking for libevent_core >= 2... " >&6; } if test -n "$LIBEVENT_CORE_CFLAGS"; then pkg_cv_LIBEVENT_CORE_CFLAGS="$LIBEVENT_CORE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent_core >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent_core >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CORE_CFLAGS=`$PKG_CONFIG --cflags "libevent_core >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBEVENT_CORE_LIBS"; then pkg_cv_LIBEVENT_CORE_LIBS="$LIBEVENT_CORE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent_core >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent_core >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CORE_LIBS=`$PKG_CONFIG --libs "libevent_core >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBEVENT_CORE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libevent_core >= 2" 2>&1` else LIBEVENT_CORE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libevent_core >= 2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBEVENT_CORE_PKG_ERRORS" >&5 found_libevent=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libevent=no else LIBEVENT_CORE_CFLAGS=$pkg_cv_LIBEVENT_CORE_CFLAGS LIBEVENT_CORE_LIBS=$pkg_cv_LIBEVENT_CORE_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libevent_CFLAGS="$LIBEVENT_CORE_CFLAGS" libevent_LIBS="$LIBEVENT_CORE_LIBS" found_libevent=yes fi if test x$found_libevent = xno; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libevent >= 2" >&5 printf %s "checking for libevent >= 2... " >&6; } if test -n "$LIBEVENT_CFLAGS"; then pkg_cv_LIBEVENT_CFLAGS="$LIBEVENT_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_CFLAGS=`$PKG_CONFIG --cflags "libevent >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBEVENT_LIBS"; then pkg_cv_LIBEVENT_LIBS="$LIBEVENT_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libevent >= 2\""; } >&5 ($PKG_CONFIG --exists --print-errors "libevent >= 2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBEVENT_LIBS=`$PKG_CONFIG --libs "libevent >= 2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBEVENT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libevent >= 2" 2>&1` else LIBEVENT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libevent >= 2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBEVENT_PKG_ERRORS" >&5 found_libevent=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libevent=no else LIBEVENT_CFLAGS=$pkg_cv_LIBEVENT_CFLAGS LIBEVENT_LIBS=$pkg_cv_LIBEVENT_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libevent_CFLAGS="$LIBEVENT_CFLAGS" libevent_LIBS="$LIBEVENT_LIBS" found_libevent=yes fi fi if test x$found_libevent = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing event_init" >&5 printf %s "checking for library containing event_init... " >&6; } if test ${ac_cv_search_event_init+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char event_init (void); int main (void) { return event_init (); ; return 0; } _ACEOF for ac_lib in '' event_core event event-1.4 do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_event_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_event_init+y} then : break fi done if test ${ac_cv_search_event_init+y} then : else case e in #( e) ac_cv_search_event_init=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_event_init" >&5 printf "%s\n" "$ac_cv_search_event_init" >&6; } ac_res=$ac_cv_search_event_init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_libevent=yes else case e in #( e) found_libevent=no ;; esac fi if test "x$found_libevent" = "xyes"; then libevent_LIBS="$ac_cv_search_event_init" fi fi if test x$found_libevent = xno; then ac_fn_c_check_header_compile "$LINENO" "event2/event.h" "ac_cv_header_event2_event_h" "$ac_includes_default" if test "x$ac_cv_header_event2_event_h" = xyes then : printf "%s\n" "#define HAVE_EVENT2_EVENT_H 1" >>confdefs.h else case e in #( e) ac_fn_c_check_header_compile "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default" if test "x$ac_cv_header_event_h" = xyes then : printf "%s\n" "#define HAVE_EVENT_H 0" >>confdefs.h else case e in #( e) found_libevent=no ;; esac fi ;; esac fi fi if test "x$found_libevent" = xno; then as_fn_error $? "\"libevent not found\"" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "uuid_create" "ac_cv_func_uuid_create" if test "x$ac_cv_func_uuid_create" = xyes then : found_uuid=yes else case e in #( e) found_uuid=no ;; esac fi # Don't define HAVE_BSD_UUID on darwin (Apple) as this breaks the BSD API. # Instead, use the UUID implementation wrapper that's in compat/ plus uuid # ossp if test "x$found_uuid" = "xyes" -a "x$PLATFORM" != "darwin"; then printf "%s\n" "#define HAVE_BSD_UUID 1" >>confdefs.h else pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uuid" >&5 printf %s "checking for uuid... " >&6; } if test -n "$LIBUUID_CFLAGS"; then pkg_cv_LIBUUID_CFLAGS="$LIBUUID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_CFLAGS=`$PKG_CONFIG --cflags "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBUUID_LIBS"; then pkg_cv_LIBUUID_LIBS="$LIBUUID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBUUID_LIBS=`$PKG_CONFIG --libs "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBUUID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "uuid" 2>&1` else LIBUUID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "uuid" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBUUID_PKG_ERRORS" >&5 found_libuuid=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_libuuid=no else LIBUUID_CFLAGS=$pkg_cv_LIBUUID_CFLAGS LIBUUID_LIBS=$pkg_cv_LIBUUID_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libuuid_CFLAGS="$LIBUUID_CFLAGS" libuuid_LIBS="$LIBUUID_LIBS" found_libuuid=yes fi if test "x$found_libuuid" = "xno"; then ac_fn_c_check_header_compile "$LINENO" "uuid.h" "ac_cv_header_uuid_h" "$ac_includes_default" if test "x$ac_cv_header_uuid_h" = xyes then : found_libuuid=yes else case e in #( e) found_libuuid=no ;; esac fi fi fi if test "x$found_libuuid" = "xno"; then as_fn_error $? "\"*** couldn't find uuid ***\"" "$LINENO" 5 fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib" >&5 printf %s "checking for zlib... " >&6; } if test -n "$ZLIB_CFLAGS"; then pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$ZLIB_LIBS"; then pkg_cv_ZLIB_LIBS="$ZLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1` else ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ZLIB_PKG_ERRORS" >&5 found_zlib=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_zlib=no else ZLIB_CFLAGS=$pkg_cv_ZLIB_CFLAGS ZLIB_LIBS=$pkg_cv_ZLIB_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } zlib_CFLAGS="$ZLIB_CFLAGS" zlib_LIBS="$ZLIB_LIBS" found_zlib=yes fi if test "x$found_zlib" = "xno"; then ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes then : else case e in #( e) found_zlib=no ;; esac fi fi if test "x$found_zlib" = "xno"; then as_fn_error $? "\"*** couldn't find zlib ***\"" "$LINENO" 5 fi if test "$PLATFORM" = "linux"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libbsd-overlay" >&5 printf %s "checking for libbsd-overlay... " >&6; } if test -n "$LIBBSD_CFLAGS"; then pkg_cv_LIBBSD_CFLAGS="$LIBBSD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_CFLAGS=`$PKG_CONFIG --cflags "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBBSD_LIBS"; then pkg_cv_LIBBSD_LIBS="$LIBBSD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libbsd-overlay\""; } >&5 ($PKG_CONFIG --exists --print-errors "libbsd-overlay") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBBSD_LIBS=`$PKG_CONFIG --libs "libbsd-overlay" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBBSD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libbsd-overlay" 2>&1` else LIBBSD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libbsd-overlay" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBBSD_PKG_ERRORS" >&5 as_fn_error $? "\"*** couldn't find libbsd-overlay via pkg-config\"" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "\"*** couldn't find libbsd-overlay via pkg-config\"" "$LINENO" 5 else LIBBSD_CFLAGS=$pkg_cv_LIBBSD_CFLAGS LIBBSD_LIBS=$pkg_cv_LIBBSD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libbsd_CFLAGS="$LIBBSD_CFLAGS" libbsd_LIBS="$LIBBSD_LIBS" printf "%s\n" "#define HAVE_LIBBSD 1" >>confdefs.h printf "%s\n" "#define HAVE_TREE_H test x\"\$found_sys_tree_h\" = \"xyes\"" >>confdefs.h fi # Add LIBBSD_{CFLAGS,LIBS} to the environment here, as libbsd puts its # header files in a non-standard location, which means the overlay for # and won't be found. CFLAGS="$CFLAGS $LIBBSD_CFLAGS" LIBS="$LIBS $LIBBSD_LIBS" pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libmd" >&5 printf %s "checking for libmd... " >&6; } if test -n "$LIBMD_CFLAGS"; then pkg_cv_LIBMD_CFLAGS="$LIBMD_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBMD_CFLAGS=`$PKG_CONFIG --cflags "libmd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBMD_LIBS"; then pkg_cv_LIBMD_LIBS="$LIBMD_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmd\""; } >&5 ($PKG_CONFIG --exists --print-errors "libmd") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBMD_LIBS=`$PKG_CONFIG --libs "libmd" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmd" 2>&1` else LIBMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmd" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBMD_PKG_ERRORS" >&5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else LIBMD_CFLAGS=$pkg_cv_LIBMD_CFLAGS LIBMD_LIBS=$pkg_cv_LIBMD_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libmd_CFLAGS="$LIBMD_CFLAGS" libmd_LIBS="$LIBMD_LIBS" fi CFLAGS="$CFLAGS $LIBMD_CFLAGS" LIBS="$LIBS $LIBMD_LIBS" fi # Look for a suitable queue.h. We hope libbsd is enough, but that is missing # some declarations. ac_fn_check_decl "$LINENO" "TAILQ_CONCAT" "ac_cv_have_decl_TAILQ_CONCAT" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_CONCAT" = xyes then : found_queue_h=yes else case e in #( e) found_queue_h=no ;; esac fi ac_fn_check_decl "$LINENO" "TAILQ_PREV" "ac_cv_have_decl_TAILQ_PREV" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_PREV" = xyes then : else case e in #( e) found_queue_h=no ;; esac fi ac_fn_check_decl "$LINENO" "TAILQ_FOREACH_SAFE" "ac_cv_have_decl_TAILQ_FOREACH_SAFE" "#include " "$ac_c_undeclared_builtin_options" "CFLAGS" if test "x$ac_cv_have_decl_TAILQ_FOREACH_SAFE" = xyes then : else case e in #( e) found_queue_h=no ;; esac fi if test "x$found_queue_h" = xyes; then printf "%s\n" "#define HAVE_QUEUE_H 1" >>confdefs.h else as_fn_error $? "\"*** sys/queue.h missing key defines ***" "$LINENO" 5 fi # Look for crypto (part of openssl) # Note: libcrypto (via openssl) has a .pc file in pretty-much all distros and # BSDs which we support. pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libcrypto" >&5 printf %s "checking for libcrypto... " >&6; } if test -n "$LIBCRYPTO_CFLAGS"; then pkg_cv_LIBCRYPTO_CFLAGS="$LIBCRYPTO_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcrypto\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcrypto") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBCRYPTO_CFLAGS=`$PKG_CONFIG --cflags "libcrypto" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBCRYPTO_LIBS"; then pkg_cv_LIBCRYPTO_LIBS="$LIBCRYPTO_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcrypto\""; } >&5 ($PKG_CONFIG --exists --print-errors "libcrypto") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBCRYPTO_LIBS=`$PKG_CONFIG --libs "libcrypto" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBCRYPTO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcrypto" 2>&1` else LIBCRYPTO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcrypto" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBCRYPTO_PKG_ERRORS" >&5 as_fn_error $? "\"*** Couldn't find libcrypto ***\"" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "\"*** Couldn't find libcrypto ***\"" "$LINENO" 5 else LIBCRYPTO_CFLAGS=$pkg_cv_LIBCRYPTO_CFLAGS LIBCRYPTO_LIBS=$pkg_cv_LIBCRYPTO_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libcrypto_CFLAGS="$LIBCRYPTO_CFLAGS" libcrypto_LIBS="$LIBCRYPTO_LIBS" fi if test "x$PLATFORM" != "xopenbsd"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtls" >&5 printf %s "checking for libtls... " >&6; } if test -n "$LIBTLS_CFLAGS"; then pkg_cv_LIBTLS_CFLAGS="$LIBTLS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBTLS_CFLAGS=`$PKG_CONFIG --cflags "libtls" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBTLS_LIBS"; then pkg_cv_LIBTLS_LIBS="$LIBTLS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtls\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtls") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBTLS_LIBS=`$PKG_CONFIG --libs "libtls" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBTLS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libtls" 2>&1` else LIBTLS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libtls" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBTLS_PKG_ERRORS" >&5 as_fn_error $? "\"*** Couldn't find libtls ***\"" "$LINENO" 5 elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "\"*** Couldn't find libtls ***\"" "$LINENO" 5 else LIBTLS_CFLAGS=$pkg_cv_LIBTLS_CFLAGS LIBTLS_LIBS=$pkg_cv_LIBTLS_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } libtls_CFLAGS="$LIBTLS_CFLAGS" libtls_LIBS="$LIBTLS_LIBS" fi fi # Look for __progname. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __progname" >&5 printf %s "checking for __progname... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern char *__progname; int main(void) { const char *cp = __progname; printf("%s\n", cp); exit(0); } _ACEOF if ac_fn_c_try_link "$LINENO" then : printf "%s\n" "#define HAVE___PROGNAME 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else case e in #( e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panelw" >&5 printf %s "checking for panelw... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "panelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "panelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panelw" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panelw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi if test "x$found_panel" = "xno"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gnupanelw" >&5 printf %s "checking for gnupanelw... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "gnupanelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "gnupanelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gnupanelw\""; } >&5 ($PKG_CONFIG --exists --print-errors "gnupanelw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "gnupanelw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gnupanelw" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gnupanelw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi fi if test "x$found_panel" = "xno"; then pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for panel" >&5 printf %s "checking for panel... " >&6; } if test -n "$LIBPANELW_CFLAGS"; then pkg_cv_LIBPANELW_CFLAGS="$LIBPANELW_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_CFLAGS=`$PKG_CONFIG --cflags "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBPANELW_LIBS"; then pkg_cv_LIBPANELW_LIBS="$LIBPANELW_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"panel\""; } >&5 ($PKG_CONFIG --exists --print-errors "panel") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBPANELW_LIBS=`$PKG_CONFIG --libs "panel" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "panel" 2>&1` else LIBPANELW_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "panel" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBPANELW_PKG_ERRORS" >&5 found_panel=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_panel=no else LIBPANELW_CFLAGS=$pkg_cv_LIBPANELW_CFLAGS LIBPANELW_LIBS=$pkg_cv_LIBPANELW_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes fi fi if test "x$found_panel" = "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for update_panels in -lpanelw" >&5 printf %s "checking for update_panels in -lpanelw... " >&6; } if test ${ac_cv_lib_panelw_update_panels+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpanelw -lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char update_panels (void); int main (void) { return update_panels (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_panelw_update_panels=yes else case e in #( e) ac_cv_lib_panelw_update_panels=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_panelw_update_panels" >&5 printf "%s\n" "$ac_cv_lib_panelw_update_panels" >&6; } if test "x$ac_cv_lib_panelw_update_panels" = xyes then : printf "%s\n" "#define HAVE_LIBPANELW 1" >>confdefs.h LIBS="-lpanelw $LIBS" else case e in #( e) as_fn_error $? " \"*** panelw not found for ncurses. ***\"" "$LINENO" 5 ;; esac fi fi pkg_failed=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ncursesw" >&5 printf %s "checking for ncursesw... " >&6; } if test -n "$LIBNCURSES_CFLAGS"; then pkg_cv_LIBNCURSES_CFLAGS="$LIBNCURSES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNCURSES_CFLAGS=`$PKG_CONFIG --cflags "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBNCURSES_LIBS"; then pkg_cv_LIBNCURSES_LIBS="$LIBNCURSES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ncursesw\""; } >&5 ($PKG_CONFIG --exists --print-errors "ncursesw") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBNCURSES_LIBS=`$PKG_CONFIG --libs "ncursesw" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBNCURSES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ncursesw" 2>&1` else LIBNCURSES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ncursesw" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBNCURSES_PKG_ERRORS" >&5 found_ncurses=no elif test $pkg_failed = untried; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } found_ncurses=no else LIBNCURSES_CFLAGS=$pkg_cv_LIBNCURSES_CFLAGS LIBNCURSES_LIBS=$pkg_cv_LIBNCURSES_LIBS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } found_ncurses=yes fi if test "x$found_ncurses" = xyes; then libncurses_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $LIBPANELW_CFLAGS" libncurses_LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBPANELW_LIBS" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing setupterm" >&5 printf %s "checking for library containing setupterm... " >&6; } if test ${ac_cv_search_setupterm+y} then : printf %s "(cached) " >&6 else case e in #( e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. The 'extern "C"' is for builds by C++ compilers; although this is not generally supported in C code supporting it here has little cost and some practical benefit (sr 110532). */ #ifdef __cplusplus extern "C" #endif char setupterm (void); int main (void) { return setupterm (); ; return 0; } _ACEOF for ac_lib in '' found_ncurses=yes do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_setupterm=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_setupterm+y} then : break fi done if test ${ac_cv_search_setupterm+y} then : else case e in #( e) ac_cv_search_setupterm=no ;; esac fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_setupterm" >&5 printf "%s\n" "$ac_cv_search_setupterm" >&6; } ac_res=$ac_cv_search_setupterm if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" found_ncurses=no fi if test "x$found_ncurses" = xyes; then ac_fn_c_check_header_compile "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default" if test "x$ac_cv_header_ncurses_h" = xyes then : libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw" fi fi fi if test "x$found_ncurses" = xyes; then printf "%s\n" "#define HAVE_NCURSES_H 1" >>confdefs.h else # No ncurses, try curses. ac_fn_c_check_func "$LINENO" "setupterm" "ac_cv_func_setupterm" if test "x$ac_cv_func_setupterm" = xyes then : found_curses=yes else case e in #( e) found_curses=no ;; esac fi ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default" if test "x$ac_cv_header_curses_h" = xyes then : found_curses=yes else case e in #( e) found_curses=no ;; esac fi if test "x$found_curses" = xyes; then libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw -lpanelw" printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h else as_fn_error $? "\"curses not found\"" "$LINENO" 5 fi fi # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # variables. CPPFLAGS="$SAVED_CPPFLAGS" CFLAGS="$SAVED_CFLAGS" LDFLAGS="$SAVED_LDFLAGS" # LIBS is designed to accumulate library dependencies as checks for them are # peformed, so that this can be included directly to ld(1). # # However, this hinders the splitting up of the library dependencies so that # they're targetted just where they're needed. Flatting LIBS here ensures # that this happens appropriately. LIBS="" if test "x$enable_cvg" = xyes; then CVG_ENABLED_TRUE= CVG_ENABLED_FALSE='#' else CVG_ENABLED_TRUE='#' CVG_ENABLED_FALSE= fi ac_config_files="$ac_config_files Makefile compat/Makefile gitwrapper/Makefile got/Makefile gotadmin/Makefile gotctl/Makefile gotd/Makefile gotd/libexec/Makefile gotd/libexec/got-notify-email/Makefile gotd/libexec/got-notify-http/Makefile gotsh/Makefile gotwebd/Makefile libexec/Makefile libexec/got-fetch-http/Makefile libexec/got-fetch-pack/Makefile libexec/got-index-pack/Makefile libexec/got-read-blob/Makefile libexec/got-read-commit/Makefile libexec/got-read-gitconfig/Makefile libexec/got-read-gotconfig/Makefile libexec/got-read-object/Makefile libexec/got-read-pack/Makefile libexec/got-read-patch/Makefile libexec/got-read-tag/Makefile libexec/got-read-tree/Makefile libexec/got-send-pack/Makefile tog/Makefile Makefile.common:Makefile.common.in" if test "x$enable_cvg" = "xyes"; then ac_config_files="$ac_config_files cvg/Makefile" fi cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # 'ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # 'set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; esac if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SHA2_TRUE}" && test -z "${HAVE_SHA2_FALSE}"; then as_fn_error $? "conditional \"HAVE_SHA2\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_GETOPT_TRUE}" && test -z "${HAVE_GETOPT_FALSE}"; then as_fn_error $? "conditional \"HAVE_GETOPT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SETPROCTITLE_TRUE}" && test -z "${HAVE_SETPROCTITLE_FALSE}"; then as_fn_error $? "conditional \"HAVE_SETPROCTITLE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_SIPHASH_TRUE}" && test -z "${HAVE_SIPHASH_FALSE}"; then as_fn_error $? "conditional \"HAVE_SIPHASH\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_CLOSEFROM_TRUE}" && test -z "${HAVE_CLOSEFROM_FALSE}"; then as_fn_error $? "conditional \"HAVE_CLOSEFROM\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_B64_TRUE}" && test -z "${HAVE_B64_FALSE}"; then as_fn_error $? "conditional \"HAVE_B64\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_FREEBSD_TRUE}" && test -z "${HOST_FREEBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_FREEBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_LINUX_TRUE}" && test -z "${HOST_LINUX_FALSE}"; then as_fn_error $? "conditional \"HOST_LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_DARWIN_TRUE}" && test -z "${HOST_DARWIN_FALSE}"; then as_fn_error $? "conditional \"HOST_DARWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_NETBSD_TRUE}" && test -z "${HOST_NETBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_NETBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_OPENBSD_TRUE}" && test -z "${HOST_OPENBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_OPENBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HOST_DRAGONFLYBSD_TRUE}" && test -z "${HOST_DRAGONFLYBSD_FALSE}"; then as_fn_error $? "conditional \"HOST_DRAGONFLYBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_LINUX_LANDLOCK_TRUE}" && test -z "${HAVE_LINUX_LANDLOCK_FALSE}"; then as_fn_error $? "conditional \"HAVE_LINUX_LANDLOCK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAVE_IMSG_TRUE}" && test -z "${HAVE_IMSG_FALSE}"; then as_fn_error $? "conditional \"HAVE_IMSG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CVG_ENABLED_TRUE}" && test -z "${CVG_ENABLED_FALSE}"; then as_fn_error $? "conditional \"CVG_ENABLED\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case e in #( e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else case e in #( e) as_fn_append () { eval $1=\$$1\$2 } ;; esac fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else case e in #( e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } ;; esac fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by got-portable $as_me 0.119, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ '$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ got-portable config.status 0.119 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" Copyright (C) 2023 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: '$1' Try '$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: '$1' Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "include/got_compat.h") CONFIG_HEADERS="$CONFIG_HEADERS include/got_compat.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "compat/Makefile") CONFIG_FILES="$CONFIG_FILES compat/Makefile" ;; "gitwrapper/Makefile") CONFIG_FILES="$CONFIG_FILES gitwrapper/Makefile" ;; "got/Makefile") CONFIG_FILES="$CONFIG_FILES got/Makefile" ;; "gotadmin/Makefile") CONFIG_FILES="$CONFIG_FILES gotadmin/Makefile" ;; "gotctl/Makefile") CONFIG_FILES="$CONFIG_FILES gotctl/Makefile" ;; "gotd/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/Makefile" ;; "gotd/libexec/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/Makefile" ;; "gotd/libexec/got-notify-email/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/got-notify-email/Makefile" ;; "gotd/libexec/got-notify-http/Makefile") CONFIG_FILES="$CONFIG_FILES gotd/libexec/got-notify-http/Makefile" ;; "gotsh/Makefile") CONFIG_FILES="$CONFIG_FILES gotsh/Makefile" ;; "gotwebd/Makefile") CONFIG_FILES="$CONFIG_FILES gotwebd/Makefile" ;; "libexec/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/Makefile" ;; "libexec/got-fetch-http/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-fetch-http/Makefile" ;; "libexec/got-fetch-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-fetch-pack/Makefile" ;; "libexec/got-index-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-index-pack/Makefile" ;; "libexec/got-read-blob/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-blob/Makefile" ;; "libexec/got-read-commit/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-commit/Makefile" ;; "libexec/got-read-gitconfig/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-gitconfig/Makefile" ;; "libexec/got-read-gotconfig/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-gotconfig/Makefile" ;; "libexec/got-read-object/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-object/Makefile" ;; "libexec/got-read-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-pack/Makefile" ;; "libexec/got-read-patch/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-patch/Makefile" ;; "libexec/got-read-tag/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-tag/Makefile" ;; "libexec/got-read-tree/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-read-tree/Makefile" ;; "libexec/got-send-pack/Makefile") CONFIG_FILES="$CONFIG_FILES libexec/got-send-pack/Makefile" ;; "tog/Makefile") CONFIG_FILES="$CONFIG_FILES tog/Makefile" ;; "Makefile.common") CONFIG_FILES="$CONFIG_FILES Makefile.common:Makefile.common.in" ;; "cvg/Makefile") CONFIG_FILES="$CONFIG_FILES cvg/Makefile" ;; *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See 'config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 printf "%s\n" "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi executables="$(eval echo ${exec_prefix}/bin)" helpers="$(eval echo ${libexecdir})" manpages="$(eval echo ${mandir})" gotdep="$GOTD_EMPTY_PATHC" gotgwlep="$GITWRAPPER_LIBEXEC_PATHC" if test -z "$enable_cvg"; then enable_cvg="no" fi if test -z "$gotdep"; then gotdep="N/A" fi if test -z "$gotgwlep"; then gotgwlep="N/A" fi echo " Configured got-portable with: Version: $VERSION Prefix: ${prefix} Executables: ${executables} Bison: $YACC CFlags: $CFLAGS cvg: ${enable_cvg} Gotd: Empty Path: ${gotdep} Gitwrapper: ${gotgwlep} Helpers: ${helpers} Man pages: ${manpages} " got-portable-0.119/configure.ac0000664000175000017500000005521615066536113012113 # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([got-portable], m4_esyscmd_s(util/got-portable-ver.sh), [thomas@xteddy.org]) AC_CONFIG_AUX_DIR(etc) AC_CONFIG_SRCDIR([lib/rcsutil.h]) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_HEADERS([include/got_compat.h]) AC_DEFINE_UNQUOTED(VERSION, $VERSION) AC_SUBST(VERSION) AC_SUBST(GOT_RELEASE) AC_DEFINE_UNQUOTED([GOT_VERSION], VERSION, [GoT version string]) AC_DEFINE_UNQUOTED([GOT_VERSION_NUMBER], VERSION, [Got version number]) AC_USE_SYSTEM_EXTENSIONS AC_CANONICAL_HOST AC_CONFIG_SUBDIRS([template]) AC_ARG_ENABLE([cvg], AS_HELP_STRING([--enable-cvg], [EXPERIMENTAL: cvg - cvs-like-git])) # Override gotd's empty_path location. AC_ARG_WITH([gotd-empty-path], [AS_HELP_STRING([--with-gotd-empty-path], [gotd empty path]) ], [GOTD_EMPTY_PATHC=$withval] []) AC_SUBST(GOTD_EMPTY_PATHC) # Override where git's libexec helpers are located for gitwrapper. AC_ARG_WITH([gitwrapper-git-libexec-path], [AS_HELP_STRING([--with-gitwrapper-git-libexec-path], [git libexec path for gitwrapper]) ], [GITWRAPPER_LIBEXEC_PATHC=$withval] []) AC_SUBST(GITWRAPPER_LIBEXEC_PATHC) # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. : ${CFLAGS=""} # Save user CPPFLAGS, CFLAGS and LDFLAGS. We need to change them because # AC_CHECK_HEADER doesn't give us any other way to update the include # paths. But for Makefile.am we want to use AM_CPPFLAGS and friends. SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" # YACC override YACC_OVERRIDE="yes" # Checks for programs. AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET if test -z "$YACC"; then YACC_OVERRIDE="no" AC_PROG_YACC fi AM_PROG_AR AC_PROG_RANLIB PKG_PROG_PKG_CONFIG if test "$YACC_OVERRIDE" = "yes"; then AC_MSG_NOTICE("Using YACC set from environment: $YACC") fi # Checks for header files. AC_CHECK_HEADERS([ \ fcntl.h \ getopt.h \ langinfo.h \ libutil.h \ limits.h \ linux/landlock.h \ locale.h \ netdb.h \ netinet/in.h \ paths.h \ poll.h \ sha.h \ sha1.h \ sha2.h \ sha256.h \ stddef.h \ stdint.h \ stdlib.h \ string.h \ sys/ioctl.h \ sys/param.h \ sys/poll.h \ sys/queue.h \ sys/select.h \ sys/socket.h \ sys/time.h \ sys/tree.h \ tls.h \ util.h \ unistd.h \ wchar.h \ ]) AC_HEADER_DIRENT AC_CHECK_DECL([F_CLOSEM], HAVE_FCNTL_CLOSEM AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], [Use F_CLOSEM fcntl for closefrom]), [], [#include #include ] ) AC_MSG_CHECKING([for /proc/pid/fd directory]) if test -d "/proc/$$/fd" ; then AC_DEFINE([HAVE_PROC_PID], [1], [Define if you have /proc/$pid/fd]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_MSG_CHECKING([whether program_invocation_short_name is defined]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ program_invocation_short_name = "test"; ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_PROGRAM_INVOCATION_SHORT_NAME], [1], [Define if program_invocation_short_name is defined]) ], [ AC_MSG_RESULT([no]) ]) # Look for prctl(PR_SET_NAME). AC_CHECK_DECL( [PR_SET_NAME], [AC_DEFINE([HAVE_PR_SET_NAME], [1], [Define if PR_SET_NAME is defined])], [], [#include ] ) AM_CONDITIONAL([HAVE_SHA2], [test "x$ac_cv_header_sha2_h" = xyes || \ test "x$ac_cv_header_sha256_h" = xyes]) AC_CACHE_CHECK([whether getopt has optreset support], ac_cv_have_getopt_optreset, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ extern int optreset; optreset = 0; ]])], [ ac_cv_have_getopt_optreset="yes" ], [ ac_cv_have_getopt_optreset="no" ]) ]) AM_CONDITIONAL([HAVE_GETOPT], [test "x$ac_cv_have_getopt_optreset" = "xyes"]) if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then AC_DEFINE([HAVE_GETOPT_OPTRESET], [1], [Define if your getopt(3) defines and uses optreset]) fi AC_CHECK_MEMBERS([struct pollfd.fd], [], [], [[ #include #ifdef HAVE_POLL_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif ]]) # Checks for typ edefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT64_T AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Check for ifgroupreq which is only available on BSD. AC_CHECK_TYPES([struct ifgroupreq]) # Check for sockaddr_storage. On some systems, ss_len is filled out, although # this is not mandated by POSIX, and hence systems such as linux, don't have # it. AC_CHECK_TYPES([struct sockaddr_storage], [], [], [ #include #include ]) # Same thing as sockaddr_storage above, only now check if the member exists in # the struct as well. AC_CHECK_MEMBERS([struct sockaddr_storage.ss_len], , , [ #include #include #include ] ) AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , [ #include #include #include ] ) # Both checks above will result in: # # HAVE_STRUCT_SOCKADDR_AS_LEN # SS_LEN # # Either being defined or not. # Look for library needed for flock. AC_SEARCH_LIBS(flock, bsd) # Checks for library functions. AC_FUNC_FORK AC_FUNC_FSEEKO AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_MMAP AC_FUNC_REALLOC AC_FUNC_STRERROR_R AC_FUNC_STRNLEN AC_CHECK_FUNCS([ \ dup2 \ flock \ getcwd \ localtime_r \ memchr \ memmove \ memset \ mergesort \ mkdir \ munmap \ nl_langinfo \ realpath \ regcomp \ rmdir \ setlocale \ socket \ setresgid \ setresuid \ setproctitle \ strcasecmp \ strchr \ strcspn \ strdup \ strerror \ strncasecmp \ strndup \ strrchr \ strspn \ strstr \ strtol \ strtoul \ sysconf \ wcwidth \ ]) AC_CHECK_DECL( RB_GENERATE_STATIC, found_sys_tree_h=yes, found_sys_tree_h=no, [#include ] ) AM_CONDITIONAL([HAVE_SETPROCTITLE], [test "x$ac_cv_func_setproctitle" = xyes]) if test "x$ac_cv_func_sysconf" = xyes; then AC_DEFINE([HAVE_SYSCONF], [1], [Define to 1 if sysconf() present]) fi # Siphash support. AC_CHECK_FUNCS([SipHash]) AM_CONDITIONAL([HAVE_SIPHASH], [test "x$ac_cv_func_SipHash" = xyes]) # Check for functions with a compatibility implementation. AC_REPLACE_FUNCS([ \ asprintf \ closefrom \ explicit_bzero \ fmt_scaled \ freezero \ getdtablecount \ getline \ getprogname \ recallocarray \ reallocarray \ strlcat \ strlcpy \ strndup \ strnlen \ strsep \ strtonum \ ]) AM_CONDITIONAL([HAVE_CLOSEFROM], [test "x$ac_cv_func_closefrom" = xyes]) # Always use our getopt because 1) glibc's doesn't enforce argument order 2) # musl does not set optarg to NULL for flags without arguments (although it is # not required to, but it is helpful) 3) there are probably other weird # implementations. AC_LIBOBJ(getopt) # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="" if test "x$found_b64_ntop" = xno; then AC_MSG_CHECKING(for b64_ntop with -lresolv) LIBS="-lresolv" AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="$LIBS" fi if test "x$found_b64_ntop" = xno; then AC_MSG_CHECKING(for b64_ntop with -lnetwork) LIBS="-lresolv -lnetwork" AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include #include ], [ b64_ntop(NULL, 0, NULL, 0); ])], found_b64_ntop=yes, found_b64_ntop=no ) AC_MSG_RESULT($found_b64_ntop) libresolv_LIBS="$LIBS" fi AM_CONDITIONAL([HAVE_B64], [test "x$found_b64_ntop" = xyes]) if test "x$found_b64_ntop" = xyes; then AC_DEFINE([HAVE_B64_NTOP], [1], [define if b64_ntop is present]) AC_SUBST(libresolv_LIBS) else AC_LIBOBJ(base64) fi # Check the platform we're compiling on. AC_MSG_CHECKING(platform) case "$host_os" in *linux*) AC_MSG_RESULT(linux) PLATFORM=linux ;; *freebsd*) AC_MSG_RESULT(freebsd) PLATFORM=freebsd ;; *darwin*) AC_MSG_RESULT(darwin) PLATFORM=darwin ;; *netbsd*) AC_MSG_RESULT(netbsd) PLATFORM=netbsd ;; *openbsd*) AC_MSG_RESULT(openbsd) PLATFORM=openbsd ;; *dragonfly*) AC_MSG_RESULT(dragonfly) PLATFORM=dragonflybsd ;; *) AC_MSG_RESULT(unknown) PLATFORM=unknown ;; esac AC_SUBST(PLATFORM) AM_CONDITIONAL([HOST_FREEBSD], [test "$PLATFORM" = "freebsd"]) AM_CONDITIONAL([HOST_LINUX], [test "$PLATFORM" = "linux"]) AM_CONDITIONAL([HOST_DARWIN], [test "$PLATFORM" = "darwin"]) AM_CONDITIONAL([HOST_NETBSD], [test "$PLATFORM" = "netbsd"]) AM_CONDITIONAL([HOST_OPENBSD], [test "$PLATFORM" = "openbsd"]) AM_CONDITIONAL([HOST_DRAGONFLYBSD], [test "$PLATFORM" = "dragonflybsd"]) # On OpenBSD, these functions are already defined, yet looking for them in # this way on OpenBSD breaks inclusion. # FIXME: this needs addressing. if test "x$PLATFORM" != "xopenbsd"; then AC_CHECK_FUNCS([SHA256Update]) fi # Look for yacc. if test "YACC_OVERRIDE" = "yes" && test -n "$YACC" \ && ! command -v "$YACC" >/dev/null 2>&1; then AC_MSG_ERROR("yacc not found: $YACC") fi if test x"$PLATFORM" = "xdarwin"; then # Check for and/or set HOMEBREW_PREFIX. brew is a common way of # installing applications. The other is MacPorts. # # Before Apple Silicon existed (M1 onward), the paths for applications # installed via homebrew was typically /usr/local. However, with M1 # onward, this changed to a different path. # # Rather than hardcode this, check for HOMEBREW_PREFIX in the # environment if it's already set, and use it. Otherwise, check for # brew(1) and use that. If that fails, default to /usr/local # # This also means that MacPorts should continue to work. # # But with MacPorts, we should also check --prefix, and use that if it # has been supplied. # # In both cases, the variable HOMEBREW_PREFIX is used for both. HB_PREFIX="" FOUND_BISON="no" GNUBISON="" if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE"; then # HOMEBREW_PREFIX not set, check for brew(1) if command -v brew >/dev/null 2>&1; then AC_MSG_NOTICE("HOMEBREW_PREFIX set via 'brew --prefix'") export HOMEBREW_PREFIX="$(brew --prefix)" fi if test -z "$HOMEBREW_PREFIX" -o "$HOMEBREW_PREFIX" = "NONE" then # Default. if test -z "${prefix}" -o "${prefix}" = "NONE"; then export HOMEBREW_PREFIX="/usr/local" HB_PREFIX="/usr/local" AC_MSG_NOTICE("HOMEBREW_PREFIX defaulting to $HB_PREFIX") else HB_PREFIX="$(eval echo ${prefix})" if test "$HB_PREFIX" = "NONE"; then HB_PREFIX="/opt/local" else AC_MSG_NOTICE("HOMEBREW_PREFIX using --prefix") fi export HOMEBREW_PREFIX="$HB_PREFIX" fi fi fi AC_MSG_NOTICE("HOMEBREW_PREFIX determined as: $HOMEBREW_PREFIX") if test "$YACC_OVERRIDE" = "no" && \ ! test -x "${HOMEBREW_PREFIX}/opt/bison/bin/bison"; then AC_MSG_WARN([ "*********************************************************** GNU Bison not found: ${HOMEBREW_PREFIX}/opt/bison/bin/bison *********************************************************** Falling back to checking either /usr/local or \${prefix}" ]) FOUND_BISON="no" AC_MSG_WARN("Trying ${HB_PREFIX}/opt/bison/bin/bison") if test -x "${HB_PREFIX}/opt/bison/bin/bison"; then export HOMEBREW_PREFIX="/usr/local" FOUND_BISON="yes" GNUBISON="${HB_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no"; then HB_PREFIX="/opt/local" AC_MSG_WARN("Trying ${HB_PREFIX}/bin/bison") if test -x "${HB_PREFIX}/bin/bison"; then export HOMEBREW_PREFIX="${HB_PREFIX}" GNUBISON="${HB_PREFIX}/bin/bison" FOUND_BISON="yes" fi fi else FOUND_BISON="yes" GNUBISON="${HOMEBREW_PREFIX}/opt/bison/bin/bison" fi if test "$FOUND_BISON" = "no" && test "$YACC_OVERRIDE" = "no"; then AC_MSG_ERROR("*** Couldn't find GNU BISON ***") fi # Override YACC here to point to the GNU version of bison. if test "$YACC_OVERRIDE" = "yes"; then export YACC="$YACC -y" else AC_MSG_NOTICE("Found GNU Bison as: $GNUBISON") export YACC="${GNUBISON} -y" fi export LDFLAGS="-L${HOMEBREW_PREFIX}/opt/ncurses/lib -L${HOMEBREW_PREFIX}/opt/openssl@3/lib $LDFLAGS" export CPPFLAGS="-I${HOMEBREW_PREFIX}/opt/ncurses/include -I${HOMEBREW_PREFIX}/opt/openssl@3/include $CPPFLAGS" export PKG_CONFIG_PATH="${HOMEBREW_PREFIX}/opt/ncurses/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig" fi # Landlock detection. AC_MSG_CHECKING([for landlock]) AM_CONDITIONAL([HAVE_LINUX_LANDLOCK], [test "x$ac_cv_header_linux_landlock_h" = "xyes"]) if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi # Clang sanitizers wrap reallocarray even if it isn't available on the target # system. When compiled it always returns NULL and crashes the program. To # detect this we need a more complicated test. AC_MSG_CHECKING([for working reallocarray]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [#include ], [return (reallocarray(NULL, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])] ) AC_MSG_CHECKING([for working recallocarray]) AC_RUN_IFELSE([AC_LANG_PROGRAM( [#include ], [return (recallocarray(NULL, 1, 1, 1) == NULL);] )], AC_MSG_RESULT(yes), [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])], [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])] ) # Look for imsg_init in libutil. AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no) AM_CONDITIONAL([HAVE_IMSG], [test "x$found_imsg_init" = "xyes"]) if test "x$found_imsg_init" = "xyes"; then AC_DEFINE([HAVE_IMSG], [1], [Define to 1 if imsg is declared in libutil]) libutil_LIBS="$ac_cv_search_imsg_init" AC_SUBST(libutil_LIBS) fi # libevent (for gotwebd). Lifted from tmux. # Look for libevent. Try libevent_core or libevent with pkg-config first then # look for the library. found_libevent=no PKG_CHECK_MODULES( LIBEVENT_CORE, [libevent_core >= 2], [ libevent_CFLAGS="$LIBEVENT_CORE_CFLAGS" libevent_LIBS="$LIBEVENT_CORE_LIBS" AC_SUBST(libevent_CFLAGS) AC_SUBST(libevent_LIBS) found_libevent=yes ], found_libevent=no ) if test x$found_libevent = xno; then PKG_CHECK_MODULES( LIBEVENT, [libevent >= 2], [ libevent_CFLAGS="$LIBEVENT_CFLAGS" libevent_LIBS="$LIBEVENT_LIBS" AC_SUBST(libevent_CFLAGS) AC_SUBST(libevent_LIBS) found_libevent=yes ], found_libevent=no ) fi if test x$found_libevent = xno; then AC_SEARCH_LIBS( event_init, [event_core event event-1.4], found_libevent=yes, found_libevent=no ) if test "x$found_libevent" = "xyes"; then libevent_LIBS="$ac_cv_search_event_init" AC_SUBST(libevent_LIBS) fi fi if test x$found_libevent = xno; then AC_CHECK_HEADER( event2/event.h, AC_DEFINE([HAVE_EVENT2_EVENT_H], [1], [libevent2 has event.h]), [ AC_CHECK_HEADER( event.h, AC_DEFINE([HAVE_EVENT_H], [0], [libevent]), found_libevent=no ) ] ) fi if test "x$found_libevent" = xno; then AC_MSG_ERROR("libevent not found") fi AC_CHECK_FUNC([uuid_create], [found_uuid=yes], [found_uuid=no]) # Don't define HAVE_BSD_UUID on darwin (Apple) as this breaks the BSD API. # Instead, use the UUID implementation wrapper that's in compat/ plus uuid # ossp if test "x$found_uuid" = "xyes" -a "x$PLATFORM" != "darwin"; then AC_DEFINE([HAVE_BSD_UUID], [1], [BSD UUID]) else PKG_CHECK_MODULES( LIBUUID, uuid, [ libuuid_CFLAGS="$LIBUUID_CFLAGS" libuuid_LIBS="$LIBUUID_LIBS" AC_SUBST(libuuid_CFLAGS) AC_SUBST(libuuid_LIBS) found_libuuid=yes ], [ found_libuuid=no ] ) if test "x$found_libuuid" = "xno"; then AC_CHECK_HEADER( uuid.h, found_libuuid=yes, found_libuuid=no) fi fi if test "x$found_libuuid" = "xno"; then AC_MSG_ERROR("*** couldn't find uuid ***") fi PKG_CHECK_MODULES( ZLIB, zlib, [ zlib_CFLAGS="$ZLIB_CFLAGS" zlib_LIBS="$ZLIB_LIBS" AC_SUBST(zlib_CFLAGS) AC_SUBST(zlib_LIBS) found_zlib=yes ], [ found_zlib=no ] ) if test "x$found_zlib" = "xno"; then AC_CHECK_HEADER( zlib.h, , found_zlib=no) fi if test "x$found_zlib" = "xno"; then AC_MSG_ERROR("*** couldn't find zlib ***") fi if test "$PLATFORM" = "linux"; then PKG_CHECK_MODULES( LIBBSD, libbsd-overlay, [ libbsd_CFLAGS="$LIBBSD_CFLAGS" libbsd_LIBS="$LIBBSD_LIBS" AC_SUBST(libbsd_CFLAGS) AC_SUBST(libbsd_LIBS) AC_DEFINE([HAVE_LIBBSD], [1], [BSD UUID]) AC_DEFINE([HAVE_TREE_H], [test x"$found_sys_tree_h" = "xyes"], [HAVE_TREE_H]) ], [ AC_MSG_ERROR("*** couldn't find libbsd-overlay via pkg-config") ] ) # Add LIBBSD_{CFLAGS,LIBS} to the environment here, as libbsd puts its # header files in a non-standard location, which means the overlay for # and won't be found. CFLAGS="$CFLAGS $LIBBSD_CFLAGS" LIBS="$LIBS $LIBBSD_LIBS" PKG_CHECK_MODULES( LIBMD, libmd, [ libmd_CFLAGS="$LIBMD_CFLAGS" libmd_LIBS="$LIBMD_LIBS" AC_SUBST(libmd_CFLAGS) AC_SUBST(libmd_LIBS) ], [] ) CFLAGS="$CFLAGS $LIBMD_CFLAGS" LIBS="$LIBS $LIBMD_LIBS" fi # Look for a suitable queue.h. We hope libbsd is enough, but that is missing # some declarations. AC_CHECK_DECL( TAILQ_CONCAT, found_queue_h=yes, found_queue_h=no, [#include ] ) AC_CHECK_DECL( TAILQ_PREV, , found_queue_h=no, [#include ] ) AC_CHECK_DECL( TAILQ_FOREACH_SAFE, , found_queue_h=no, [#include ] ) if test "x$found_queue_h" = xyes; then AC_DEFINE([HAVE_QUEUE_H], [1], [sys/queue.h]) else AC_MSG_ERROR("*** sys/queue.h missing key defines ***) fi # Look for crypto (part of openssl) # Note: libcrypto (via openssl) has a .pc file in pretty-much all distros and # BSDs which we support. PKG_CHECK_MODULES( LIBCRYPTO, [libcrypto], [ libcrypto_CFLAGS="$LIBCRYPTO_CFLAGS" libcrypto_LIBS="$LIBCRYPTO_LIBS" AC_SUBST(libcrypto_CFLAGS) AC_SUBST(libcrypto_LIBS) ], AC_MSG_ERROR(["*** Couldn't find libcrypto ***"]) ) if test "x$PLATFORM" != "xopenbsd"; then PKG_CHECK_MODULES( LIBTLS, [libtls], [ libtls_CFLAGS="$LIBTLS_CFLAGS" libtls_LIBS="$LIBTLS_LIBS" AC_SUBST(libtls_CFLAGS) AC_SUBST(libtls_LIBS) ], AC_MSG_ERROR(["*** Couldn't find libtls ***"]) ) fi # Look for __progname. AC_MSG_CHECKING(for __progname) AC_LINK_IFELSE([AC_LANG_SOURCE( [ #include #include extern char *__progname; int main(void) { const char *cp = __progname; printf("%s\n", cp); exit(0); } ])], [AC_DEFINE([HAVE___PROGNAME], [1], [___progname]) AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)] ) PKG_CHECK_MODULES( LIBPANELW, panelw, LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes, found_panel=no ) if test "x$found_panel" = "xno"; then PKG_CHECK_MODULES( LIBPANELW, gnupanelw, [ LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes ], found_panel=no ) fi if test "x$found_panel" = "xno"; then PKG_CHECK_MODULES( LIBPANELW, panel, [ LIBPANELW_LIBS="$LIBPANELW_LIBS" found_panel=yes ], found_panel=no ) fi if test "x$found_panel" = "xno"; then AC_CHECK_LIB(panelw, update_panels, [], AC_MSG_ERROR([ "*** panelw not found for ncurses. ***"]), [-lncurses] ) fi PKG_CHECK_MODULES( LIBNCURSES, ncursesw, found_ncurses=yes, found_ncurses=no ) if test "x$found_ncurses" = xyes; then libncurses_CFLAGS="$LIBNCURSES_CFLAGS $LIBTINFO_CFLAGS $LIBPANELW_CFLAGS" libncurses_LIBS="$LIBNCURSES_LIBS $LIBTINFO_LIBS $LIBPANELW_LIBS" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) else AC_SEARCH_LIBS( setupterm, found_ncurses=yes, found_ncurses=no ) if test "x$found_ncurses" = xyes; then AC_CHECK_HEADER( ncurses.h, libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) ) fi fi if test "x$found_ncurses" = xyes; then AC_DEFINE([HAVE_NCURSES_H], [1], [NCurses]) else # No ncurses, try curses. AC_CHECK_FUNC( setupterm, found_curses=yes, found_curses=no ) AC_CHECK_HEADER( curses.h, found_curses=yes, found_curses=no) if test "x$found_curses" = xyes; then libncurses_CFLAGS="$LIBPANELW_CFLAGS $LIBPANEL_CFLAGS" libncurses_LIBS="$LIBPANELW_LIBS -lncursesw -lpanelw" AC_SUBST(libncurses_CFLAGS) AC_SUBST(libncurses_LIBS) AC_DEFINE([HAVE_CURSES_H], [1], [Curses_h]) else AC_MSG_ERROR("curses not found") fi fi # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # variables. AC_SUBST(AM_CPPFLAGS) CPPFLAGS="$SAVED_CPPFLAGS" AC_SUBST(AM_CFLAGS) CFLAGS="$SAVED_CFLAGS" AC_SUBST(AM_LDFLAGS) LDFLAGS="$SAVED_LDFLAGS" # LIBS is designed to accumulate library dependencies as checks for them are # peformed, so that this can be included directly to ld(1). # # However, this hinders the splitting up of the library dependencies so that # they're targetted just where they're needed. Flatting LIBS here ensures # that this happens appropriately. LIBS="" AH_BOTTOM([#include "got_compat2.h"]) AM_CONDITIONAL([CVG_ENABLED], [test "x$enable_cvg" = xyes]) AC_CONFIG_FILES([Makefile compat/Makefile gitwrapper/Makefile got/Makefile gotadmin/Makefile gotctl/Makefile gotd/Makefile gotd/libexec/Makefile gotd/libexec/got-notify-email/Makefile gotd/libexec/got-notify-http/Makefile gotsh/Makefile gotwebd/Makefile libexec/Makefile libexec/got-fetch-http/Makefile libexec/got-fetch-pack/Makefile libexec/got-index-pack/Makefile libexec/got-read-blob/Makefile libexec/got-read-commit/Makefile libexec/got-read-gitconfig/Makefile libexec/got-read-gotconfig/Makefile libexec/got-read-object/Makefile libexec/got-read-pack/Makefile libexec/got-read-patch/Makefile libexec/got-read-tag/Makefile libexec/got-read-tree/Makefile libexec/got-send-pack/Makefile tog/Makefile Makefile.common:Makefile.common.in]) if test "x$enable_cvg" = "xyes"; then AC_CONFIG_FILES([cvg/Makefile]) fi AC_OUTPUT executables="$(eval echo ${exec_prefix}/bin)" helpers="$(eval echo ${libexecdir})" manpages="$(eval echo ${mandir})" gotdep="$GOTD_EMPTY_PATHC" gotgwlep="$GITWRAPPER_LIBEXEC_PATHC" if test -z "$enable_cvg"; then enable_cvg="no" fi if test -z "$gotdep"; then gotdep="N/A" fi if test -z "$gotgwlep"; then gotgwlep="N/A" fi echo " Configured got-portable with: Version: $VERSION Prefix: ${prefix} Executables: ${executables} Bison: $YACC CFlags: $CFLAGS cvg: ${enable_cvg} Gotd: Empty Path: ${gotdep} Gitwrapper: ${gotgwlep} Helpers: ${helpers} Man pages: ${manpages} " got-portable-0.119/aclocal.m40000664000175000017500000017370115066537201011464 # generated automatically by aclocal 1.17 -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],, [m4_warning([this file was generated for autoconf 2.72. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and use pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurrence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.17' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.17], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.17])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_BEFORE([$0], [AC_PROG_AR])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} : ${ARFLAGS=cr} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR $ARFLAGS libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thus: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([_AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl AC_REQUIRE([_AM_PROG_RM_F]) AC_REQUIRE([_AM_PROG_XARGS_N]) dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2022-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_RM_F # --------------- # Check whether 'rm -f' without any arguments works. # https://bugs.gnu.org/10828 AC_DEFUN([_AM_PROG_RM_F], [am__rm_f_notfound= AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""']) AC_SUBST(am__rm_f_notfound) ]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SLEEP_FRACTIONAL_SECONDS # ---------------------------- AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl AC_CACHE_CHECK([whether sleep supports fractional seconds], am_cv_sleep_fractional_seconds, [dnl AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes], [am_cv_sleep_fractional_seconds=no]) ])]) # _AM_FILESYSTEM_TIMESTAMP_RESOLUTION # ----------------------------------- # Determine the filesystem's resolution for file modification # timestamps. The coarsest we know of is FAT, with a resolution # of only two seconds, even with the most recent "exFAT" extensions. # The finest (e.g. ext4 with large inodes, XFS, ZFS) is one # nanosecond, matching clock_gettime. However, it is probably not # possible to delay execution of a shell script for less than one # millisecond, due to process creation overhead and scheduling # granularity, so we don't check for anything finer than that. (See below.) AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS]) AC_CACHE_CHECK([filesystem timestamp resolution], am_cv_filesystem_timestamp_resolution, [dnl # Default to the worst case. am_cv_filesystem_timestamp_resolution=2 # Only try to go finer than 1 sec if sleep can do it. # Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work, # - 1 sec is not much of a win compared to 2 sec, and # - it takes 2 seconds to perform the test whether 1 sec works. # # Instead, just use the default 2s on platforms that have 1s resolution, # accept the extra 1s delay when using $sleep in the Automake tests, in # exchange for not incurring the 2s delay for running the test for all # packages. # am_try_resolutions= if test "$am_cv_sleep_fractional_seconds" = yes; then # Even a millisecond often causes a bunch of false positives, # so just try a hundredth of a second. The time saved between .001 and # .01 is not terribly consequential. am_try_resolutions="0.01 0.1 $am_try_resolutions" fi # In order to catch current-generation FAT out, we must *modify* files # that already exist; the *creation* timestamp is finer. Use names # that make ls -t sort them differently when they have equal # timestamps than when they have distinct timestamps, keeping # in mind that ls -t prints the *newest* file first. rm -f conftest.ts? : > conftest.ts1 : > conftest.ts2 : > conftest.ts3 # Make sure ls -t actually works. Do 'set' in a subshell so we don't # clobber the current shell's arguments. (Outer-level square brackets # are removed by m4; they're present so that m4 does not expand # ; be careful, easy to get confused.) if ( set X `[ls -t conftest.ts[12]]` && { test "$[]*" != "X conftest.ts1 conftest.ts2" || test "$[]*" != "X conftest.ts2 conftest.ts1"; } ); then :; else # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". _AS_ECHO_UNQUOTED( ["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""], [AS_MESSAGE_LOG_FD]) AC_MSG_FAILURE([ls -t produces unexpected output. Make sure there is not a broken ls alias in your environment.]) fi for am_try_res in $am_try_resolutions; do # Any one fine-grained sleep might happen to cross the boundary # between two values of a coarser actual resolution, but if we do # two fine-grained sleeps in a row, at least one of them will fall # entirely within a coarse interval. echo alpha > conftest.ts1 sleep $am_try_res echo beta > conftest.ts2 sleep $am_try_res echo gamma > conftest.ts3 # We assume that 'ls -t' will make use of high-resolution # timestamps if the operating system supports them at all. if (set X `ls -t conftest.ts?` && test "$[]2" = conftest.ts3 && test "$[]3" = conftest.ts2 && test "$[]4" = conftest.ts1); then # # Ok, ls -t worked. If we're at a resolution of 1 second, we're done, # because we don't need to test make. make_ok=true if test $am_try_res != 1; then # But if we've succeeded so far with a subsecond resolution, we # have one more thing to check: make. It can happen that # everything else supports the subsecond mtimes, but make doesn't; # notably on macOS, which ships make 3.81 from 2006 (the last one # released under GPLv2). https://bugs.gnu.org/68808 # # We test $MAKE if it is defined in the environment, else "make". # It might get overridden later, but our hope is that in practice # it does not matter: it is the system "make" which is (by far) # the most likely to be broken, whereas if the user overrides it, # probably they did so with a better, or at least not worse, make. # https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html # # Create a Makefile (real tab character here): rm -f conftest.mk echo 'conftest.ts1: conftest.ts2' >conftest.mk echo ' touch conftest.ts2' >>conftest.mk # # Now, running # touch conftest.ts1; touch conftest.ts2; make # should touch ts1 because ts2 is newer. This could happen by luck, # but most often, it will fail if make's support is insufficient. So # test for several consecutive successes. # # (We reuse conftest.ts[12] because we still want to modify existing # files, not create new ones, per above.) n=0 make=${MAKE-make} until test $n -eq 3; do echo one > conftest.ts1 sleep $am_try_res echo two > conftest.ts2 # ts2 should now be newer than ts1 if $make -f conftest.mk | grep 'up to date' >/dev/null; then make_ok=false break # out of $n loop fi n=`expr $n + 1` done fi # if $make_ok; then # Everything we know to check worked out, so call this resolution good. am_cv_filesystem_timestamp_resolution=$am_try_res break # out of $am_try_res loop fi # Otherwise, we'll go on to check the next resolution. fi done rm -f conftest.ts? # (end _am_filesystem_timestamp_resolution) ])]) # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION]) # This check should not be cached, as it may vary across builds of # different projects. AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). am_build_env_is_sane=no am_has_slept=no rm -f conftest.file for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[]*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi test "$[]2" = conftest.file ); then am_build_env_is_sane=yes break fi # Just in case. sleep "$am_cv_filesystem_timestamp_resolution" am_has_slept=yes done AC_MSG_RESULT([$am_build_env_is_sane]) if test "$am_build_env_is_sane" = no; then AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl ( sleep "$am_cv_filesystem_timestamp_resolution" ) & am_sleep_pid=$! ]) AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SILENT_RULES # ---------------- # Enable less verbose build rules support. AC_DEFUN([_AM_SILENT_RULES], [AM_DEFAULT_VERBOSITY=1 AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls dnl to AM_SILENT_RULES to change the default value. AC_CONFIG_COMMANDS_PRE([dnl case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; esac if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi ])dnl ]) # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or # empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_REQUIRE([_AM_SILENT_RULES]) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])]) # Copyright (C) 2001-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test x$am_uid = xunknown; then AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work]) elif test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test x$gm_gid = xunknown; then AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work]) elif test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR # Copyright (C) 2022-2024 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_XARGS_N # ---------------- # Check whether 'xargs -n' works. It should work everywhere, so the fallback # is not optimized at all as we never expect to use it. AC_DEFUN([_AM_PROG_XARGS_N], [AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2 3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])]) AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }' ])dnl AC_SUBST(am__xargs_n) ]) got-portable-0.119/Makefile.am0000664000175000017500000002327715066536113011663 # When creating a distribution tarball, make sure we enable all current # configure flags so that no files are missing. This is irrespective of # whether the end-user will enable this; this step is here so that all the # relevant files are included in the distribution. AM_DISTCHECK_CONFIGURE_FLAGS= --enable-cvg SUBDIRS = compat \ gitwrapper \ got \ gotadmin \ gotctl \ gotd \ gotsh \ gotwebd \ libexec \ template \ tog # -portable: re-enable once upstream is happy: cvg # TODO: gotd gotsh template if CVG_ENABLED SUBDIRS += cvg endif include $(top_builddir)/Makefile.common EXTRA_DIST = CHANGES \ CHANGELOG \ LICENCE \ README.portable \ regress \ util/got-portable-ver.sh LDADD = $(LIBOBJS) if HOST_FREEBSD LDADD += -lmd LIBS += -lmd endif LIBS += -lm $(zlib_LIBS) $(libbsd_LIBS) $(libmd_LIBS) AM_CPPFLAGS += $(libbsd_CFLAGS) $(libmd_CFLAGS) TEST_TARGETS=compat regress-delta regress-deltify regress-fetch regress-idset \ regress-path regress-tog regress-cmdline GOT_TEST_ROOT=/tmp .PHONY: compat compat: $(MAKE) -C compat tests: $(TEST_TARGETS) regress-cmdline: (export PLATFORM=@PLATFORM@; \ cd $(top_builddir)/regress/cmdline || exit $$?; \ ./checkout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./update.sh -q -r "$(GOT_TEST_ROOT)"; \ ./status.sh -q -r "$(GOT_TEST_ROOT)"; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"; \ ./add.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rm.sh -q -r "$(GOT_TEST_ROOT)"; \ ./diff.sh -q -r "$(GOT_TEST_ROOT)"; \ ./blame.sh -q -r "$(GOT_TEST_ROOT)"; \ ./branch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tag.sh -q -r "$(GOT_TEST_ROOT)"; \ ./ref.sh -q -r "$(GOT_TEST_ROOT)"; \ ./commit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./revert.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cherrypick.sh -q -r "$(GOT_TEST_ROOT)"; \ ./backout.sh -q -r "$(GOT_TEST_ROOT)"; \ ./rebase.sh -q -r "$(GOT_TEST_ROOT)"; \ ./import.sh -q -r "$(GOT_TEST_ROOT)"; \ ./histedit.sh -q -r "$(GOT_TEST_ROOT)"; \ ./integrate.sh -q -r "$(GOT_TEST_ROOT)"; \ ./merge.sh -q -r "$(GOT_TEST_ROOT)"; \ ./stage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./unstage.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cat.sh -q -r "$(GOT_TEST_ROOT)"; \ ./clone.sh -q -r "$(GOT_TEST_ROOT)"; \ ./fetch.sh -q -r "$(GOT_TEST_ROOT)"; \ ./send.sh -q -r "$(GOT_TEST_ROOT)"; \ ./tree.sh -q -r "$(GOT_TEST_ROOT)"; \ ./patch.sh -q -r "$(GOT_TEST_ROOT)" \ ./pack.sh -q -r "$(GOT_TEST_ROOT)"; \ ./cleanup.sh -q -r "$(GOT_TEST_ROOT)") regress-delta: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/delta/delta_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/delta/delta_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/delta/delta_test regress-deltify: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/deltify/deltify_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/deltify/deltify_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/deltify/deltify_test regress-fetch: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/fetch/fetch_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/fetch/fetch_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) -lm && \ $(top_builddir)/regress/fetch/fetch_test regress-idset: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/idset/idset_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/idset/idset_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/idset/idset_test regress-path: $(CC) $(DEFS) $(AM_CFLAGS) $(AM_CPPFLAGS) \ -o $(top_builddir)/regress/path/path_test \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/deltify.c \ $(top_srcdir)/lib/dial.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/pack_create.c \ $(top_srcdir)/lib/pack_create_privsep.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/ratelimit.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/regress/path/path_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/path/path_test regress-tog: (cd $(top_builddir)/regress/tog || exit $$?; \ ./log.sh -q -r "$(GOT_TEST_ROOT)"); got-portable-0.119/gotwebd/0000775000175000017500000000000015066537275011341 5got-portable-0.119/gotwebd/gotweb.c0000664000175000017500000011066515066536113012713 /* * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_worktree.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" static int gotweb_render_index(struct template *); static const struct got_error *gotweb_load_got_path(struct repo_dir **, const char *, struct request *); static const struct got_error *gotweb_load_file(char **, const char *, const char *, int); static const struct got_error *gotweb_get_repo_description(char **, struct server *, const char *, int); static const struct got_error *gotweb_get_clone_url(char **, struct server *, const char *, int); static void gotweb_free_repo_dir(struct repo_dir *); int gotweb_reply(struct request *c, int status, const char *ctype, struct gotweb_url *location) { const char *csp; if (status != 200 && tp_writef(c->tp, "Status: %d\r\n", status) == -1) return -1; if (location) { if (tp_writes(c->tp, "Location: ") == -1 || gotweb_render_absolute_url(c, location) == -1 || tp_writes(c->tp, "\r\n") == -1) return -1; } csp = "Content-Security-Policy: default-src 'self'; " "script-src 'none'; object-src 'none';\r\n"; if (tp_writes(c->tp, csp) == -1) return -1; if (ctype && tp_writef(c->tp, "Content-Type: %s\r\n", ctype) == -1) return -1; return tp_writes(c->tp, "\r\n"); } static int gotweb_reply_file(struct request *c, const char *ctype, const char *file, const char *suffix) { int r; r = tp_writef(c->tp, "Content-Disposition: attachment; " "filename=%s%s\r\n", file, suffix ? suffix : ""); if (r == -1) return -1; return gotweb_reply(c, 200, ctype, NULL); } static struct socket * gotweb_get_socket(int sock_id) { struct socket *sock; TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) { if (sock->conf.id == sock_id) return sock; } return NULL; } static void cleanup_request(struct request *c) { uint32_t request_id = c->request_id; fcgi_cleanup_request(c); if (imsg_compose_event(gotwebd_env->iev_auth, GOTWEBD_IMSG_REQ_ABORT, GOTWEBD_PROC_GOTWEB, -1, -1, &request_id, sizeof(request_id)) == -1) log_warn("imsg_compose_event"); } static struct request * recv_request(struct imsg *imsg) { const struct got_error *error; struct request *c; struct server *srv; size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE; int fd = -1; uint8_t *outbuf = NULL; if (datalen != sizeof(*c)) { log_warnx("bad request size received over imsg"); return NULL; } fd = imsg_get_fd(imsg); if (fd == -1) { log_warnx("no client file descriptor"); return NULL; } c = calloc(1, sizeof(*c)); if (c == NULL) { log_warn("calloc"); return NULL; } outbuf = calloc(1, GOTWEBD_CACHESIZE); if (outbuf == NULL) { log_warn("calloc"); free(c); return NULL; } memcpy(c, imsg->data, sizeof(*c)); /* Non-NULL pointers, if any, are not from our address space. */ c->sock = NULL; c->srv = NULL; c->t = NULL; c->tp = NULL; c->buf = NULL; c->outbuf = outbuf; memset(&c->ev, 0, sizeof(c->ev)); memset(&c->tmo, 0, sizeof(c->tmo)); /* Use our own temporary file descriptors. */ memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd)); c->fd = fd; c->tp = template(c, fcgi_write, c->outbuf, GOTWEBD_CACHESIZE); if (c->tp == NULL) { log_warn("gotweb init template"); cleanup_request(c); return NULL; } c->sock = gotweb_get_socket(c->sock_id); if (c->sock == NULL) { log_warn("socket id '%d' not found", c->sock_id); cleanup_request(c); return NULL; } /* init the transport */ error = gotweb_init_transport(&c->t); if (error) { log_warnx("gotweb init transport: %s", error->msg); cleanup_request(c); return NULL; } /* get the gotwebd server */ srv = gotweb_get_server(c->fcgi_params.server_name); if (srv == NULL) { log_warnx("server '%s' not found", c->fcgi_params.server_name); cleanup_request(c); return NULL; } c->srv = srv; return c; } int gotweb_process_request(struct request *c) { const struct got_error *error = NULL; struct server *srv = c->srv;; struct querystring *qs = NULL; struct repo_dir *repo_dir = NULL; struct repo_commit *commit; const char *rss_ctype = "application/rss+xml;charset=utf-8"; const uint8_t *buf; size_t len; int r, binary = 0; /* querystring */ qs = &c->fcgi_params.qs; c->t->qs = qs; /* Log the request. */ if (gotwebd_env->gotwebd_verbose > 0) { struct gotwebd_fcgi_params *p = &c->fcgi_params; char *server_name = NULL; char *document_uri = NULL; const char *action_name = NULL; if (p->server_name[0] && stravis(&server_name, p->server_name, VIS_SAFE) == -1) { log_warn("stravis"); server_name = NULL; } if (p->document_uri[0] && stravis(&document_uri, p->document_uri, VIS_SAFE) == -1) { log_warn("stravis"); document_uri = NULL; } action_name = gotweb_action_name(qs->action); log_info("processing request: server='%s' action='%s' " "commit='%s', file='%s', folder='%s', headref='%s' " "index_page=%d path='%s' document_uri='%s'", server_name ? server_name : "", action_name ? action_name : "", qs->commit, qs->file, qs->folder, qs->headref, qs->index_page, qs->path, document_uri ? document_uri : ""); free(server_name); free(document_uri); } /* * certain actions require a commit id in the querystring. this stops * bad actors from exploiting this by manually manipulating the * querystring. */ if (qs->action == BLAME || qs->action == BLOB || qs->action == BLOBRAW || qs->action == DIFF || qs->action == PATCH) { if (qs->commit[0] == '\0') { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } } if (qs->action != INDEX) { if (qs->path[0] == '\0') { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } error = gotweb_load_got_path(&repo_dir, qs->path, c); c->t->repo_dir = repo_dir; if (error) goto err; } if (qs->action == BLOBRAW || qs->action == BLOB) { if (qs->folder[0] == '\0' || qs->file[0] == '\0') { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } error = got_get_repo_commits(c, 1); if (error) goto err; error = got_open_blob_for_output(&c->t->blob, &c->t->fd, &binary, c, qs->folder, qs->file, qs->commit); if (error) goto err; } switch (qs->action) { case BLAME: if (qs->folder[0] == '\0' || qs->file[0] == '\0') { error = got_error(GOT_ERR_BAD_QUERYSTRING); goto err; } error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_blame); case BLOB: if (binary) { struct gotweb_url url = { .index_page = -1, .action = BLOBRAW, .path = qs->path[0] ? qs->path : NULL, .commit = qs->commit[0] ? qs->commit : NULL, .folder = qs->folder[0] ? qs->folder : NULL, .file = qs->file[0] ? qs->file : NULL, }; return gotweb_reply(c, 302, NULL, &url); } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_blob); case BLOBRAW: if (binary) r = gotweb_reply_file(c, "application/octet-stream", qs->file, NULL); else r = gotweb_reply(c, 200, "text/plain", NULL); if (r == -1) return -1; if (template_flush(c->tp) == -1) return -1; for (;;) { error = got_object_blob_read_block(&len, c->t->blob); if (error) break; if (len == 0) break; buf = got_object_blob_get_read_buf(c->t->blob); if (fcgi_write(c, buf, len) == -1) return -1; } return 0; case BRIEFS: error = got_get_repo_commits(c, srv->max_commits_display); if (error) goto err; if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_briefs); case COMMITS: error = got_get_repo_commits(c, srv->max_commits_display); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_commits); case DIFF: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } error = got_open_diff_for_output(&c->t->fp, c); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_diff); case INDEX: c->t->nrepos = scandir(srv->repos_path, &c->t->repos, NULL, alphasort); if (c->t->nrepos == -1) { c->t->repos = NULL; error = got_error_from_errno2("scandir", srv->repos_path); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_index); case PATCH: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } error = got_open_diff_for_output(&c->t->fp, c); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/plain", NULL) == -1) return -1; return gotweb_render_patch(c->tp); case RSS: error = got_get_repo_tags(c, D_MAXSLCOMMDISP); if (error) goto err; if (gotweb_reply_file(c, rss_ctype, repo_dir->name, ".rss") == -1) return -1; return gotweb_render_rss(c->tp); case SUMMARY: error = got_ref_list(&c->t->refs, c->t->repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) { log_warnx("%s: got_ref_list: %s", __func__, error->msg); goto err; } error = got_get_repo_commits(c, srv->summary_commits_display); if (error) goto err; qs->action = TAGS; error = got_get_repo_tags(c, srv->summary_tags_display); if (error) { log_warnx("%s: got_get_repo_tags: %s", __func__, error->msg); goto err; } qs->action = SUMMARY; commit = TAILQ_FIRST(&c->t->repo_commits); if (commit && qs->commit[0] == '\0') { if (strlcpy(qs->commit, commit->commit_id, sizeof(qs->commit)) >= sizeof(qs->commit)) { error = got_error_msg(GOT_ERR_NO_SPACE, "commit ID too long"); log_warn("%s: %s", __func__, error->msg); goto err; } } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_summary); case TAG: error = got_get_repo_tags(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (TAILQ_EMPTY(&c->t->repo_tags)) { error = got_error_msg(GOT_ERR_BAD_OBJ_ID, "bad commit id"); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_tag); case TAGS: error = got_get_repo_tags(c, srv->max_commits_display); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_tags); case TREE: error = got_get_repo_commits(c, 1); if (error) { log_warnx("%s: %s", __func__, error->msg); goto err; } if (gotweb_reply(c, 200, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_tree); case ERR: default: error = got_error(GOT_ERR_BAD_QUERYSTRING); } err: c->t->error = error; if (gotweb_reply(c, 400, "text/html", NULL) == -1) return -1; return gotweb_render_page(c->tp, gotweb_render_error); } struct server * gotweb_get_server(const char *server_name) { struct server *srv; /* check against the server name first */ if (*server_name != '\0') TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) if (strcmp(srv->name, server_name) == 0) return srv; /* otherwise, use the first server */ return TAILQ_FIRST(&gotwebd_env->servers); }; const struct got_error * gotweb_init_transport(struct transport **t) { const struct got_error *error = NULL; *t = calloc(1, sizeof(**t)); if (*t == NULL) return got_error_from_errno2(__func__, "calloc"); TAILQ_INIT(&(*t)->repo_commits); TAILQ_INIT(&(*t)->repo_tags); TAILQ_INIT(&(*t)->refs); (*t)->fd = -1; return error; } struct gotwebd_repo * gotweb_get_repository(struct server *server, const char *name) { struct gotwebd_repo *repo; TAILQ_FOREACH(repo, &server->repos, entry) { if (strncmp(repo->name, name, strlen(repo->name)) != 0) continue; if (strlen(name) == strlen(repo->name)) return repo; if (strlen(name) != strlen(repo->name) + 4) continue; if (strcmp(name + strlen(repo->name), ".git") == 0) return repo; } return NULL; } void gotweb_free_repo_tag(struct repo_tag *rt) { if (rt != NULL) { free(rt->commit_id); free(rt->tag_name); free(rt->tag_commit); free(rt->commit_msg); free(rt->tagger); } free(rt); } void gotweb_free_repo_commit(struct repo_commit *rc) { if (rc != NULL) { free(rc->path); free(rc->refs_str); free(rc->commit_id); free(rc->parent_id); free(rc->tree_id); free(rc->author); free(rc->committer); free(rc->commit_msg); } free(rc); } static void gotweb_free_repo_dir(struct repo_dir *repo_dir) { if (repo_dir != NULL) { free(repo_dir->name); free(repo_dir->owner); free(repo_dir->description); free(repo_dir->url); free(repo_dir->path); } free(repo_dir); } void gotweb_free_transport(struct transport *t) { const struct got_error *err; struct repo_commit *rc = NULL, *trc = NULL; struct repo_tag *rt = NULL, *trt = NULL; int i; got_ref_list_free(&t->refs); TAILQ_FOREACH_SAFE(rc, &t->repo_commits, entry, trc) { TAILQ_REMOVE(&t->repo_commits, rc, entry); gotweb_free_repo_commit(rc); } TAILQ_FOREACH_SAFE(rt, &t->repo_tags, entry, trt) { TAILQ_REMOVE(&t->repo_tags, rt, entry); gotweb_free_repo_tag(rt); } gotweb_free_repo_dir(t->repo_dir); t->qs = NULL; free(t->more_id); free(t->tags_more_id); if (t->blob) got_object_blob_close(t->blob); if (t->fp) { err = got_gotweb_closefile(t->fp); if (err) log_warnx("%s: got_gotweb_closefile failure: %s", __func__, err->msg); } if (t->fd != -1 && close(t->fd) == -1) log_warn("%s: close", __func__); if (t->repos) { for (i = 0; i < t->nrepos; ++i) free(t->repos[i]); free(t->repos); } if (t->repo) got_repo_close(t->repo); free(t); } void gotweb_index_navs(struct request *c, struct gotweb_url *prev, int *have_prev, struct gotweb_url *next, int *have_next) { struct transport *t = c->t; const struct querystring *qs = t->qs; struct server *srv = c->srv; *have_prev = *have_next = 0; if (qs->index_page > 0) { *have_prev = 1; *prev = (struct gotweb_url){ .action = -1, .index_page = qs->index_page - 1, }; } if (t->next_disp == srv->max_repos_display && t->repos_total != (qs->index_page + 1) * srv->max_repos_display) { *have_next = 1; *next = (struct gotweb_url){ .action = -1, .index_page = qs->index_page + 1, }; } } static int gotweb_render_index(struct template *tp) { const struct got_error *error = NULL; struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; const struct querystring *qs = t->qs; struct repo_dir *repo_dir = NULL; struct dirent **sd_dent = t->repos; unsigned int d_i, d_disp = 0; unsigned int d_skipped = 0; int type, r; if (gotweb_render_repo_table_hdr(c->tp) == -1) return -1; for (d_i = 0; d_i < t->nrepos; d_i++) { if (strcmp(sd_dent[d_i]->d_name, ".") == 0 || strcmp(sd_dent[d_i]->d_name, "..") == 0) { d_skipped++; continue; } error = got_path_dirent_type(&type, srv->repos_path, sd_dent[d_i]); if (error) continue; if (type != DT_DIR) { d_skipped++; continue; } if (qs->index_page > 0 && (qs->index_page * srv->max_repos_display) > t->prev_disp) { t->prev_disp++; continue; } error = gotweb_load_got_path(&repo_dir, sd_dent[d_i]->d_name, c); if (error) { if (error->code != GOT_ERR_NOT_GIT_REPO) log_warnx("%s: %s: %s", __func__, sd_dent[d_i]->d_name, error->msg); gotweb_free_repo_dir(repo_dir); repo_dir = NULL; d_skipped++; continue; } d_disp++; t->prev_disp++; r = gotweb_render_repo_fragment(c->tp, repo_dir); gotweb_free_repo_dir(repo_dir); repo_dir = NULL; got_repo_close(t->repo); t->repo = NULL; if (r == -1) return -1; t->next_disp++; if (d_disp == srv->max_repos_display) break; } t->repos_total = t->nrepos - d_skipped; if (srv->max_repos_display == 0 || t->repos_total <= srv->max_repos_display) return 0; if (gotweb_render_navs(c->tp) == -1) return -1; return 0; } static inline int should_urlencode(int c) { if (c <= ' ' || c >= 127) return 1; switch (c) { /* gen-delim */ case ':': case '/': case '?': case '#': case '[': case ']': case '@': /* sub-delims */ case '!': case '$': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case ';': case '=': /* needed because the URLs are embedded into the HTML */ case '\"': return 1; default: return 0; } } static char * gotweb_urlencode(const char *str) { const char *s; char *escaped; size_t i, len; int a, b; len = 0; for (s = str; *s; ++s) { len++; if (should_urlencode(*s)) len += 2; } escaped = calloc(1, len + 1); if (escaped == NULL) return NULL; i = 0; for (s = str; *s; ++s) { if (should_urlencode(*s)) { a = (*s & 0xF0) >> 4; b = (*s & 0x0F); escaped[i++] = '%'; escaped[i++] = a <= 9 ? ('0' + a) : ('7' + a); escaped[i++] = b <= 9 ? ('0' + b) : ('7' + b); } else escaped[i++] = *s; } return escaped; } const char * gotweb_action_name(int action) { switch (action) { case NO_ACTION: return "no action"; case BLAME: return "blame"; case BLOB: return "blob"; case BLOBRAW: return "blobraw"; case BRIEFS: return "briefs"; case COMMITS: return "commits"; case DIFF: return "diff"; case ERR: return "err"; case INDEX: return "index"; case PATCH: return "patch"; case SUMMARY: return "summary"; case TAG: return "tag"; case TAGS: return "tags"; case TREE: return "tree"; case RSS: return "rss"; default: return NULL; } } int gotweb_render_url(struct request *c, struct gotweb_url *url) { const char *sep = "?", *action; char *tmp; int r; action = gotweb_action_name(url->action); if (action != NULL) { if (tp_writef(c->tp, "?action=%s", action) == -1) return -1; sep = "&"; } if (url->commit) { if (tp_writef(c->tp, "%scommit=%s", sep, url->commit) == -1) return -1; sep = "&"; } if (url->file) { tmp = gotweb_urlencode(url->file); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%sfile=%s", sep, tmp); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->folder) { if (got_path_is_root_dir(url->folder)) tmp = NULL; else { tmp = gotweb_urlencode(url->folder); if (tmp == NULL) return -1; } r = tp_writef(c->tp, "%sfolder=%s", sep, tmp ? tmp : ""); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->headref) { tmp = gotweb_urlencode(url->headref); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%sheadref=%s", sep, url->headref); free(tmp); if (r == -1) return -1; sep = "&"; } if (url->index_page != -1) { if (tp_writef(c->tp, "%sindex_page=%d", sep, url->index_page) == -1) return -1; sep = "&"; } if (url->path) { tmp = gotweb_urlencode(url->path); if (tmp == NULL) return -1; r = tp_writef(c->tp, "%spath=%s", sep, tmp); free(tmp); if (r == -1) return -1; sep = "&"; } return 0; } int gotweb_render_absolute_url(struct request *c, struct gotweb_url *url) { struct template *tp = c->tp; struct gotwebd_fcgi_params *p = &c->fcgi_params; const char *proto = p->https ? "https" : "http"; if (tp_writes(tp, proto) == -1 || tp_writes(tp, "://") == -1 || tp_htmlescape(tp, p->server_name) == -1 || tp_htmlescape(tp, p->document_uri) == -1) return -1; return gotweb_render_url(c, url); } /* * Ensure that a path sent in the request will not escape from the given * parent directory. This matters for got-portable where we are not * necessarily running in chroot and cannot be protected by unveil(2). */ static const struct got_error * validate_path(const char *path, const char *parent_path, const char *orig_path) { const struct got_error *error = NULL; char *abspath; abspath = realpath(path, NULL); if (abspath == NULL) { /* Paths which cannot be resolved are safe. */ if (errno == ENOENT || errno == EACCES || errno == ENOTDIR) return NULL; return got_error_from_errno("realpath"); } if (!got_path_is_child(abspath, parent_path, strlen(parent_path))) error = got_error_path(orig_path, GOT_ERR_NOT_GIT_REPO); free(abspath); return error; } static enum gotwebd_access auth_check(struct request *c, struct gotwebd_access_rule_list *rules) { struct gotwebd *env = gotwebd_env; enum gotwebd_access access = GOTWEBD_ACCESS_NO_MATCH; struct gotwebd_access_rule *rule; /* * The www user ID implies that no user authentication occurred. * But authentication is enabled so we must deny this request. */ if (c->client_uid == env->www_uid) return GOTWEBD_ACCESS_DENIED; /* * We cannot access /etc/passwd in this process so we cannot * verify the client's user ID outselves here. * Match rules against the access identifier which has already * passed authentication in the auth process. */ STAILQ_FOREACH(rule, rules, entry) { if (strcmp(rule->identifier, c->access_identifier) == 0) access = rule->access; } return access; } static const struct got_error * gotweb_load_got_path(struct repo_dir **rp, const char *dir, struct request *c) { const struct got_error *error = NULL; struct gotwebd *env = gotwebd_env; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir; DIR *dt; char *dir_test; struct gotwebd_repo *repo; enum gotwebd_auth_config auth_config = 0; enum gotwebd_access access = GOTWEBD_ACCESS_DENIED; *rp = calloc(1, sizeof(**rp)); if (*rp == NULL) return got_error_from_errno("calloc"); repo_dir = *rp; if (asprintf(&dir_test, "%s/%s/%s", srv->repos_path, dir, GOTWEB_GIT_DIR) == -1) return got_error_from_errno("asprintf"); error = validate_path(dir_test, srv->repos_path, dir); if (error) { free(dir_test); return error; } dt = opendir(dir_test); if (dt == NULL) { free(dir_test); if (asprintf(&dir_test, "%s/%s", srv->repos_path, dir) == -1) return got_error_from_errno("asprintf"); dt = opendir(dir_test); if (dt == NULL) { free(dir_test); if (asprintf(&dir_test, "%s/%s%s", srv->repos_path, dir, GOTWEB_GIT_DIR) == -1) return got_error_from_errno("asprintf"); dt = opendir(dir_test); if (dt == NULL) { free(dir_test); return got_error_path(dir, GOT_ERR_NOT_GIT_REPO); } } } repo_dir->path = dir_test; dir_test = NULL; error = got_path_basename(&repo_dir->name, repo_dir->path); if (error) goto err; repo = gotweb_get_repository(srv, repo_dir->name); if (repo) { auth_config = repo->auth_config; switch (auth_config) { case GOTWEBD_AUTH_DISABLED: access = GOTWEBD_ACCESS_PERMITTED; break; case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: access = auth_check(c, &repo->access_rules); if (access == GOTWEBD_ACCESS_NO_MATCH) access = auth_check(c, &srv->access_rules); if (access == GOTWEBD_ACCESS_NO_MATCH) access = auth_check(c, &env->access_rules); if (access == GOTWEBD_ACCESS_NO_MATCH) access = GOTWEBD_ACCESS_DENIED; break; } } else { auth_config = srv->auth_config; switch (auth_config) { case GOTWEBD_AUTH_DISABLED: access = GOTWEBD_ACCESS_PERMITTED; break; case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: access = auth_check(c, &srv->access_rules); if (access == GOTWEBD_ACCESS_NO_MATCH) access = auth_check(c, &env->access_rules); if (access == GOTWEBD_ACCESS_NO_MATCH) access = GOTWEBD_ACCESS_DENIED; break; } } if (access != GOTWEBD_ACCESS_PERMITTED && access != GOTWEBD_ACCESS_DENIED) fatalx("invalid access check result %d", access); if (access != GOTWEBD_ACCESS_PERMITTED) { error = got_error_path(repo_dir->name, GOT_ERR_NOT_GIT_REPO); goto err; } if (srv->respect_exportok && faccessat(dirfd(dt), "git-daemon-export-ok", F_OK, 0) == -1) { error = got_error_path(repo_dir->name, GOT_ERR_NOT_GIT_REPO); goto err; } error = got_repo_open(&t->repo, repo_dir->path, NULL, gotwebd_env->pack_fds); if (error) goto err; error = gotweb_get_repo_description(&repo_dir->description, srv, repo_dir->path, dirfd(dt)); if (error) goto err; if (srv->show_repo_owner) { error = gotweb_load_file(&repo_dir->owner, repo_dir->path, "owner", dirfd(dt)); if (error) goto err; if (repo_dir->owner == NULL) { error = got_get_repo_owner(&repo_dir->owner, c); if (error) goto err; } } if (srv->show_repo_age) { error = got_get_repo_age(&repo_dir->age, c, NULL); if (error) goto err; } error = gotweb_get_clone_url(&repo_dir->url, srv, repo_dir->path, dirfd(dt)); err: free(dir_test); if (dt != NULL && closedir(dt) == EOF && error == NULL) error = got_error_from_errno("closedir"); if (error && t->repo) { got_repo_close(t->repo); t->repo = NULL; } return error; } static const struct got_error * gotweb_load_file(char **str, const char *dir, const char *file, int dirfd) { const struct got_error *error = NULL; struct stat sb; off_t len; int fd; *str = NULL; fd = openat(dirfd, file, O_RDONLY); if (fd == -1) { if (errno == ENOENT || errno == EACCES) return NULL; return got_error_from_errno_fmt("openat %s/%s", dir, file); } if (fstat(fd, &sb) == -1) { error = got_error_from_errno_fmt("fstat %s/%s", dir, file); goto done; } len = sb.st_size; if (len > GOTWEBD_MAXDESCRSZ - 1) len = GOTWEBD_MAXDESCRSZ - 1; *str = calloc(len + 1, 1); if (*str == NULL) { error = got_error_from_errno("calloc"); goto done; } if (read(fd, *str, len) == -1) error = got_error_from_errno("read"); done: if (fd != -1 && close(fd) == -1 && error == NULL) error = got_error_from_errno("close"); return error; } static const struct got_error * gotweb_get_repo_description(char **description, struct server *srv, const char *dirpath, int dir) { *description = NULL; if (srv->show_repo_description == 0) return NULL; return gotweb_load_file(description, dirpath, "description", dir); } static const struct got_error * gotweb_get_clone_url(char **url, struct server *srv, const char *dirpath, int dir) { *url = NULL; if (srv->show_repo_cloneurl == 0) return NULL; return gotweb_load_file(url, dirpath, "cloneurl", dir); } int gotweb_render_age(struct template *tp, time_t committer_time) { struct request *c = tp->tp_arg; long long diff_time; const char *years = "years ago", *months = "months ago"; const char *weeks = "weeks ago", *days = "days ago"; const char *hours = "hours ago", *minutes = "minutes ago"; const char *seconds = "seconds ago", *now = "right now"; diff_time = time(NULL) - committer_time; if (diff_time > 60 * 60 * 24 * 365 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / 365), years) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * (365 / 12) * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / (365 / 12)), months) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * 7 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24 / 7), weeks) == -1) return -1; } else if (diff_time > 60 * 60 * 24 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60 / 24), days) == -1) return -1; } else if (diff_time > 60 * 60 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60 / 60), hours) == -1) return -1; } else if (diff_time > 60 * 2) { if (tp_writef(c->tp, "%lld %s", (diff_time / 60), minutes) == -1) return -1; } else if (diff_time > 2) { if (tp_writef(c->tp, "%lld %s", diff_time, seconds) == -1) return -1; } else { if (tp_writes(tp, now) == -1) return -1; } return 0; } static void gotweb_shutdown(void) { imsgbuf_clear(&gotwebd_env->iev_parent->ibuf); free(gotwebd_env->iev_parent); imsgbuf_clear(&gotwebd_env->iev_auth->ibuf); free(gotwebd_env->iev_auth); config_free_access_rules(&gotwebd_env->access_rules); while (!TAILQ_EMPTY(&gotwebd_env->servers)) { struct server *srv; srv = TAILQ_FIRST(&gotwebd_env->servers); TAILQ_REMOVE(&gotwebd_env->servers, srv, entry); config_free_access_rules(&srv->access_rules); config_free_repos(&srv->repos); free(srv); } while (!TAILQ_EMPTY(&gotwebd_env->sockets)) { struct socket *sock; sock = TAILQ_FIRST(&gotwebd_env->sockets); TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); free(sock); } while (!TAILQ_EMPTY(&gotwebd_env->addresses)) { struct address *h; h = TAILQ_FIRST(&gotwebd_env->addresses); TAILQ_REMOVE(&gotwebd_env->addresses, h, entry); free(h); } free(gotwebd_env); exit(0); } static void gotweb_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: gotweb_shutdown(); break; default: log_warn("unhandled signal %d", sig); } } static void gotweb_launch(struct gotwebd *env) { struct server *srv; const struct got_error *error; if (env->iev_auth == NULL) fatal("auth process not connected"); #ifndef PROFILE if (pledge("stdio rpath recvfd sendfd proc exec unveil", NULL) == -1) fatal("pledge"); #endif TAILQ_FOREACH(srv, &gotwebd_env->servers, entry) { if (unveil(srv->repos_path, "r") == -1) fatal("unveil %s", srv->repos_path); } error = got_privsep_unveil_exec_helpers(); if (error) fatalx("%s", error->msg); if (unveil(NULL, NULL) == -1) fatal("unveil"); event_add(&env->iev_auth->ev, NULL); } static void gotweb_dispatch_server(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct request *c; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_REQ_PROCESS: c = recv_request(&imsg); if (c) { int request_id = c->request_id; if (gotweb_process_request(c) == -1) { log_warnx("request %u failed", request_id); } else { if (template_flush(c->tp) == -1) { log_warn("request %u flush", request_id); } } fcgi_create_end_record(c); cleanup_request(c); } break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_auth_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->iev_auth != NULL) fatalx("auth process already connected"); fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid auth pipe fd"); iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = gotweb_dispatch_server; iev->data = iev; event_set(&iev->ev, fd, EV_READ, gotweb_dispatch_server, iev); imsg_event_add(iev); env->iev_auth = iev; } static void gotweb_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; struct server *srv; struct gotwebd_repo *repo; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_ACCESS_RULE: if (TAILQ_EMPTY(&env->servers)) { /* global access rule */ config_get_access_rule(&env->access_rules, &imsg); } else { srv = TAILQ_LAST(&env->servers, serverlist); if (TAILQ_EMPTY(&srv->repos)) { /* per-server access rule */ config_get_access_rule( &srv->access_rules, &imsg); } else { /* per-repository access rule */ repo = TAILQ_LAST(&srv->repos, gotwebd_repolist); config_get_access_rule( &repo->access_rules, &imsg); } } break; case GOTWEBD_IMSG_CFG_SRV: config_getserver(env, &imsg); break; case GOTWEBD_IMSG_CFG_REPO: if (TAILQ_EMPTY(&env->servers)) fatalx("%s: unexpected CFG_REPO msg", __func__); srv = TAILQ_LAST(&env->servers, serverlist); config_get_repository(&srv->repos, &imsg); break; case GOTWEBD_IMSG_CFG_FD: config_getfd(env, &imsg); break; case GOTWEBD_IMSG_CFG_SOCK: config_getsock(env, &imsg); break; case GOTWEBD_IMSG_CFG_DONE: config_getcfg(env, &imsg); break; case GOTWEBD_IMSG_CTL_PIPE: recv_auth_pipe(env, &imsg); break; case GOTWEBD_IMSG_AUTH_CONF: if (imsg_get_data(&imsg, &env->auth_config, sizeof(env->auth_config)) == -1) fatalx("%s: invalid AUTH_CONF msg", __func__); break; case GOTWEBD_IMSG_WWW_UID: if (imsg_get_data(&imsg, &env->www_uid, sizeof(env->www_uid)) == -1) fatalx("%s: invalid WWW_UID msg", __func__); break; case GOTWEBD_IMSG_CTL_START: gotweb_launch(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotweb(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; struct event_base *evb; evb = event_init(); sockets_rlimit(-1); env->iev_parent = calloc(1, sizeof(*env->iev_parent)); if (env->iev_parent == NULL) fatal("calloc"); if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&env->iev_parent->ibuf); env->iev_parent->handler = gotweb_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, gotweb_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, gotweb_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, gotweb_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, gotweb_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, gotweb_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, gotweb_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio rpath recvfd sendfd proc exec unveil", NULL) == -1) fatal("pledge"); #endif event_dispatch(); event_base_free(evb); gotweb_shutdown(); } got-portable-0.119/gotwebd/sockets.c0000664000175000017500000006764115066536113013104 /* * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" #define SOCKS_BACKLOG 5 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) static volatile int client_cnt; static struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; static void sockets_sighdlr(int, short, void *); static void sockets_shutdown(void); static void sockets_launch(struct gotwebd *); static void sockets_dispatch_main(int, short, void *); static int sockets_unix_socket_listen(struct gotwebd *, struct socket *, uid_t, gid_t); static int sockets_create_socket(struct address *); static int sockets_accept_reserve(int, struct sockaddr *, socklen_t *, int, volatile int *); int cgi_inflight = 0; /* Request hash table needs some spare room to avoid collisions. */ struct requestlist requests[GOTWEBD_MAXCLIENTS * 4]; static SIPHASH_KEY requests_hash_key; static void requests_init(void) { int i; arc4random_buf(&requests_hash_key, sizeof(requests_hash_key)); for (i = 0; i < nitems(requests); i++) TAILQ_INIT(&requests[i]); } static uint64_t request_hash(uint32_t request_id) { return SipHash24(&requests_hash_key, &request_id, sizeof(request_id)); } static void add_request(struct request *c) { uint64_t slot = request_hash(c->request_id) % nitems(requests); TAILQ_INSERT_HEAD(&requests[slot], c, entry); client_cnt++; } static void del_request(struct request *c) { uint64_t slot = request_hash(c->request_id) % nitems(requests); TAILQ_REMOVE(&requests[slot], c, entry); client_cnt--; } static struct request * find_request(uint32_t request_id) { uint64_t slot; struct request *c; slot = request_hash(request_id) % nitems(requests); TAILQ_FOREACH(c, &requests[slot], entry) { if (c->request_id == request_id) return c; } return NULL; } static void cleanup_request(struct request *c) { struct gotwebd *env = gotwebd_env; cgi_inflight--; if (c->worker_idx != -1) { if (env->worker_load[c->worker_idx] <= 0) fatalx("request in flight on worker with zero load"); env->worker_load[c->worker_idx]--; } del_request(c); event_add(&c->sock->ev, NULL); if (evtimer_initialized(&c->tmo)) evtimer_del(&c->tmo); if (event_initialized(&c->ev)) event_del(&c->ev); if (c->fd != -1) close(c->fd); free(c->buf); free(c); } static void request_timeout(int fd, short events, void *arg) { struct request *c = arg; log_warnx("request %u has timed out", c->request_id); cleanup_request(c); } static void requests_purge(void) { uint64_t slot; struct request *c; for (slot = 0; slot < nitems(requests); slot++) { while (!TAILQ_EMPTY(&requests[slot])) { c = TAILQ_FIRST(&requests[slot]); cleanup_request(c); } } } static uint32_t get_request_id(void) { int duplicate = 0; uint32_t id; do { id = arc4random(); duplicate = (find_request(id) != NULL); } while (duplicate || id == 0); return id; } static void request_done(struct request *c) { /* * If we have not yet handed the client off to gotweb.c we * must send an FCGI end record ourselves. */ if (c->client_status < CLIENT_REQUEST) fcgi_create_end_record(c); cleanup_request(c); } void sockets(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; struct event_base *evb; requests_init(); evb = event_init(); sockets_rlimit(-1); env->iev_parent = calloc(1, sizeof(*env->iev_parent)); if (env->iev_parent == NULL) fatal("calloc"); if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&env->iev_parent->ibuf); env->iev_parent->handler = sockets_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, sockets_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); if (env->prefork <= 0) fatalx("invalid prefork count: %d", env->prefork); env->iev_auth = calloc(env->prefork, sizeof(*env->iev_auth)); if (env->iev_auth == NULL) fatal("calloc"); env->auth_pending = env->prefork; signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, sockets_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, sockets_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, sockets_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, sockets_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, sockets_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio inet unix recvfd sendfd", NULL) == -1) fatal("pledge"); #endif event_dispatch(); event_base_free(evb); sockets_shutdown(); } void sockets_parse_sockets(struct gotwebd *env) { struct address *a; struct socket *new_sock = NULL; int sock_id = 1; TAILQ_FOREACH(a, &env->addresses, entry) { new_sock = sockets_conf_new_socket(sock_id, a); if (new_sock) { sock_id++; TAILQ_INSERT_TAIL(&env->sockets, new_sock, entry); } } } struct socket * sockets_conf_new_socket(int id, struct address *a) { struct socket *sock; struct address *acp; if ((sock = calloc(1, sizeof(*sock))) == NULL) fatalx("%s: calloc", __func__); sock->conf.id = id; sock->fd = -1; sock->conf.af_type = a->ss.ss_family; if (a->ss.ss_family == AF_UNIX) { struct sockaddr_un *sun; sun = (struct sockaddr_un *)&a->ss; if (strlcpy(sock->conf.unix_socket_name, sun->sun_path, sizeof(sock->conf.unix_socket_name)) >= sizeof(sock->conf.unix_socket_name)) fatalx("unix socket path too long: %s", sun->sun_path); } sock->conf.fcgi_socket_port = a->port; acp = &sock->conf.addr; memcpy(&acp->ss, &a->ss, sizeof(acp->ss)); acp->slen = a->slen; acp->ai_family = a->ai_family; acp->ai_socktype = a->ai_socktype; acp->ai_protocol = a->ai_protocol; acp->port = a->port; if (*a->ifname != '\0') { if (strlcpy(acp->ifname, a->ifname, sizeof(acp->ifname)) >= sizeof(acp->ifname)) { fatalx("%s: interface name truncated", __func__); } } return (sock); } static void sockets_launch(struct gotwebd *env) { struct socket *sock; const char *sockname; int i, have_unix = 0, have_inet = 0; if (env->iev_fcgi == NULL) fatalx("fcgi process not connected"); if (env->auth_pending != 0) fatal("auth process not connected"); TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) { if (sock->conf.af_type == AF_UNIX) { have_unix = 1; sockname = sock->conf.unix_socket_name; } else { have_inet = 1; sockname = sock->conf.addr.ifname; } log_info("%s: configuring socket %s %d (%d)", __func__, sockname, sock->conf.id, sock->fd); if (listen(sock->fd, SOCKS_BACKLOG) == -1) fatal("cannot listen on %s", sockname); event_set(&sock->ev, sock->fd, EV_READ | EV_PERSIST, sockets_socket_accept, sock); if (event_add(&sock->ev, NULL)) fatalx("event add sock"); evtimer_set(&sock->pause, sockets_socket_accept, sock); log_info("%s: running socket listener %d", __func__, sock->conf.id); } #ifndef PROFILE if (have_unix && have_inet) { if (pledge("stdio inet unix sendfd", NULL) == -1) fatal("pledge"); } else if (have_unix) { if (pledge("stdio unix sendfd", NULL) == -1) fatal("pledge"); } else if (have_inet) { if (pledge("stdio inet sendfd", NULL) == -1) fatal("pledge"); } #endif event_add(&env->iev_fcgi->ev, NULL); for (i = 0; i < env->prefork; i++) event_add(&env->iev_auth[i].ev, NULL); } static void abort_request(struct imsg *imsg) { struct request *c; uint32_t request_id; if (imsg_get_data(imsg, &request_id, sizeof(request_id)) == -1) { log_warn("imsg_get_data"); return; } c = find_request(request_id); if (c == NULL) return; request_done(c); } static void server_dispatch_auth(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_REQ_ABORT: abort_request(&imsg); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_auth_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->auth_pending <= 0) { log_warn("all auth pipes already received"); return; } fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid auth pipe fd"); iev = &env->iev_auth[env->auth_pending - 1]; if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct request)); iev->handler = server_dispatch_auth; iev->data = iev; event_set(&iev->ev, fd, EV_READ, server_dispatch_auth, iev); imsg_event_add(iev); env->auth_pending--; } static struct imsgev * select_worker(struct request *c) { struct gotwebd *env = gotwebd_env; int i, least_busy_worker_idx, min_load; min_load = env->worker_load[0]; least_busy_worker_idx = 0; for (i = 1; i < env->prefork; i++) { if (env->worker_load[i] > min_load) continue; min_load = env->worker_load[i]; least_busy_worker_idx = i; } log_debug("dispatching request %u to gotweb %d", c->request_id, least_busy_worker_idx); c->worker_idx = least_busy_worker_idx; return &env->iev_auth[least_busy_worker_idx]; } static int process_request(struct request *c) { struct gotwebd *env = gotwebd_env; struct gotwebd_fcgi_params *params = &c->fcgi_params; struct querystring *qs = ¶ms->qs; struct imsgev *iev_auth; int ret, i; struct request ic; /* Fill in defaults for unspecified parameters where needed. */ if (qs->action == NO_ACTION) qs->action = INDEX; if (qs->index_page == -1) qs->index_page = 0; if (qs->headref[0] == '\0') { if (strlcpy(qs->headref, GOT_REF_HEAD, sizeof(qs->headref)) >= sizeof(qs->headref)) { log_warnx("head reference buffer too small"); return -1; } } if (params->server_name[0] == '\0') { struct server *srv = TAILQ_FIRST(&env->servers); if (strlcpy(params->server_name, srv->name, sizeof(params->server_name)) >= sizeof(params->server_name)) { log_warnx("server name buffer too small"); return -1; } } memcpy(&ic, c, sizeof(ic)); /* Don't leak pointers from our address space to another process. */ ic.sock = NULL; ic.srv = NULL; ic.t = NULL; ic.tp = NULL; ic.buf = NULL; ic.outbuf = NULL; /* Other process will use its own set of temp files. */ for (i = 0; i < nitems(c->priv_fd); i++) ic.priv_fd[i] = -1; ic.fd = -1; iev_auth = select_worker(c); ret = imsg_compose_event(iev_auth, GOTWEBD_IMSG_REQ_PROCESS, GOTWEBD_PROC_SOCKETS, -1, c->fd, &ic, sizeof(ic)); if (ret == -1) { log_warn("imsg_compose_event"); c->worker_idx = -1; return -1; } c->fd = -1; c->client_status = CLIENT_REQUEST; env->worker_load[c->worker_idx]++; return 0; } static void recv_parsed_params(struct imsg *imsg) { struct gotwebd_fcgi_params params, *p; struct request *c; if (imsg_get_data(imsg, ¶ms, sizeof(params)) == -1) { log_warn("imsg_get_data"); return; } c = find_request(params.request_id); if (c == NULL) return; if (c->client_status > CLIENT_FCGI_STDIN) return; if (c->client_status < CLIENT_FCGI_PARAMS) goto fail; p = &c->fcgi_params; if (params.qs.action != NO_ACTION) p->qs.action = params.qs.action; if (params.qs.commit[0] && strlcpy(p->qs.commit, params.qs.commit, sizeof(p->qs.commit)) >= sizeof(p->qs.commit)) { log_warnx("commit ID too long"); goto fail; } if (params.qs.file[0] && strlcpy(p->qs.file, params.qs.file, sizeof(p->qs.file)) >= sizeof(p->qs.file)) { log_warnx("file path too long"); goto fail; } if (params.qs.folder[0] && strlcpy(p->qs.folder, params.qs.folder, sizeof(p->qs.folder)) >= sizeof(p->qs.folder)) { log_warnx("folder path too long"); goto fail; } if (params.qs.headref[0] && strlcpy(p->qs.headref, params.qs.headref, sizeof(p->qs.headref)) >= sizeof(p->qs.headref)) { log_warnx("headref too long"); goto fail; } if (params.qs.index_page != -1) p->qs.index_page = params.qs.index_page; if (params.qs.path[0] && strlcpy(p->qs.path, params.qs.path, sizeof(p->qs.path)) >= sizeof(p->qs.path)) { log_warnx("path path too long"); goto fail; } if (params.qs.login[0] != '\0' && strlcpy(p->qs.login, params.qs.login, sizeof(p->qs.login)) >= sizeof(p->qs.login)) { log_warnx("login token too long"); goto fail; } if (params.document_uri[0] != '\0' && strlcpy(p->document_uri, params.document_uri, sizeof(p->document_uri)) >= sizeof(p->document_uri)) { log_warnx("document uri too long"); goto fail; } if (params.server_name[0] != '\0' && strlcpy(p->server_name, params.server_name, sizeof(p->server_name)) >= sizeof(p->server_name)) { log_warnx("server name too long"); goto fail; } if (params.auth_cookie[0] != '\0' && strlcpy(p->auth_cookie, params.auth_cookie, sizeof(p->auth_cookie)) >= sizeof(p->auth_cookie)) { log_warnx("auth cookie too long"); goto fail; } if (params.https && !p->https) p->https = 1; c->nparams_parsed++; if (c->client_status == CLIENT_FCGI_STDIN && c->nparams_parsed >= c->nparams) { if (process_request(c) == -1) goto fail; } return; fail: request_done(c); } static void server_dispatch_fcgi(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_FCGI_PARAMS: recv_parsed_params(&imsg); break; case GOTWEBD_IMSG_REQ_ABORT: abort_request(&imsg); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_fcgi_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->iev_fcgi != NULL) { log_warn("fcgi pipe already received"); return; } fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid fcgi pipe fd"); iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct gotwebd_fcgi_record)); iev->handler = server_dispatch_fcgi; iev->data = iev; event_set(&iev->ev, fd, EV_READ, server_dispatch_fcgi, iev); imsg_event_add(iev); env->iev_fcgi = iev; } static void sockets_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_SRV: config_getserver(env, &imsg); break; case GOTWEBD_IMSG_CFG_SOCK: config_getsock(env, &imsg); break; case GOTWEBD_IMSG_CFG_DONE: config_getcfg(env, &imsg); break; case GOTWEBD_IMSG_CTL_PIPE: if (env->iev_fcgi == NULL) recv_fcgi_pipe(env, &imsg); else recv_auth_pipe(env, &imsg); break; case GOTWEBD_IMSG_CTL_START: sockets_launch(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void sockets_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: sockets_shutdown(); break; default: log_info("SIGNAL: %d", sig); fatalx("unexpected signal"); } } static void sockets_shutdown(void) { int i; requests_purge(); /* clean servers */ while (!TAILQ_EMPTY(&gotwebd_env->servers)) { struct server *srv; srv = TAILQ_FIRST(&gotwebd_env->servers); TAILQ_REMOVE(&gotwebd_env->servers, srv, entry); free(srv); } while (!TAILQ_EMPTY(&gotwebd_env->addresses)) { struct address *h; h = TAILQ_FIRST(&gotwebd_env->addresses); TAILQ_REMOVE(&gotwebd_env->addresses, h, entry); free(h); } while (!TAILQ_EMPTY(&gotwebd_env->sockets)) { struct socket *sock; sock = TAILQ_FIRST(&gotwebd_env->sockets); TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); free(sock); } imsgbuf_clear(&gotwebd_env->iev_parent->ibuf); free(gotwebd_env->iev_parent); imsgbuf_clear(&gotwebd_env->iev_fcgi->ibuf); free(gotwebd_env->iev_fcgi); for (i = 0; i < gotwebd_env->prefork; i++) imsgbuf_clear(&gotwebd_env->iev_auth[i].ibuf); free(gotwebd_env->iev_auth); free(gotwebd_env->worker_load); free(gotwebd_env); exit(0); } int sockets_privinit(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid) { if (sock->conf.af_type == AF_UNIX) { log_info("%s: initializing unix socket %s", __func__, sock->conf.unix_socket_name); sock->fd = sockets_unix_socket_listen(env, sock, uid, gid); if (sock->fd == -1) return -1; } if (sock->conf.af_type == AF_INET || sock->conf.af_type == AF_INET6) { log_info("%s: initializing %s FCGI socket on port %d", __func__, sock->conf.af_type == AF_INET ? "inet" : "inet6", sock->conf.fcgi_socket_port); sock->fd = sockets_create_socket(&sock->conf.addr); if (sock->fd == -1) return -1; } return 0; } static int sockets_unix_socket_listen(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid) { int u_fd = -1; mode_t old_umask, mode; int flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC flags |= SOCK_CLOEXEC; #endif u_fd = socket(AF_UNIX, flags, 0); if (u_fd == -1) { log_warn("%s: socket", __func__); return -1; } if (unlink(sock->conf.unix_socket_name) == -1) { if (errno != ENOENT) { log_warn("%s: unlink %s", __func__, sock->conf.unix_socket_name); close(u_fd); return -1; } } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP; if (bind(u_fd, (struct sockaddr *)&sock->conf.addr.ss, sock->conf.addr.slen) == -1) { log_warn("%s: bind: %s", __func__, sock->conf.unix_socket_name); close(u_fd); (void)umask(old_umask); return -1; } (void)umask(old_umask); if (chmod(sock->conf.unix_socket_name, mode) == -1) { log_warn("%s: chmod", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } if (chown(sock->conf.unix_socket_name, uid, gid) == -1) { log_warn("%s: chown", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } return u_fd; } static int sockets_create_socket(struct address *a) { int fd = -1, o_val = 1, flags; fd = socket(a->ai_family, a->ai_socktype, a->ai_protocol); if (fd == -1) return -1; log_debug("%s: opened socket (%d) for %s", __func__, fd, a->ifname); if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &o_val, sizeof(int)) == -1) { log_warn("%s: setsockopt error", __func__); close(fd); return -1; } /* non-blocking */ flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) { log_warn("%s: could not enable non-blocking I/O", __func__); close(fd); return -1; } if (bind(fd, (struct sockaddr *)&a->ss, a->slen) == -1) { close(fd); log_warn("%s: can't bind to port %d", __func__, a->port); return -1; } return (fd); } static int sockets_accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int reserve, volatile int *counter) { int ret; if (getdtablecount() + reserve + *counter + 1 >= getdtablesize()) { log_warnx("inflight fds exceeded"); errno = EMFILE; return -1; } /* TA: This needs fixing upstream. */ #ifdef __APPLE__ ret = accept(sockfd, addr, addrlen); #else ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif if (ret > -1) { (*counter)++; log_debug("inflight incremented, now %d", *counter); } return ret; } static int parse_params(struct request *c, uint8_t *record, size_t record_len) { struct gotwebd *env = gotwebd_env; struct gotwebd_fcgi_record rec; int ret; memset(&rec, 0, sizeof(rec)); memcpy(rec.record, record, record_len); rec.record_len = record_len; rec.request_id = c->request_id; ret = imsg_compose_event(env->iev_fcgi, GOTWEBD_IMSG_FCGI_PARSE_PARAMS, GOTWEBD_PROC_SOCKETS, -1, -1, &rec, sizeof(rec)); if (ret == -1) log_warn("imsg_compose_event"); return ret; } static void read_fcgi_records(int fd, short events, void *arg) { struct request *c = arg; ssize_t n; struct fcgi_record_header h; size_t record_len; n = read(fd, c->buf + c->buf_len, FCGI_RECORD_SIZE - c->buf_len); switch (n) { case -1: switch (errno) { case EINTR: case EAGAIN: goto more; default: goto fail; } break; case 0: if (c->client_status < CLIENT_FCGI_STDIN) { log_warnx("client %u closed connection too early", c->request_id); goto fail; } return; default: break; } c->buf_len += n; while (c->buf_len >= sizeof(h)) { memcpy(&h, c->buf, sizeof(h)); record_len = sizeof(h) + ntohs(h.content_len) + h.padding_len; if (record_len > FCGI_RECORD_SIZE) { log_warnx("FGI record length too large"); goto fail; } if (c->buf_len < record_len) goto more; switch (h.type) { case FCGI_BEGIN_REQUEST: if (c->client_status >= CLIENT_FCGI_BEGIN) { log_warnx("unexpected FCGI_BEGIN_REQUEST"); goto fail; } if (ntohs(h.content_len) != sizeof(struct fcgi_begin_request_body)) { log_warnx("wrong begin request size %u != %zu", ntohs(h.content_len), sizeof(struct fcgi_begin_request_body)); goto fail; } /* XXX -- FCGI_CANT_MPX_CONN */ c->client_status = CLIENT_FCGI_BEGIN; c->id = ntohs(h.id); break; case FCGI_PARAMS: if (c->client_status < CLIENT_FCGI_BEGIN) { log_warnx("FCGI_PARAMS without " "FCGI_BEGIN_REQUEST"); goto fail; } if (c->client_status > CLIENT_FCGI_PARAMS) { log_warnx("FCGI_PARAMS after FCGI_STDIN"); goto fail; } if (c->id != ntohs(h.id)) { log_warnx("unexpected ID in FCGI header"); goto fail; } c->client_status = CLIENT_FCGI_PARAMS; c->nparams++; if (parse_params(c, c->buf, record_len) == -1) goto fail; break; case FCGI_ABORT_REQUEST: log_warnx("received FCGI_ABORT_REQUEST from client"); request_done(c); return; case FCGI_STDIN: if (c->client_status < CLIENT_FCGI_BEGIN) { log_warnx("FCGI_STDIN without " "FCGI_BEGIN_REQUEST"); goto fail; } if (c->client_status < CLIENT_FCGI_PARAMS) { log_warnx("FCGI_STDIN without FCGI_PARAMS"); goto fail; } if (c->id != ntohs(h.id)) { log_warnx("unexpected ID in FCGI header"); goto fail; } c->client_status = CLIENT_FCGI_STDIN; if (c->nparams_parsed >= c->nparams) { if (process_request(c) == -1) goto fail; } break; default: log_warn("unexpected FCGI type %u", h.type); goto fail; } /* drop the parsed record */ c->buf_len -= record_len; memmove(c->buf, c->buf + record_len, c->buf_len); } more: event_add(&c->ev, NULL); return; fail: request_done(c); } void sockets_socket_accept(int fd, short event, void *arg) { struct socket *sock = (struct socket *)arg; struct sockaddr_storage ss; struct timeval backoff; struct request *c = NULL; uint8_t *buf = NULL; socklen_t len; int s; backoff.tv_sec = 1; backoff.tv_usec = 0; if (event & EV_TIMEOUT) { event_add(&sock->ev, NULL); return; } len = sizeof(ss); s = sockets_accept_reserve(fd, (struct sockaddr *)&ss, &len, FD_RESERVE, &cgi_inflight); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: event_add(&sock->ev, NULL); return; case EMFILE: case ENFILE: log_warn("accept"); event_del(&sock->ev); evtimer_add(&sock->pause, &backoff); return; default: log_warn("%s: accept", __func__); } } if (client_cnt > GOTWEBD_MAXCLIENTS) { cgi_inflight--; close(s); if (c != NULL) free(c); event_add(&sock->ev, NULL); return; } c = calloc(1, sizeof(struct request)); if (c == NULL) { log_warn("%s: calloc", __func__); close(s); cgi_inflight--; event_add(&sock->ev, NULL); return; } buf = calloc(1, FCGI_RECORD_SIZE); if (buf == NULL) { log_warn("%s: calloc", __func__); close(s); cgi_inflight--; free(c); event_add(&sock->ev, NULL); return; } fcgi_init_querystring(&c->fcgi_params.qs); c->buf = buf; c->fd = s; c->sock = sock; memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd)); c->sock_id = sock->conf.id; c->buf_len = 0; c->client_status = CLIENT_CONNECT; c->request_id = get_request_id(); c->worker_idx = -1; event_set(&c->ev, s, EV_READ, read_fcgi_records, c); event_add(&c->ev, NULL); evtimer_set(&c->tmo, request_timeout, c); evtimer_add(&c->tmo, &timeout); add_request(c); } void sockets_rlimit(int maxfd) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) == -1) fatal("%s: failed to get resource limit", __func__); log_info("%s: max open files %llu", __func__, (unsigned long long)rl.rlim_max); /* * Allow the maximum number of open file descriptors for this * login class (which should be the class "daemon" by default). */ if (maxfd == -1) rl.rlim_cur = rl.rlim_max; else rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd); if (setrlimit(RLIMIT_NOFILE, &rl) == -1) fatal("%s: failed to set resource limit", __func__); } got-portable-0.119/gotwebd/fcgi.c0000664000175000017500000005146415066536113012335 /* * Copyright (c) 2020-2022 Tracey Emery * Copyright (c) 2014 Reyk Floeter * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "got_object.h" #include "got_lib_poll.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" static void fcgi_sighdlr(int, short, void *); static void fcgi_shutdown(void); static void fcgi_launch(struct gotwebd *); void fcgi_parse_record(struct gotwebd_fcgi_record *); int fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *, uint16_t); int fcgi_parse_params(uint8_t *, uint16_t, struct gotwebd_fcgi_params *); int fcgi_send_response(struct request *, int, const void *, size_t); void dump_fcgi_request_body(const char *, struct fcgi_record_header *); void dump_fcgi_record_header(const char *, struct fcgi_record_header *); void dump_fcgi_begin_request_body(const char *, struct fcgi_begin_request_body *); void dump_fcgi_end_request_body(const char *, struct fcgi_end_request_body *); extern struct requestlist requests; static void fcgi_shutdown(void) { imsgbuf_clear(&gotwebd_env->iev_parent->ibuf); free(gotwebd_env->iev_parent); if (gotwebd_env->iev_sockets) { imsgbuf_clear(&gotwebd_env->iev_sockets->ibuf); free(gotwebd_env->iev_sockets); } free(gotwebd_env); exit(0); } static void fcgi_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: fcgi_shutdown(); break; default: log_warn("unexpected signal %d", sig); break; } } static void send_parsed_params(struct gotwebd_fcgi_params *params) { struct gotwebd *env = gotwebd_env; if (imsg_compose_event(env->iev_sockets, GOTWEBD_IMSG_FCGI_PARAMS, GOTWEBD_PROC_FCGI, -1, -1, params, sizeof(*params)) == -1) log_warn("imsg_compose_event"); } static void abort_request(uint32_t request_id) { struct gotwebd *env = gotwebd_env; if (imsg_compose_event(env->iev_sockets, GOTWEBD_IMSG_REQ_ABORT, GOTWEBD_PROC_FCGI, -1, -1, &request_id, sizeof(request_id)) == -1) log_warn("imsg_compose_event"); } void fcgi_parse_record(struct gotwebd_fcgi_record *rec) { struct fcgi_record_header *h; uint8_t *record_body; struct gotwebd_fcgi_params params = { 0 }; fcgi_init_querystring(¶ms.qs); if (rec->record_len < sizeof(struct fcgi_record_header) || rec->record_len > sizeof(rec->record)) { log_warnx("invalid fcgi record size"); abort_request(rec->request_id); return; } h = (struct fcgi_record_header *)&rec->record[0]; dump_fcgi_record_header("", h); if (rec->record_len != sizeof(*h) + ntohs(h->content_len) + h->padding_len) { abort_request(rec->request_id); return; } dump_fcgi_request_body("", h); if (h->version != 1) { log_warn("wrong fcgi header version: %u", h->version); abort_request(rec->request_id); return; } record_body = &rec->record[sizeof(*h)]; switch (h->type) { case FCGI_PARAMS: if (fcgi_parse_params(record_body, ntohs(h->content_len), ¶ms) == -1) { abort_request(rec->request_id); break; } params.request_id = rec->request_id; send_parsed_params(¶ms); break; default: log_warn("unexpected fcgi type %d", h->type); abort_request(rec->request_id); break; } } static const struct querystring_keys querystring_keys[] = { { "action", ACTION }, { "commit", COMMIT }, { "file", RFILE }, { "folder", FOLDER }, { "headref", HEADREF }, { "index_page", INDEX_PAGE }, { "path", PATH }, { "login", LOGIN }, }; static const struct action_keys action_keys[] = { { "blame", BLAME }, { "blob", BLOB }, { "blobraw", BLOBRAW }, { "briefs", BRIEFS }, { "commits", COMMITS }, { "diff", DIFF }, { "error", ERR }, { "index", INDEX }, { "patch", PATCH }, { "summary", SUMMARY }, { "tag", TAG }, { "tags", TAGS }, { "tree", TREE }, { "rss", RSS }, }; void fcgi_init_querystring(struct querystring *qs) { memset(qs, 0, sizeof(*qs)); qs->action = NO_ACTION; qs->index_page = -1; } /* * Adapted from usr.sbin/httpd/httpd.c url_decode. */ static const struct got_error * urldecode(char *url) { char *p, *q; char hex[3]; unsigned long x; hex[2] = '\0'; p = q = url; while (*p != '\0') { switch (*p) { case '%': /* Encoding character is followed by two hex chars */ if (!isxdigit((unsigned char)p[1]) || !isxdigit((unsigned char)p[2]) || (p[1] == '0' && p[2] == '0')) return got_error(GOT_ERR_BAD_QUERYSTRING); hex[0] = p[1]; hex[1] = p[2]; /* * We don't have to validate "hex" because it is * guaranteed to include two hex chars followed by nul. */ x = strtoul(hex, NULL, 16); *q = (char)x; p += 2; break; default: *q = *p; break; } p++; q++; } *q = '\0'; return NULL; } static const struct got_error * validate_path(const char *path) { size_t len = strlen(path); if (len >= 3 && strncmp(path, "../", 3) == 0) return got_error(GOT_ERR_BAD_QUERYSTRING); if (len >= 4 && strstr(path, "/../") != NULL) return got_error(GOT_ERR_BAD_QUERYSTRING); if (len >= 3 && strcmp(path + len - 3, "/..") == 0) return got_error(GOT_ERR_BAD_QUERYSTRING); return NULL; } static const struct got_error * assign_querystring(struct querystring *qs, char *key, char *value) { const struct got_error *error = NULL; const char *errstr; int a_cnt, el_cnt; error = urldecode(value); if (error) return error; for (el_cnt = 0; el_cnt < nitems(querystring_keys); el_cnt++) { if (strcmp(key, querystring_keys[el_cnt].name) != 0) continue; switch (querystring_keys[el_cnt].element) { case ACTION: for (a_cnt = 0; a_cnt < nitems(action_keys); a_cnt++) { if (strcmp(value, action_keys[a_cnt].name) != 0) continue; qs->action = action_keys[a_cnt].action; break; } if (a_cnt == nitems(action_keys)) qs->action = ERR; break; case COMMIT: if (strlcpy(qs->commit, value, sizeof(qs->commit)) >= sizeof(qs->commit)) { error = got_error_msg(GOT_ERR_NO_SPACE, "requested commit ID too long"); goto done; } break; case RFILE: error = validate_path(value); if (error) goto done; if (strlcpy(qs->file, value, sizeof(qs->file)) >= sizeof(qs->file)) { error = got_error_msg(GOT_ERR_NO_SPACE, "requested in-repository path too long"); goto done; } break; case FOLDER: error = validate_path(value); if (error) goto done; if (strlcpy(qs->folder, value[0] ? value : "/", sizeof(qs->folder)) >= sizeof(qs->folder)) { error = got_error_msg(GOT_ERR_NO_SPACE, "requested repository folder path " "too long"); goto done; } break; case HEADREF: error = validate_path(value); if (error) goto done; if (strlcpy(qs->headref, value, sizeof(qs->headref)) >= sizeof(qs->headref)) { error = got_error_msg(GOT_ERR_NO_SPACE, "requested repository head ref too long"); goto done; } break; case INDEX_PAGE: if (*value == '\0') break; qs->index_page = strtonum(value, 0, INT_MAX, &errstr); if (errstr) { error = got_error_from_errno3(__func__, "strtonum", errstr); goto done; } break; case PATH: error = validate_path(value); if (error) goto done; if (strlcpy(qs->path, value, sizeof(qs->path)) >= sizeof(qs->path)) { error = got_error_msg(GOT_ERR_NO_SPACE, "requested repository path too long"); goto done; } break; case LOGIN: if (strlcpy(qs->login, value, sizeof(qs->login)) >= sizeof(qs->login)) { error = got_error_msg(GOT_ERR_NO_SPACE, "login token too long"); goto done; } break; } /* entry found */ break; } done: return error; } static const struct got_error * parse_querystring(struct querystring *qs, char *qst) { const struct got_error *error = NULL; char *tok1 = NULL, *tok1_pair = NULL, *tok1_end = NULL; char *tok2 = NULL, *tok2_pair = NULL, *tok2_end = NULL; if (qst == NULL) return error; tok1 = strdup(qst); if (tok1 == NULL) return got_error_from_errno2(__func__, "strdup"); tok1_pair = tok1; tok1_end = tok1; while (tok1_pair != NULL) { strsep(&tok1_end, "&"); tok2 = strdup(tok1_pair); if (tok2 == NULL) { free(tok1); return got_error_from_errno2(__func__, "strdup"); } tok2_pair = tok2; tok2_end = tok2; while (tok2_pair != NULL) { strsep(&tok2_end, "="); if (tok2_end) { error = assign_querystring(qs, tok2_pair, tok2_end); if (error) goto err; } tok2_pair = tok2_end; } free(tok2); tok1_pair = tok1_end; } free(tok1); return error; err: free(tok2); free(tok1); return error; } static void parse_cookie_hdr(struct gotwebd_fcgi_params *params, char *hdr, size_t len) { size_t l; char *end; memset(params->auth_cookie, 0, sizeof(params->auth_cookie)); while (len > 0) { if (hdr[0] == ' ' || hdr[0] == '\t') { hdr++; len--; continue; } /* looking at the start of name=val */ if ((end = memchr(hdr, ' ', len)) == NULL || (end = memchr(hdr, '\t', len)) == NULL) end = hdr + len; l = end - hdr; if (len > 8 && !strncmp(hdr, "gwdauth=", 8)) { hdr += 8; len -= 8; l -= 8; if (l < MAX_AUTH_COOKIE - 1) { memcpy(params->auth_cookie, hdr, l); params->auth_cookie[l] = '\0'; } return; } /* skip to the next one */ hdr += l; len -= l; } } int fcgi_parse_params(uint8_t *buf, uint16_t n, struct gotwebd_fcgi_params *params) { const struct got_error *error; uint32_t name_len, val_len; uint8_t *val; if (n == 0) return 0; while (n > 0) { if (buf[0] >> 7 == 0) { name_len = buf[0]; n--; buf++; } else { if (n > 3) { name_len = ((buf[0] & 0x7f) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; n -= 4; buf += 4; } else return -1; } if (n == 0) return -1; if (buf[0] >> 7 == 0) { val_len = buf[0]; n--; buf++; } else { if (n > 3) { val_len = ((buf[0] & 0x7f) << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; n -= 4; buf += 4; } else return -1; } if (n < name_len + val_len) return -1; val = buf + name_len; if (val_len < MAX_QUERYSTRING && name_len == 12 && strncmp(buf, "QUERY_STRING", 12) == 0) { char querystring[MAX_QUERYSTRING]; memcpy(querystring, val, val_len); querystring[val_len] = '\0'; fcgi_init_querystring(¶ms->qs); error = parse_querystring(¶ms->qs, querystring); if (error) { log_warnx("%s: %s", __func__, error->msg); return -1; } } if (val_len < MAX_DOCUMENT_URI && name_len == 12 && strncmp(buf, "DOCUMENT_URI", 12) == 0) { memcpy(params->document_uri, val, val_len); params->document_uri[val_len] = '\0'; } if (val_len < MAX_SERVER_NAME && name_len == 11 && strncmp(buf, "SERVER_NAME", 11) == 0) { memcpy(params->server_name, val, val_len); params->server_name[val_len] = '\0'; } if (name_len == 5 && strncmp(buf, "HTTPS", 5) == 0) params->https = 1; if (name_len == 11 && strncmp(buf, "HTTP_COOKIE", 11) == 0) parse_cookie_hdr(params, val, val_len); buf += name_len + val_len; n -= name_len - val_len; } return 0; } static int send_response(struct request *c, int type, const uint8_t *data, size_t len) { static const uint8_t padding[FCGI_PADDING_SIZE]; struct fcgi_record_header header; struct iovec iov[3]; struct timespec ts; ssize_t nw; size_t padded_len, tot; int i, err = 0, th = 20; ts.tv_sec = 0; ts.tv_nsec = 50; memset(&header, 0, sizeof(header)); header.version = 1; header.type = type; header.id = htons(c->id); header.content_len = htons(len); /* The FastCGI spec suggests to align the output buffer */ tot = sizeof(header) + len; padded_len = FCGI_ALIGN(tot); if (padded_len > tot) { header.padding_len = padded_len - tot; tot += header.padding_len; } iov[0].iov_base = &header; iov[0].iov_len = sizeof(header); iov[1].iov_base = (void *)data; iov[1].iov_len = len; iov[2].iov_base = (void *)padding; iov[2].iov_len = header.padding_len; dump_fcgi_record_header("resp ", &header); /* * XXX: add some simple write heuristics here * On slower VMs, spotty connections, etc., we don't want to go right to * disconnect. Let's at least try to write the data a few times before * giving up. */ while (tot > 0) { nw = writev(c->fd, iov, nitems(iov)); if (nw == 0) { c->client_status = CLIENT_DISCONNECT; break; } if (nw == -1) { err++; if (errno == EAGAIN && err < th) { nanosleep(&ts, NULL); continue; } log_warn("%s: write failure", __func__); c->client_status = CLIENT_DISCONNECT; return -1; } if (nw != tot) log_warnx("%s: partial write: %zu vs %zu", __func__, nw, tot); tot -= nw; for (i = 0; i < nitems(iov); ++i) { if (nw < iov[i].iov_len) { iov[i].iov_base += nw; iov[i].iov_len -= nw; break; } nw -= iov[i].iov_len; iov[i].iov_len = 0; } } return 0; } int fcgi_send_response(struct request *c, int type, const void *data, size_t len) { size_t avail; if (c->client_status == CLIENT_DISCONNECT) return -1; while (len > 0) { avail = len; if (avail > FCGI_CONTENT_SIZE) avail = FCGI_CONTENT_SIZE; if (send_response(c, type, data, avail) == -1) return -1; data += avail; len -= avail; } return 0; } int fcgi_write(void *arg, const void *buf, size_t len) { struct request *c = arg; return fcgi_send_response(c, FCGI_STDOUT, buf, len); } void fcgi_create_end_record(struct request *c) { struct fcgi_end_request_body end_request; memset(&end_request, 0, sizeof(end_request)); end_request.app_status = htonl(0); /* script status */ end_request.protocol_status = FCGI_REQUEST_COMPLETE; fcgi_send_response(c, FCGI_END_REQUEST, &end_request, sizeof(end_request)); } void fcgi_cleanup_request(struct request *c) { if (evtimer_initialized(&c->tmo)) evtimer_del(&c->tmo); if (event_initialized(&c->ev)) event_del(&c->ev); if (c->fd != -1) close(c->fd); if (c->tp != NULL) template_free(c->tp); if (c->t != NULL) gotweb_free_transport(c->t); free(c->buf); free(c->outbuf); free(c); } void dump_fcgi_request_body(const char *p, struct fcgi_record_header *h) { if (h->type == FCGI_BEGIN_REQUEST) dump_fcgi_begin_request_body(p, (struct fcgi_begin_request_body *)(h + 1)); else if (h->type == FCGI_END_REQUEST) dump_fcgi_end_request_body(p, (struct fcgi_end_request_body *)(h + 1)); } void dump_fcgi_record_header(const char* p, struct fcgi_record_header *h) { log_debug("%sversion: %d", p, h->version); log_debug("%stype: %d", p, h->type); log_debug("%srequestId: %d", p, ntohs(h->id)); log_debug("%scontentLength: %d", p, ntohs(h->content_len)); log_debug("%spaddingLength: %d", p, h->padding_len); log_debug("%sreserved: %d", p, h->reserved); } void dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b) { log_debug("%srole %d", p, ntohs(b->role)); log_debug("%sflags %d", p, b->flags); } void dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b) { log_debug("%sappStatus: %d", p, ntohl(b->app_status)); log_debug("%sprotocolStatus: %d", p, b->protocol_status); } static void fcgi_launch(struct gotwebd *env) { if (env->iev_sockets == NULL) fatalx("sockets process not connected"); #ifndef PROFILE if (pledge("stdio", NULL) == -1) fatal("pledge"); #endif event_add(&env->iev_sockets->ev, NULL); } static struct gotwebd_fcgi_record * recv_record(struct imsg *imsg) { struct gotwebd_fcgi_record *record; record = calloc(1, sizeof(*record)); if (record == NULL) { log_warn("calloc"); return NULL; } if (imsg_get_data(imsg, record, sizeof(*record)) == -1) { log_warn("imsg_get_data"); free(record); return NULL; } return record; } static void fcgi_dispatch_server(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_FCGI_PARSE_PARAMS: { struct gotwebd_fcgi_record *rec; rec = recv_record(&imsg); if (rec) { fcgi_parse_record(rec); free(rec); } break; } default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_server_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->iev_sockets != NULL) { log_warn("sockets pipe already received"); return; } fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid server pipe fd"); iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct gotwebd_fcgi_record)); iev->handler = fcgi_dispatch_server; iev->data = iev; event_set(&iev->ev, fd, EV_READ, fcgi_dispatch_server, iev); imsg_event_add(iev); env->iev_sockets = iev; } static void fcgi_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_DONE: config_getcfg(env, &imsg); break; case GOTWEBD_IMSG_CTL_PIPE: recv_server_pipe(env, &imsg); break; case GOTWEBD_IMSG_CTL_START: fcgi_launch(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_fcgi(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; struct event_base *evb; evb = event_init(); if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL) fatal("malloc"); if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&env->iev_parent->ibuf); env->iev_parent->handler = fcgi_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, fcgi_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, fcgi_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, fcgi_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, fcgi_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, fcgi_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, fcgi_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio recvfd", NULL) == -1) fatal("pledge"); #endif event_dispatch(); event_base_free(evb); fcgi_shutdown(); } got-portable-0.119/gotwebd/parse.c0000664000175000017500000025671315066537256012554 /* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* First part of user prologue. */ #line 23 "parse.y" #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotwebd *gotwebd; static struct server *new_srv; static struct server *conf_new_server(const char *); int getservice(const char *); int n; int get_addrs(const char *, const char *); struct address *get_unix_addr(const char *); int addr_dup_check(struct addresslist *, struct address *); void add_addr(struct address *); static struct gotwebd_repo *new_repo; static struct gotwebd_repo *conf_new_repo(struct server *, const char *); static void conf_new_access_rule( struct gotwebd_access_rule_list *, enum gotwebd_access, char *); typedef struct { union { long long number; char *string; } v; int lineno; } YYSTYPE; #line 170 "parse.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ LISTEN = 258, /* LISTEN */ GOTWEBD_LOGIN = 259, /* GOTWEBD_LOGIN */ WWW = 260, /* WWW */ SITE_NAME = 261, /* SITE_NAME */ SITE_OWNER = 262, /* SITE_OWNER */ SITE_LINK = 263, /* SITE_LINK */ LOGO = 264, /* LOGO */ LOGO_URL = 265, /* LOGO_URL */ SHOW_REPO_OWNER = 266, /* SHOW_REPO_OWNER */ SHOW_REPO_AGE = 267, /* SHOW_REPO_AGE */ SHOW_REPO_DESCRIPTION = 268, /* SHOW_REPO_DESCRIPTION */ MAX_REPOS_DISPLAY = 269, /* MAX_REPOS_DISPLAY */ REPOS_PATH = 270, /* REPOS_PATH */ MAX_COMMITS_DISPLAY = 271, /* MAX_COMMITS_DISPLAY */ ON = 272, /* ON */ ERROR = 273, /* ERROR */ SHOW_SITE_OWNER = 274, /* SHOW_SITE_OWNER */ SHOW_REPO_CLONEURL = 275, /* SHOW_REPO_CLONEURL */ PORT = 276, /* PORT */ PREFORK = 277, /* PREFORK */ RESPECT_EXPORTOK = 278, /* RESPECT_EXPORTOK */ SERVER = 279, /* SERVER */ CHROOT = 280, /* CHROOT */ CUSTOM_CSS = 281, /* CUSTOM_CSS */ SOCKET = 282, /* SOCKET */ SUMMARY_COMMITS_DISPLAY = 283, /* SUMMARY_COMMITS_DISPLAY */ SUMMARY_TAGS_DISPLAY = 284, /* SUMMARY_TAGS_DISPLAY */ USER = 285, /* USER */ AUTHENTICATION = 286, /* AUTHENTICATION */ ENABLE = 287, /* ENABLE */ DISABLE = 288, /* DISABLE */ INSECURE = 289, /* INSECURE */ REPOSITORY = 290, /* REPOSITORY */ PERMIT = 291, /* PERMIT */ DENY = 292, /* DENY */ STRING = 293, /* STRING */ NUMBER = 294 /* NUMBER */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define LISTEN 258 #define GOTWEBD_LOGIN 259 #define WWW 260 #define SITE_NAME 261 #define SITE_OWNER 262 #define SITE_LINK 263 #define LOGO 264 #define LOGO_URL 265 #define SHOW_REPO_OWNER 266 #define SHOW_REPO_AGE 267 #define SHOW_REPO_DESCRIPTION 268 #define MAX_REPOS_DISPLAY 269 #define REPOS_PATH 270 #define MAX_COMMITS_DISPLAY 271 #define ON 272 #define ERROR 273 #define SHOW_SITE_OWNER 274 #define SHOW_REPO_CLONEURL 275 #define PORT 276 #define PREFORK 277 #define RESPECT_EXPORTOK 278 #define SERVER 279 #define CHROOT 280 #define CUSTOM_CSS 281 #define SOCKET 282 #define SUMMARY_COMMITS_DISPLAY 283 #define SUMMARY_TAGS_DISPLAY 284 #define USER 285 #define AUTHENTICATION 286 #define ENABLE 287 #define DISABLE 288 #define INSECURE 289 #define REPOSITORY 290 #define PERMIT 291 #define DENY 292 #define STRING 293 #define NUMBER 294 /* Value type. */ extern YYSTYPE yylval; int yyparse (void); /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL_LISTEN = 3, /* LISTEN */ YYSYMBOL_GOTWEBD_LOGIN = 4, /* GOTWEBD_LOGIN */ YYSYMBOL_WWW = 5, /* WWW */ YYSYMBOL_SITE_NAME = 6, /* SITE_NAME */ YYSYMBOL_SITE_OWNER = 7, /* SITE_OWNER */ YYSYMBOL_SITE_LINK = 8, /* SITE_LINK */ YYSYMBOL_LOGO = 9, /* LOGO */ YYSYMBOL_LOGO_URL = 10, /* LOGO_URL */ YYSYMBOL_SHOW_REPO_OWNER = 11, /* SHOW_REPO_OWNER */ YYSYMBOL_SHOW_REPO_AGE = 12, /* SHOW_REPO_AGE */ YYSYMBOL_SHOW_REPO_DESCRIPTION = 13, /* SHOW_REPO_DESCRIPTION */ YYSYMBOL_MAX_REPOS_DISPLAY = 14, /* MAX_REPOS_DISPLAY */ YYSYMBOL_REPOS_PATH = 15, /* REPOS_PATH */ YYSYMBOL_MAX_COMMITS_DISPLAY = 16, /* MAX_COMMITS_DISPLAY */ YYSYMBOL_ON = 17, /* ON */ YYSYMBOL_ERROR = 18, /* ERROR */ YYSYMBOL_SHOW_SITE_OWNER = 19, /* SHOW_SITE_OWNER */ YYSYMBOL_SHOW_REPO_CLONEURL = 20, /* SHOW_REPO_CLONEURL */ YYSYMBOL_PORT = 21, /* PORT */ YYSYMBOL_PREFORK = 22, /* PREFORK */ YYSYMBOL_RESPECT_EXPORTOK = 23, /* RESPECT_EXPORTOK */ YYSYMBOL_SERVER = 24, /* SERVER */ YYSYMBOL_CHROOT = 25, /* CHROOT */ YYSYMBOL_CUSTOM_CSS = 26, /* CUSTOM_CSS */ YYSYMBOL_SOCKET = 27, /* SOCKET */ YYSYMBOL_SUMMARY_COMMITS_DISPLAY = 28, /* SUMMARY_COMMITS_DISPLAY */ YYSYMBOL_SUMMARY_TAGS_DISPLAY = 29, /* SUMMARY_TAGS_DISPLAY */ YYSYMBOL_USER = 30, /* USER */ YYSYMBOL_AUTHENTICATION = 31, /* AUTHENTICATION */ YYSYMBOL_ENABLE = 32, /* ENABLE */ YYSYMBOL_DISABLE = 33, /* DISABLE */ YYSYMBOL_INSECURE = 34, /* INSECURE */ YYSYMBOL_REPOSITORY = 35, /* REPOSITORY */ YYSYMBOL_PERMIT = 36, /* PERMIT */ YYSYMBOL_DENY = 37, /* DENY */ YYSYMBOL_STRING = 38, /* STRING */ YYSYMBOL_NUMBER = 39, /* NUMBER */ YYSYMBOL_40_n_ = 40, /* '\n' */ YYSYMBOL_41_ = 41, /* '=' */ YYSYMBOL_42_ = 42, /* '*' */ YYSYMBOL_43_ = 43, /* '{' */ YYSYMBOL_44_ = 44, /* '}' */ YYSYMBOL_YYACCEPT = 45, /* $accept */ YYSYMBOL_grammar = 46, /* grammar */ YYSYMBOL_varset = 47, /* varset */ YYSYMBOL_numberstring = 48, /* numberstring */ YYSYMBOL_boolean = 49, /* boolean */ YYSYMBOL_listen_addr = 50, /* listen_addr */ YYSYMBOL_main = 51, /* main */ YYSYMBOL_server = 52, /* server */ YYSYMBOL_53_1 = 53, /* $@1 */ YYSYMBOL_serveropts1 = 54, /* serveropts1 */ YYSYMBOL_serveropts2 = 55, /* serveropts2 */ YYSYMBOL_repository = 56, /* repository */ YYSYMBOL_57_2 = 57, /* $@2 */ YYSYMBOL_repoopts2 = 58, /* repoopts2 */ YYSYMBOL_repoopts1 = 59, /* repoopts1 */ YYSYMBOL_nl = 60, /* nl */ YYSYMBOL_optnl = 61 /* optnl */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_uint8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 149 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 45 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 17 /* YYNRULES -- Number of rules. */ #define YYNRULES 68 /* YYNSTATES -- Number of states. */ #define YYNSTATES 130 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 294 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 43, 2, 44, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 138, 138, 139, 140, 141, 142, 143, 146, 164, 165, 174, 188, 189, 198, 199, 202, 210, 233, 241, 257, 269, 275, 281, 289, 297, 305, 309, 313, 328, 343, 343, 361, 371, 381, 391, 401, 410, 420, 430, 433, 436, 439, 442, 445, 448, 456, 464, 472, 480, 489, 498, 507, 511, 515, 518, 519, 522, 522, 541, 542, 545, 554, 563, 572, 576, 582, 585, 586 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "LISTEN", "GOTWEBD_LOGIN", "WWW", "SITE_NAME", "SITE_OWNER", "SITE_LINK", "LOGO", "LOGO_URL", "SHOW_REPO_OWNER", "SHOW_REPO_AGE", "SHOW_REPO_DESCRIPTION", "MAX_REPOS_DISPLAY", "REPOS_PATH", "MAX_COMMITS_DISPLAY", "ON", "ERROR", "SHOW_SITE_OWNER", "SHOW_REPO_CLONEURL", "PORT", "PREFORK", "RESPECT_EXPORTOK", "SERVER", "CHROOT", "CUSTOM_CSS", "SOCKET", "SUMMARY_COMMITS_DISPLAY", "SUMMARY_TAGS_DISPLAY", "USER", "AUTHENTICATION", "ENABLE", "DISABLE", "INSECURE", "REPOSITORY", "PERMIT", "DENY", "STRING", "NUMBER", "'\\n'", "'='", "'*'", "'{'", "'}'", "$accept", "grammar", "varset", "numberstring", "boolean", "listen_addr", "main", "server", "$@1", "serveropts1", "serveropts2", "repository", "$@2", "repoopts2", "repoopts1", "nl", "optnl", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-48) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-31) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -48, 3, -48, -24, 4, -7, -6, -10, -4, -1, 0, 1, 11, -29, -29, 5, -48, -9, 7, 8, -48, -25, 16, 17, -48, 15, -48, -48, 25, -48, -48, -48, -48, -48, 22, -48, -48, -48, 26, -48, -48, 45, -48, -48, 24, -48, -48, -48, -27, 28, -48, -48, 28, 112, -48, 31, 32, 33, 34, 36, -16, -16, -16, 37, 39, 51, -16, -16, -16, 40, 52, 55, 44, 64, 59, -29, -29, 28, 73, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, 66, -48, -48, -48, -48, -48, -48, 58, -48, 68, 28, -48, 28, -48, 20, 76, 81, -29, -29, -18, 28, 79, -48, -48, -48, -48, 58, -48, -48, -48 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 16, 29, 17, 21, 24, 23, 9, 10, 26, 27, 0, 4, 5, 6, 0, 15, 14, 0, 28, 22, 0, 25, 8, 20, 0, 68, 18, 19, 68, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 54, 33, 34, 35, 36, 37, 12, 11, 13, 40, 41, 42, 45, 32, 46, 39, 43, 44, 38, 47, 48, 50, 49, 57, 52, 53, 56, 31, 0, 51, 0, 68, 55, 68, 66, 0, 0, 0, 0, 0, 0, 68, 62, 61, 64, 65, 58, 0, 60, 63, 59 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -48, -48, -48, -14, -17, -48, -48, -48, -48, 38, -48, -48, -48, -48, -5, -11, -47 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 1, 17, 32, 88, 41, 18, 19, 44, 77, 78, 79, 109, 119, 120, 111, 53 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 33, 85, 38, 2, 3, 54, 4, 5, 6, 30, 31, 50, 51, 39, 115, 116, 20, 40, 117, 118, 22, 21, 86, 87, 23, 7, 125, 8, 9, 24, 105, 35, 28, 10, 25, 11, 12, 26, 27, 13, 14, 15, 29, 16, 89, 90, 34, 36, 37, 94, 95, 96, 115, 116, 42, 43, 117, 118, -30, 45, 46, 103, 104, 113, 47, 114, 48, 49, 52, 80, 81, 82, 83, 127, 84, 100, 91, 92, 97, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 93, 98, 66, 67, 99, 101, 68, 102, 110, 69, 108, 70, 71, 123, 124, 72, 73, 121, 74, 75, 76, 112, 122, 128, 126, 129, 107, 106, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 66, 67, 0, 0, 68, 0, 0, 69, 0, 70, 71, 0, 0, 72, 73, 0, 74, 75, 76 }; static const yytype_int8 yycheck[] = { 14, 17, 27, 0, 1, 52, 3, 4, 5, 38, 39, 38, 39, 38, 32, 33, 40, 42, 36, 37, 27, 17, 38, 39, 30, 22, 44, 24, 25, 39, 77, 40, 31, 30, 38, 32, 33, 38, 38, 36, 37, 38, 31, 40, 61, 62, 41, 40, 40, 66, 67, 68, 32, 33, 38, 38, 36, 37, 43, 34, 38, 75, 76, 110, 38, 112, 21, 43, 40, 38, 38, 38, 38, 120, 38, 31, 39, 38, 38, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 39, 39, 19, 20, 39, 31, 23, 38, 40, 26, 34, 28, 29, 117, 118, 32, 33, 31, 35, 36, 37, 43, 31, 34, 119, 126, 78, 44, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, -1, 19, 20, -1, -1, 23, -1, -1, 26, -1, 28, 29, -1, -1, 32, 33, -1, 35, 36, 37 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 46, 0, 1, 3, 4, 5, 22, 24, 25, 30, 32, 33, 36, 37, 38, 40, 47, 51, 52, 40, 17, 27, 30, 39, 38, 38, 38, 31, 31, 38, 39, 48, 48, 41, 40, 40, 40, 27, 38, 42, 50, 38, 38, 53, 34, 38, 38, 21, 43, 38, 39, 40, 61, 61, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19, 20, 23, 26, 28, 29, 32, 33, 35, 36, 37, 54, 55, 56, 38, 38, 38, 38, 38, 17, 38, 39, 49, 49, 49, 39, 38, 39, 49, 49, 49, 38, 39, 39, 31, 31, 38, 48, 48, 61, 44, 54, 34, 57, 40, 60, 43, 61, 61, 32, 33, 36, 37, 58, 59, 31, 31, 48, 48, 44, 59, 61, 34, 60 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 45, 46, 46, 46, 46, 46, 46, 47, 48, 48, 49, 49, 49, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, 52, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 57, 56, 58, 58, 59, 59, 59, 59, 59, 60, 61, 61 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 2, 2, 5, 5, 4, 2, 3, 2, 2, 3, 2, 2, 3, 2, 0, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 1, 3, 2, 0, 7, 3, 2, 2, 2, 3, 2, 2, 2, 2, 0 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { FILE *yyoutput = yyo; YY_USE (yyoutput); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)]); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep) { YY_USE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 7: /* grammar: grammar error '\n' */ #line 143 "parse.y" { file->errors++; } #line 1412 "parse.c" break; case 8: /* varset: STRING '=' STRING */ #line 146 "parse.y" { char *s = (yyvsp[-2].v.string); while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); YYERROR; } } if (symset((yyvsp[-2].v.string), (yyvsp[0].v.string), 0) == -1) fatal("cannot store variable"); free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1433 "parse.c" break; case 10: /* numberstring: NUMBER */ #line 165 "parse.y" { if (asprintf(&(yyval.v.string), "%lld", (long long)(yyvsp[0].v.number)) == -1) { yyerror("asprintf: %s", strerror(errno)); YYERROR; } } #line 1444 "parse.c" break; case 11: /* boolean: STRING */ #line 174 "parse.y" { if (strcasecmp((yyvsp[0].v.string), "1") == 0 || strcasecmp((yyvsp[0].v.string), "on") == 0) (yyval.v.number) = 1; else if (strcasecmp((yyvsp[0].v.string), "0") == 0 || strcasecmp((yyvsp[0].v.string), "off") == 0) (yyval.v.number) = 0; else { yyerror("invalid boolean value '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1463 "parse.c" break; case 12: /* boolean: ON */ #line 188 "parse.y" { (yyval.v.number) = 1; } #line 1469 "parse.c" break; case 13: /* boolean: NUMBER */ #line 189 "parse.y" { if ((yyvsp[0].v.number) != 0 && (yyvsp[0].v.number) != 1) { yyerror("invalid boolean value '%lld'", (yyvsp[0].v.number)); YYERROR; } (yyval.v.number) = (yyvsp[0].v.number); } #line 1481 "parse.c" break; case 14: /* listen_addr: '*' */ #line 198 "parse.y" { (yyval.v.string) = NULL; } #line 1487 "parse.c" break; case 16: /* main: PREFORK NUMBER */ #line 202 "parse.y" { if ((yyvsp[0].v.number) <= 0 || (yyvsp[0].v.number) > PROC_MAX_INSTANCES) { yyerror("prefork is %s: %lld", (yyvsp[0].v.number) <= 0 ? "too small" : "too large", (yyvsp[0].v.number)); YYERROR; } gotwebd->prefork = (yyvsp[0].v.number); } #line 1500 "parse.c" break; case 17: /* main: CHROOT STRING */ #line 210 "parse.y" { if (*(yyvsp[0].v.string) == '\0') { yyerror("chroot path can't be an empty" " string"); free((yyvsp[0].v.string)); YYERROR; } n = strlcpy(gotwebd->httpd_chroot, (yyvsp[0].v.string), sizeof(gotwebd->httpd_chroot)); if (n >= sizeof(gotwebd->httpd_chroot)) { yyerror("chroot path too long: %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } if (gotwebd->httpd_chroot[0] != '/') { yyerror("chroot path must be an absolute path: " "bad path %s", gotwebd->httpd_chroot); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1528 "parse.c" break; case 18: /* main: LISTEN ON listen_addr PORT STRING */ #line 233 "parse.y" { if (get_addrs((yyvsp[-2].v.string), (yyvsp[0].v.string)) == -1) { yyerror("could not get addrs"); YYERROR; } free((yyvsp[-2].v.string)); free((yyvsp[0].v.string)); } #line 1541 "parse.c" break; case 19: /* main: LISTEN ON listen_addr PORT NUMBER */ #line 241 "parse.y" { char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)(yyvsp[0].v.number)); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)(yyvsp[0].v.number)); if (get_addrs((yyvsp[-2].v.string), portno) == -1) { yyerror("could not get addrs"); YYERROR; } free((yyvsp[-2].v.string)); } #line 1562 "parse.c" break; case 20: /* main: LISTEN ON SOCKET STRING */ #line 257 "parse.y" { struct address *h; h = get_unix_addr((yyvsp[0].v.string)); if (h == NULL) { yyerror("can't listen on %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } add_addr(h); free((yyvsp[0].v.string)); } #line 1579 "parse.c" break; case 21: /* main: USER STRING */ #line 269 "parse.y" { if (gotwebd->user != NULL) yyerror("user already specified"); free(gotwebd->user); gotwebd->user = (yyvsp[0].v.string); } #line 1590 "parse.c" break; case 22: /* main: WWW USER STRING */ #line 275 "parse.y" { if (gotwebd->www_user != NULL) yyerror("www user already specified"); free(gotwebd->www_user); gotwebd->www_user = (yyvsp[0].v.string); } #line 1601 "parse.c" break; case 23: /* main: DISABLE AUTHENTICATION */ #line 281 "parse.y" { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_DISABLED; } #line 1614 "parse.c" break; case 24: /* main: ENABLE AUTHENTICATION */ #line 289 "parse.y" { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_SECURE; } #line 1627 "parse.c" break; case 25: /* main: ENABLE AUTHENTICATION INSECURE */ #line 297 "parse.y" { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_INSECURE; } #line 1640 "parse.c" break; case 26: /* main: PERMIT numberstring */ #line 305 "parse.y" { conf_new_access_rule(&gotwebd->access_rules, GOTWEBD_ACCESS_PERMITTED, (yyvsp[0].v.string)); } #line 1649 "parse.c" break; case 27: /* main: DENY numberstring */ #line 309 "parse.y" { conf_new_access_rule(&gotwebd->access_rules, GOTWEBD_ACCESS_DENIED, (yyvsp[0].v.string)); } #line 1658 "parse.c" break; case 28: /* main: GOTWEBD_LOGIN SOCKET STRING */ #line 313 "parse.y" { struct address *h; h = get_unix_addr((yyvsp[0].v.string)); if (h == NULL) { yyerror("can't listen on %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } if (gotwebd->login_sock != NULL) free(gotwebd->login_sock); gotwebd->login_sock = sockets_conf_new_socket(-1, h); free((yyvsp[0].v.string)); } #line 1676 "parse.c" break; case 29: /* server: SERVER STRING */ #line 328 "parse.y" { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, (yyvsp[0].v.string)) == 0) { yyerror("server name exists '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } new_srv = conf_new_server((yyvsp[0].v.string)); log_debug("adding server %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1696 "parse.c" break; case 30: /* $@1: %empty */ #line 343 "parse.y" { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, (yyvsp[0].v.string)) == 0) { yyerror("server name exists '%s'", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); YYERROR; } } new_srv = conf_new_server((yyvsp[0].v.string)); log_debug("adding server %s", (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 1716 "parse.c" break; case 31: /* server: SERVER STRING $@1 '{' optnl serveropts2 '}' */ #line 357 "parse.y" { } #line 1723 "parse.c" break; case 32: /* serveropts1: REPOS_PATH STRING */ #line 361 "parse.y" { n = strlcpy(new_srv->repos_path, (yyvsp[0].v.string), sizeof(new_srv->repos_path)); if (n >= sizeof(new_srv->repos_path)) { yyerror("%s: repos_path truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1738 "parse.c" break; case 33: /* serveropts1: SITE_NAME STRING */ #line 371 "parse.y" { n = strlcpy(new_srv->site_name, (yyvsp[0].v.string), sizeof(new_srv->site_name)); if (n >= sizeof(new_srv->site_name)) { yyerror("%s: site_name truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1753 "parse.c" break; case 34: /* serveropts1: SITE_OWNER STRING */ #line 381 "parse.y" { n = strlcpy(new_srv->site_owner, (yyvsp[0].v.string), sizeof(new_srv->site_owner)); if (n >= sizeof(new_srv->site_owner)) { yyerror("%s: site_owner truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1768 "parse.c" break; case 35: /* serveropts1: SITE_LINK STRING */ #line 391 "parse.y" { n = strlcpy(new_srv->site_link, (yyvsp[0].v.string), sizeof(new_srv->site_link)); if (n >= sizeof(new_srv->site_link)) { yyerror("%s: site_link truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1783 "parse.c" break; case 36: /* serveropts1: LOGO STRING */ #line 401 "parse.y" { n = strlcpy(new_srv->logo, (yyvsp[0].v.string), sizeof(new_srv->logo)); if (n >= sizeof(new_srv->logo)) { yyerror("%s: logo truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1797 "parse.c" break; case 37: /* serveropts1: LOGO_URL STRING */ #line 410 "parse.y" { n = strlcpy(new_srv->logo_url, (yyvsp[0].v.string), sizeof(new_srv->logo_url)); if (n >= sizeof(new_srv->logo_url)) { yyerror("%s: logo_url truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1812 "parse.c" break; case 38: /* serveropts1: CUSTOM_CSS STRING */ #line 420 "parse.y" { n = strlcpy(new_srv->custom_css, (yyvsp[0].v.string), sizeof(new_srv->custom_css)); if (n >= sizeof(new_srv->custom_css)) { yyerror("%s: custom_css truncated", __func__); free((yyvsp[0].v.string)); YYERROR; } free((yyvsp[0].v.string)); } #line 1827 "parse.c" break; case 39: /* serveropts1: SHOW_SITE_OWNER boolean */ #line 430 "parse.y" { new_srv->show_site_owner = (yyvsp[0].v.number); } #line 1835 "parse.c" break; case 40: /* serveropts1: SHOW_REPO_OWNER boolean */ #line 433 "parse.y" { new_srv->show_repo_owner = (yyvsp[0].v.number); } #line 1843 "parse.c" break; case 41: /* serveropts1: SHOW_REPO_AGE boolean */ #line 436 "parse.y" { new_srv->show_repo_age = (yyvsp[0].v.number); } #line 1851 "parse.c" break; case 42: /* serveropts1: SHOW_REPO_DESCRIPTION boolean */ #line 439 "parse.y" { new_srv->show_repo_description = (yyvsp[0].v.number); } #line 1859 "parse.c" break; case 43: /* serveropts1: SHOW_REPO_CLONEURL boolean */ #line 442 "parse.y" { new_srv->show_repo_cloneurl = (yyvsp[0].v.number); } #line 1867 "parse.c" break; case 44: /* serveropts1: RESPECT_EXPORTOK boolean */ #line 445 "parse.y" { new_srv->respect_exportok = (yyvsp[0].v.number); } #line 1875 "parse.c" break; case 45: /* serveropts1: MAX_REPOS_DISPLAY NUMBER */ #line 448 "parse.y" { if ((yyvsp[0].v.number) < 0) { yyerror("max_repos_display is too small: %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->max_repos_display = (yyvsp[0].v.number); } #line 1888 "parse.c" break; case 46: /* serveropts1: MAX_COMMITS_DISPLAY NUMBER */ #line 456 "parse.y" { if ((yyvsp[0].v.number) <= 1) { yyerror("max_commits_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->max_commits_display = (yyvsp[0].v.number); } #line 1901 "parse.c" break; case 47: /* serveropts1: SUMMARY_COMMITS_DISPLAY NUMBER */ #line 464 "parse.y" { if ((yyvsp[0].v.number) < 1) { yyerror("summary_commits_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->summary_commits_display = (yyvsp[0].v.number); } #line 1914 "parse.c" break; case 48: /* serveropts1: SUMMARY_TAGS_DISPLAY NUMBER */ #line 472 "parse.y" { if ((yyvsp[0].v.number) < 1) { yyerror("summary_tags_display is too small:" " %lld", (yyvsp[0].v.number)); YYERROR; } new_srv->summary_tags_display = (yyvsp[0].v.number); } #line 1927 "parse.c" break; case 49: /* serveropts1: DISABLE AUTHENTICATION */ #line 480 "parse.y" { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_DISABLED; } #line 1941 "parse.c" break; case 50: /* serveropts1: ENABLE AUTHENTICATION */ #line 489 "parse.y" { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_SECURE; } #line 1955 "parse.c" break; case 51: /* serveropts1: ENABLE AUTHENTICATION INSECURE */ #line 498 "parse.y" { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_INSECURE; } #line 1969 "parse.c" break; case 52: /* serveropts1: PERMIT numberstring */ #line 507 "parse.y" { conf_new_access_rule(&new_srv->access_rules, GOTWEBD_ACCESS_PERMITTED, (yyvsp[0].v.string)); } #line 1978 "parse.c" break; case 53: /* serveropts1: DENY numberstring */ #line 511 "parse.y" { conf_new_access_rule(&new_srv->access_rules, GOTWEBD_ACCESS_DENIED, (yyvsp[0].v.string)); } #line 1987 "parse.c" break; case 57: /* $@2: %empty */ #line 522 "parse.y" { struct gotwebd_repo *repo; TAILQ_FOREACH(repo, &new_srv->repos, entry) { if (strcmp(repo->name, (yyvsp[0].v.string)) == 0) { yyerror("duplicate repository " "'%s' in server '%s'", (yyvsp[0].v.string), new_srv->name); free((yyvsp[0].v.string)); YYERROR; } } new_repo = conf_new_repo(new_srv, (yyvsp[0].v.string)); free((yyvsp[0].v.string)); } #line 2008 "parse.c" break; case 58: /* repository: REPOSITORY STRING $@2 '{' optnl repoopts2 '}' */ #line 537 "parse.y" { } #line 2015 "parse.c" break; case 61: /* repoopts1: DISABLE AUTHENTICATION */ #line 545 "parse.y" { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_DISABLED; } #line 2029 "parse.c" break; case 62: /* repoopts1: ENABLE AUTHENTICATION */ #line 554 "parse.y" { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_SECURE; } #line 2043 "parse.c" break; case 63: /* repoopts1: ENABLE AUTHENTICATION INSECURE */ #line 563 "parse.y" { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_INSECURE; } #line 2057 "parse.c" break; case 64: /* repoopts1: PERMIT numberstring */ #line 572 "parse.y" { conf_new_access_rule(&new_repo->access_rules, GOTWEBD_ACCESS_PERMITTED, (yyvsp[0].v.string)); } #line 2066 "parse.c" break; case 65: /* repoopts1: DENY numberstring */ #line 576 "parse.y" { conf_new_access_rule(&new_repo->access_rules, GOTWEBD_ACCESS_DENIED, (yyvsp[0].v.string)); } #line 2075 "parse.c" break; #line 2079 "parse.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 589 "parse.y" struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "authentication", AUTHENTICATION }, { "chroot", CHROOT }, { "custom_css", CUSTOM_CSS }, { "deny", DENY }, { "disable", DISABLE }, { "enable", ENABLE }, { "insecure", INSECURE }, { "listen", LISTEN }, { "login", GOTWEBD_LOGIN }, { "logo", LOGO }, { "logo_url", LOGO_URL }, { "max_commits_display", MAX_COMMITS_DISPLAY }, { "max_repos_display", MAX_REPOS_DISPLAY }, { "on", ON }, { "permit", PERMIT }, { "port", PORT }, { "prefork", PREFORK }, { "repos_path", REPOS_PATH }, { "repository", REPOSITORY }, { "respect_exportok", RESPECT_EXPORTOK }, { "server", SERVER }, { "show_repo_age", SHOW_REPO_AGE }, { "show_repo_cloneurl", SHOW_REPO_CLONEURL }, { "show_repo_description", SHOW_REPO_DESCRIPTION }, { "show_repo_owner", SHOW_REPO_OWNER }, { "show_site_owner", SHOW_SITE_OWNER }, { "site_link", SITE_LINK }, { "site_name", SITE_NAME }, { "site_owner", SITE_OWNER }, { "socket", SOCKET }, { "summary_commits_display", SUMMARY_COMMITS_DISPLAY }, { "summary_tags_display", SUMMARY_TAGS_DISPLAY }, { "user", USER }, { "www", WWW }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { /* no warning, we don't require a conf file */ free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } static void add_default_server(void) { new_srv = conf_new_server(D_SITENAME); log_debug("%s: adding default server %s", __func__, D_SITENAME); } int parse_config(const char *filename, struct gotwebd *env) { struct sym *sym, *next; struct server *srv; struct gotwebd_repo *repo; if (config_init(env) == -1) fatalx("failed to initialize configuration"); gotwebd = env; file = newfile(filename, 0); if (file != NULL) { /* we don't require a config file */ yyparse(); errors = file->errors; closefile(file); } /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotwebd->gotwebd_verbose > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } /* just add default server if no config specified */ if (TAILQ_EMPTY(&gotwebd->servers)) add_default_server(); /* add the implicit listen on socket */ if (TAILQ_EMPTY(&gotwebd->addresses)) { char path[_POSIX_PATH_MAX]; struct address *h; if (strlcpy(path, gotwebd->httpd_chroot, sizeof(path)) >= sizeof(path)) { yyerror("chroot path too long: %s", gotwebd->httpd_chroot); } if (strlcat(path, D_UNIX_SOCKET, sizeof(path)) >= sizeof(path)) { yyerror("chroot path too long: %s", gotwebd->httpd_chroot); } h = get_unix_addr(path); if (h == NULL) yyerror("can't listen on %s", path); else add_addr(h); } if (errors) return (-1); /* setup our listening sockets */ sockets_parse_sockets(env); /* Add implicit login socket */ if (gotwebd->login_sock == NULL) { struct address *h; h = get_unix_addr(GOTWEBD_LOGIN_SOCKET); if (h == NULL) { fprintf(stderr, "cannot listen on %s", GOTWEBD_LOGIN_SOCKET); return (-1); } gotwebd->login_sock = sockets_conf_new_socket(-1, h); } /* Enable authentication if not explicitly configured. */ switch (env->auth_config) { case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: case GOTWEBD_AUTH_DISABLED: break; default: env->auth_config = GOTWEBD_AUTH_SECURE; break; } /* Inherit implicit authentication config from parent scope. */ TAILQ_FOREACH(srv, &env->servers, entry) { if (srv->auth_config == 0) srv->auth_config = env->auth_config; TAILQ_FOREACH(repo, &srv->repos, entry) { if (repo->auth_config == 0) repo->auth_config = srv->auth_config; } } return (0); } struct server * conf_new_server(const char *name) { struct server *srv = NULL; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); n = strlcpy(srv->name, name, sizeof(srv->name)); if (n >= sizeof(srv->name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->repos_path, gotwebd->httpd_chroot, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcpy", __func__); n = strlcat(srv->repos_path, D_GOTPATH, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcat", __func__); n = strlcpy(srv->site_name, D_SITENAME, sizeof(srv->site_name)); if (n >= sizeof(srv->site_name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_owner, D_SITEOWNER, sizeof(srv->site_owner)); if (n >= sizeof(srv->site_owner)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_link, D_SITELINK, sizeof(srv->site_link)); if (n >= sizeof(srv->site_link)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo, D_GOTLOGO, sizeof(srv->logo)); if (n >= sizeof(srv->logo)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo_url, D_GOTURL, sizeof(srv->logo_url)); if (n >= sizeof(srv->logo_url)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->custom_css, D_GOTWEBCSS, sizeof(srv->custom_css)); if (n >= sizeof(srv->custom_css)) fatalx("%s: strlcpy", __func__); srv->show_site_owner = D_SHOWSOWNER; srv->show_repo_owner = D_SHOWROWNER; srv->show_repo_age = D_SHOWAGE; srv->show_repo_description = D_SHOWDESC; srv->show_repo_cloneurl = D_SHOWURL; srv->respect_exportok = D_RESPECTEXPORTOK; srv->max_repos_display = D_MAXREPODISP; srv->max_commits_display = D_MAXCOMMITDISP; srv->summary_commits_display = D_MAXSLCOMMDISP; srv->summary_tags_display = D_MAXSLTAGDISP; STAILQ_INIT(&srv->access_rules); TAILQ_INIT(&srv->repos); TAILQ_INSERT_TAIL(&gotwebd->servers, srv, entry); return srv; }; int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; val = strrchr(s, '='); if (val == NULL) return (-1); sym = strndup(s, val - s); if (sym == NULL) fatal("%s: strndup", __func__); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } int get_addrs(const char *hostname, const char *servname) { struct addrinfo hints, *res0, *res; int error; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct address *h; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { log_warnx("%s: could not parse \"%s:%s\": %s", __func__, hostname, servname, gai_strerror(error)); return (-1); } for (res = res0; res; res = res->ai_next) { if ((h = calloc(1, sizeof(*h))) == NULL) fatal(__func__); if (hostname == NULL) { strlcpy(h->ifname, "*", sizeof(h->ifname)); } else { if (strlcpy(h->ifname, hostname, sizeof(h->ifname)) >= sizeof(h->ifname)) { log_warnx("%s: address truncated: %s", __func__, hostname); freeaddrinfo(res0); free(h); return (-1); } } h->ai_family = res->ai_family; h->ai_socktype = res->ai_socktype; h->ai_protocol = res->ai_protocol; memcpy(&h->ss, res->ai_addr, res->ai_addrlen); h->slen = res->ai_addrlen; switch (res->ai_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; h->port = ntohs(sin->sin_port); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)res->ai_addr; h->port = ntohs(sin6->sin6_port); break; default: fatalx("unknown address family %d", res->ai_family); } add_addr(h); } freeaddrinfo(res0); return (0); } struct address * get_unix_addr(const char *path) { struct address *h; struct sockaddr_un *sun; if ((h = calloc(1, sizeof(*h))) == NULL) fatal("%s: calloc", __func__); h->ai_family = AF_UNIX; h->ai_socktype = SOCK_STREAM; h->ai_protocol = PF_UNSPEC; h->slen = sizeof(*sun); sun = (struct sockaddr_un *)&h->ss; sun->sun_family = AF_UNIX; if (strlcpy(sun->sun_path, path, sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) { log_warnx("socket path too long: %s", sun->sun_path); return NULL; } return h; } int addr_dup_check(struct addresslist *al, struct address *h) { struct address *a; TAILQ_FOREACH(a, al, entry) { if (a->ai_family != h->ai_family || a->ai_socktype != h->ai_socktype || a->ai_protocol != h->ai_protocol || a->slen != h->slen || memcmp(&a->ss, &h->ss, a->slen) != 0) continue; return -1; } return 0; } void add_addr(struct address *h) { if (addr_dup_check(&gotwebd->addresses, h) == 0) { TAILQ_INSERT_TAIL(&gotwebd->addresses, h, entry); return; } free(h); } struct gotwebd_repo * gotwebd_new_repo(const char *name) { struct gotwebd_repo *repo; repo = calloc(1, sizeof(*repo)); if (repo == NULL) return NULL; STAILQ_INIT(&repo->access_rules); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) { free(repo); errno = ENOSPC; return NULL; } return repo; } static struct gotwebd_repo * conf_new_repo(struct server *server, const char *name) { struct gotwebd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '/') != NULL) fatalx("repository names must not contain slashes: %s", name); if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); repo = gotwebd_new_repo(name); if (repo == NULL) fatal("gotwebd_new_repo"); TAILQ_INSERT_TAIL(&server->repos, repo, entry); return repo; }; static void conf_new_access_rule(struct gotwebd_access_rule_list *rules, enum gotwebd_access access, char *identifier) { struct gotwebd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; if (strlcpy(rule->identifier, identifier, sizeof(rule->identifier)) >= sizeof(rule->identifier)) fatalx("identifier too long (max %zu bytes): %s", sizeof(rule->identifier) - 1, identifier); STAILQ_INSERT_TAIL(rules, rule, entry); } got-portable-0.119/gotwebd/login.c0000664000175000017500000004270115066536113012527 /* * Copyright (c) 2025 Stefan Sperling * Copyright (c) 2025 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" #define LOGIN_SOCKET_BACKLOG 4 struct gotwebd_login_client { int fd; int cmd_done; uid_t euid; struct bufferevent *bev; }; static volatile int client_cnt; static int inflight; static char login_token_secret[32]; /* * The token format is: * * "v1\0"[issued at/64bit][expire/64bit][uid/64bit][host]"\0" * * Padded with additional \0 to a length divisible by 4, and then * followed by the HMAC-SHA256 of it, all encoded in base64. */ /* checks whether the token's signature matches, i.e. if it looks good. */ int login_check_token(uid_t *euid, char **hostname, const char *token, const char *secret, size_t secret_len, const char *purpose) { time_t now; uint64_t issued, expire, uid; uint8_t *data; int len; char hmac[32], exp[32]; unsigned int explen; size_t used = 0; /* * We get called in several processes which should all have * a copy of the same secret. */ if (secret_len != sizeof(login_token_secret)) fatalx("%s token secret length mismatch", purpose); /* xxx check for overflow */ len = (strlen(token) / 4) * 3; data = malloc(len); if (data == NULL) return -1; len = EVP_DecodeBlock(data, token, strlen(token)); if (len == -1) { free(data); return -1; } /* Trim padding. */ while (len > 0 && (len % 4) != 0) len--; if (len < 28 + 32) { /* min length assuming empty hostname */ log_warnx("%s token too short: %d", purpose, len); free(data); return -1; } if (memcmp(data, "v1", 3) != 0) { log_warnx("unknown %s token format version", purpose); free(data); return -1; } used = 3; if (HMAC(EVP_sha256(), secret, secret_len, data, len - 32, exp, &explen) == NULL) { log_warnx("HMAC computation failed\n"); free(data); return -1; } if (explen != 32) { log_warnx("unexpected HMAC length: %u\n", explen); free(data); return -1; } memcpy(hmac, data + len - explen, explen); if (memcmp(hmac, exp, explen) != 0) { log_warnx("HMAC check failed\n"); free(data); return -1; } memcpy(&issued, data + used, sizeof(issued)); used += sizeof(issued); memcpy(&expire, data + used, sizeof(expire)); used += sizeof(expire); memcpy(&uid, data + used, sizeof(uid)); used += sizeof(uid); now = time(NULL); if (expire < now) { log_warnx("uid %llu: %s token has expired\n", uid, purpose); free(data); return -1; } if (euid) *euid = (uid_t)uid; if (hostname) { if (used < len - explen) { *hostname = strndup(data + used, len - explen - used); if (*hostname == NULL) { log_warn("strndup"); free(data); return -1; } } else { *hostname = strdup(""); if (*hostname == NULL) { log_warn("strdup"); free(data); return -1; } } } free(data); return 0; } char * login_gen_token(uint64_t uid, const char *hostname, time_t validity, const char *secret, size_t secret_len, const char *purpose) { BIO *bmem, *b64; BUF_MEM *bufm; char hmac[EVP_MAX_MD_SIZE]; char *enc; FILE *fp; char *tok; time_t now; uint64_t issued, expire; size_t siz, hlen, pad; unsigned int hmaclen; /* openssl... */ /* * We get called in several processes which should all have * a copy of the same secret. */ if (secret_len != sizeof(login_token_secret)) fatalx("%s token secret length mismatch", purpose); now = time(NULL); issued = (uint64_t)now; expire = issued + validity; fp = open_memstream(&tok, &siz); if (fp == NULL) return NULL; /* include NUL */ hlen = strlen(hostname) + 1; if (fwrite("v1", 1, 3, fp) != 3 || fwrite(&issued, 1, 8, fp) != 8 || fwrite(&expire, 1, 8, fp) != 8 || fwrite(&uid, 1, 8, fp) != 8 || fwrite(hostname, 1, hlen, fp) != hlen) { fclose(fp); free(tok); return NULL; } /* Pad hostname with trailing NULs for base64 encoding. */ pad = 0; while (((3 + 8 + 8 + 8 + hlen + pad) % 4) != 0) { if (fwrite("", 1, 1, fp) != 1) { fclose(fp); free(tok); return NULL; } pad++; } if (fclose(fp) == EOF) { free(tok); return NULL; } /* Base64 encoder expects a length divisible by 4. */ if ((siz % 4) != 0) fatalx("generated %s token with bad size %zu", purpose, siz); if (siz > INT_MAX) { /* * can't really happen, isn't it? yet, openssl * sometimes likes to take ints so I'd prefer to * assert. */ free(tok); return NULL; } if (HMAC(EVP_sha256(), secret, secret_len, tok, siz, hmac, &hmaclen) == NULL) { free(tok); return NULL; } bmem = BIO_new(BIO_s_mem()); if (bmem == NULL) { free(tok); return NULL; } b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { BIO_free(bmem); free(tok); return NULL; } BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); b64 = BIO_push(b64, bmem); if (BIO_write(b64, tok, siz) != (int)siz || BIO_write(b64, hmac, hmaclen) != hmaclen || BIO_flush(b64) <= 0) { free(tok); BIO_free_all(b64); return NULL; } BIO_get_mem_ptr(b64, &bufm); enc = strndup(bufm->data, bufm->length); free(tok); BIO_free_all(b64); if (login_check_token(NULL, NULL, enc, secret, secret_len, purpose) == -1) fatalx("generated %s token that won't pass validation", purpose); return enc; } static int login_socket_listen(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid) { int u_fd = -1; mode_t old_umask, mode; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif u_fd = socket(AF_UNIX, sock_flags, 0); if (u_fd == -1) { log_warn("%s: socket", __func__); return -1; } if (unlink(sock->conf.unix_socket_name) == -1) { if (errno != ENOENT) { log_warn("%s: unlink %s", __func__, sock->conf.unix_socket_name); close(u_fd); return -1; } } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; if (bind(u_fd, (struct sockaddr *)&sock->conf.addr.ss, sock->conf.addr.slen) == -1) { log_warn("%s: bind: %s", __func__, sock->conf.unix_socket_name); close(u_fd); (void)umask(old_umask); return -1; } (void)umask(old_umask); if (chmod(sock->conf.unix_socket_name, mode) == -1) { log_warn("%s: chmod", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } if (chown(sock->conf.unix_socket_name, uid, gid) == -1) { log_warn("%s: chown", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name); return -1; } if (listen(u_fd, LOGIN_SOCKET_BACKLOG) == -1) { log_warn("%s: listen", __func__); return -1; } return u_fd; } int login_privinit(struct gotwebd *env, uid_t uid, gid_t gid) { struct socket *sock = env->login_sock; if (sock == NULL) fatalx("no login socket configured"); log_info("initializing login socket %s", sock->conf.unix_socket_name); sock->fd = login_socket_listen(env, sock, uid, gid); if (sock->fd == -1) return -1; return 0; } static void login_shutdown(void) { struct gotwebd *env = gotwebd_env; imsgbuf_clear(&env->iev_parent->ibuf); free(env->iev_parent); if (env->iev_gotsh) { imsgbuf_clear(&env->iev_gotsh->ibuf); free(env->iev_gotsh); } config_free_access_rules(&env->access_rules); while (!TAILQ_EMPTY(&gotwebd_env->sockets)) { struct socket *sock; sock = TAILQ_FIRST(&gotwebd_env->sockets); TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); free(sock); } while (!TAILQ_EMPTY(&gotwebd_env->servers)) { struct server *srv; srv = TAILQ_FIRST(&gotwebd_env->servers); TAILQ_REMOVE(&gotwebd_env->servers, srv, entry); config_free_access_rules(&srv->access_rules); config_free_repos(&srv->repos); free(srv); } free(env); exit(0); } static void login_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: login_shutdown(); break; default: log_warn("unexpected signal %d", sig); break; } } static int accept_reserve(int fd, struct sockaddr *addr, socklen_t *addrlen, int reserve, volatile int *counter) { int ret; if (getdtablecount() + reserve + *counter + 1 >= getdtablesize()) { log_debug("inflight fds exceeded"); errno = EMFILE; return -1; } /* TA: This needs fixing upstream. */ #ifdef __APPLE__ ret = accept(fd, addr, addrlen); #else ret = accept4(fd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif if (ret > -1) { (*counter)++; } return ret; } static void client_err(struct bufferevent *bev, short error, void *d) { struct gotwebd_login_client *client = d; log_debug("closing connection with client fd=%d; error=%d", client->fd, error); bufferevent_free(client->bev); close(client->fd); free(client); inflight--; client_cnt--; } static void client_read(struct bufferevent *bev, void *d) { struct gotwebd_login_client *client = d; struct evbuffer *in = EVBUFFER_INPUT(bev); struct evbuffer *out = EVBUFFER_OUTPUT(bev); char *line, *cmd, *code; size_t linelen; const char *hostname; if (client->cmd_done) { log_warnx("%s: client sent data even though login command " "has already completed", __func__); client_err(bev, EVBUFFER_READ, client); return; } line = evbuffer_readln(in, &linelen, EVBUFFER_EOL_LF); if (line == NULL) { /* * there is no line yet to read. however, error if we * have too much data buffered without a newline * character. */ if (EVBUFFER_LENGTH(in) > LINE_MAX) client_err(bev, EVBUFFER_READ, client); return; } cmd = line; if (strncmp(cmd, "login", 5) == 0) { cmd += 5; cmd += strspn(cmd, " \t"); hostname = cmd; if (hostname[0] == '\0') { struct server *srv; /* * In a multi-server setup we do not want to leak our * first server's hostname to random people. But if * we only have a single server, we'll expose it. */ srv = TAILQ_FIRST(&gotwebd_env->servers); if (TAILQ_NEXT(srv, entry) == NULL) hostname = srv->name; } code = login_gen_token(client->euid, hostname, 5 * 60 /* 5 minutes */, login_token_secret, sizeof(login_token_secret), "login"); if (code == NULL) { log_warn("%s: login_gen_token failed", __func__); client_err(bev, EVBUFFER_READ, client); return; } if (evbuffer_add_printf(out, "ok https://%s/?login=%s\n", hostname, code) == -1) { log_warnx("%s: evbuffer_add_printf failed", __func__); client_err(bev, EVBUFFER_READ, client); free(code); return; } free(code); client->cmd_done = 1; bufferevent_enable(client->bev, EV_READ|EV_WRITE); return; } if (evbuffer_add_printf(out, "err unknown command\n") == -1) { log_warnx("%s: evbuffer_add_printf failed", __func__); client_err(bev, EVBUFFER_READ, client); return; } client->cmd_done = 1; return; } static void client_write(struct bufferevent *bev, void *d) { struct gotwebd_login_client *client = d; struct evbuffer *out = EVBUFFER_OUTPUT(bev); if (client->cmd_done && EVBUFFER_LENGTH(out) == 0) { /* reply sent */ client_err(bev, EVBUFFER_WRITE, client); return; } } static void login_accept(int fd, short event, void *arg) { struct imsgev *iev = arg; struct gotwebd *env = gotwebd_env; struct sockaddr_storage ss; struct timeval backoff; socklen_t len; int s = -1; struct gotwebd_login_client *client = NULL; uid_t euid; gid_t egid; backoff.tv_sec = 1; backoff.tv_usec = 0; if (event_add(&iev->ev, NULL) == -1) { log_warn("event_add"); return; } if (event & EV_TIMEOUT) return; len = sizeof(ss); /* Other backoff conditions apart from EMFILE/ENFILE? */ s = accept_reserve(fd, (struct sockaddr *)&ss, &len, FD_RESERVE, &inflight); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: return; case EMFILE: case ENFILE: event_del(&iev->ev); evtimer_add(&env->login_pause_ev, &backoff); return; default: log_warn("accept"); return; } } if (client_cnt >= GOTWEBD_MAXCLIENTS) goto err; if (getpeereid(s, &euid, &egid) == -1) { log_warn("getpeerid"); goto err; } client = calloc(1, sizeof(*client)); if (client == NULL) { log_warn("%s: calloc", __func__); goto err; } client->fd = s; client->euid = euid; s = -1; client->bev = bufferevent_new(client->fd, client_read, client_write, client_err, client); if (client->bev == NULL) { log_warn("%s: bufferevent_new failed", __func__); goto err; } bufferevent_enable(client->bev, EV_READ|EV_WRITE); /* * undocumented; but these are seconds. 10s should be plenty * for both receiving a request and sending the reply. */ bufferevent_settimeout(client->bev, 10, 10); log_debug("%s: new client connected on fd %d uid %d gid %d", __func__, client->fd, euid, egid); client_cnt++; return; err: inflight--; if (client) { if (client->bev != NULL) bufferevent_free(client->bev); close(client->fd); free(client); } if (s != -1) close(s); } static void get_login_sock(struct gotwebd *env, struct imsg *imsg) { const struct got_error *err; struct imsgev *iev; int fd; if (env->iev_gotsh != NULL) { err = got_error(GOT_ERR_PRIVSEP_MSG); fatalx("%s", err->msg); } if (IMSG_DATA_SIZE(imsg) != 0) { err = got_error(GOT_ERR_PRIVSEP_LEN); fatalx("%s", err->msg); } fd = imsg_get_fd(imsg); if (fd == -1) { err = got_error(GOT_ERR_PRIVSEP_NO_FD); fatalx("%s", err->msg); } iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); iev->handler = login_accept; iev->data = iev; event_set(&iev->ev, fd, EV_READ, login_accept, iev); imsg_event_add(iev); env->iev_gotsh = iev; } static void login_launch(struct gotwebd *env) { #ifndef PROFILE if (pledge("stdio unix", NULL) == -1) fatal("pledge"); #endif event_add(&env->iev_gotsh->ev, NULL); } static void login_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_SRV: config_getserver(env, &imsg); break; case GOTWEBD_IMSG_CFG_SOCK: get_login_sock(env, &imsg); break; case GOTWEBD_IMSG_CTL_START: login_launch(env); break; case GOTWEBD_IMSG_LOGIN_SECRET: if (imsg_get_data(&imsg, login_token_secret, sizeof(login_token_secret)) == -1) fatalx("invalid LOGIN_SECRET msg"); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void accept_paused(int fd, short event, void *arg) { struct gotwebd *env = gotwebd_env; event_add(&env->iev_gotsh->ev, NULL); } void gotwebd_login(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; struct event_base *evb; evb = event_init(); if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL) fatal("malloc"); if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&env->iev_parent->ibuf); env->iev_parent->handler = login_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, login_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); evtimer_set(&env->login_pause_ev, accept_paused, NULL); signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, login_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, login_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, login_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, login_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, login_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio recvfd unix", NULL) == -1) fatal("pledge"); #endif event_dispatch(); event_base_free(evb); login_shutdown(); } got-portable-0.119/gotwebd/pages.tmpl0000664000175000017500000010313115066536113013243 {! /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" enum gotweb_ref_tm { TM_DIFF, TM_LONG, }; static int breadcumbs(struct template *); static int datetime(struct template *, time_t, int); static int gotweb_render_blob_line(struct template *, const char *, size_t); static int gotweb_render_tree_item(struct template *, struct got_tree_entry *); static int blame_line(struct template *, const char *, struct blame_line *, int, int); static inline int gotweb_render_more(struct template *, int); static inline int tree_listing(struct template *); static inline int diff_line(struct template *, char *); static inline int tag_item(struct template *, struct repo_tag *); static inline int branch(struct template *, struct got_reflist_entry *); static inline int rss_tag_item(struct template *, struct repo_tag *); static inline int rss_author(struct template *, char *); static inline char * nextsep(char *s, char **t) { char *q; while (*s == '/') s++; *t = s; if (*s == '\0') return NULL; q = strchr(s, '/'); if (q == NULL) q = strchr(s, '\0'); return q; } !} {{ define datetime(struct template *tp, time_t t, int fmt) }} {! struct tm tm; char rfc3339[64]; char datebuf[64]; if (gmtime_r(&t, &tm) == NULL) return -1; if (strftime(rfc3339, sizeof(rfc3339), "%FT%TZ", &tm) == 0) return -1; if (fmt != TM_DIFF && asctime_r(&tm, datebuf) == NULL) return -1; !} {{ end }} {{ define breadcumbs(struct template *tp) }} {! struct request *c = tp->tp_arg; const struct querystring *qs = c->t->qs; struct gotweb_url url; const char *folder = qs->folder; const char *action = "tree"; char *t, *s = NULL, *dir = NULL; char ch; memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = TREE; url.path = qs->path[0] ? qs->path : NULL; url.commit = qs->commit[0] ? qs->commit : NULL; if (qs->action != TREE && qs->action != BLOB) { action = gotweb_action_name(qs->action); url.action = qs->action; } if (*folder != '\0') { while (*folder == '/') folder++; dir = strdup(folder); if (dir == NULL) return (-1); s = dir; } !} {{ " / " }} {{ action }} {{ " / " }} {{ if dir }} {{ while (s = nextsep(s, &t)) != NULL }} {! ch = *s; *s = '\0'; url.folder = dir; !} {{ t }} {{ " / " }} {! *s = ch; !} {{ end }} {{ end }} {{ if qs->file[0] }} {{ qs->file }} {{ end}} {{ finally }} {! free(dir); !} {{ end }} {{ define gotweb_render_page(struct template *tp, int (*body)(struct template *)) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; const struct querystring *qs = c->t->qs; struct gotweb_url u_path; const char *prfx = c->fcgi_params.document_uri; const char *css = srv->custom_css; memset(&u_path, 0, sizeof(u_path)); u_path.index_page = -1; u_path.action = SUMMARY; !} {{ srv->site_name }}
{{ render body(tp) }}

{{ if srv->show_site_owner }} {{ srv->site_owner }} {{ end }}

{{ end }} {{ define gotweb_render_error(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; !}
{{ if t->error }} {{ t->error->msg }} {{ else }} See daemon logs for details {{ end }}
{{ end }} {{ define gotweb_render_repo_table_hdr(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; !}
Project
{{ if srv->show_repo_description }}
Description
{{ end }} {{ if srv->show_repo_owner }}
Owner
{{ end }} {{ if srv->show_repo_age }}
Last Change
{{ end }}
{{ end }} {{ define gotweb_render_repo_fragment(struct template *tp, struct repo_dir *repo_dir) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }, briefs = { .action = BRIEFS, .index_page = -1, .path = repo_dir->name, }, commits = { .action = COMMITS, .index_page = -1, .path = repo_dir->name, }, tags = { .action = TAGS, .index_page = -1, .path = repo_dir->name, }, tree = { .action = TREE, .index_page = -1, .path = repo_dir->name, }, rss = { .action = RSS, .index_page = -1, .path = repo_dir->name, }; !}
{{ if srv->show_repo_description }}
{{ repo_dir->description }}
{{ end }} {{ if srv->show_repo_owner }}
{{ repo_dir->owner }}
{{ end }} {{ if srv->show_repo_age }}
{{ render datetime(tp, repo_dir->age, TM_DIFF) }}
{{ end }}
{{ end }} {{ define gotweb_render_briefs(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = c->t->qs; struct repo_commit *rc; struct repo_dir *repo_dir = t->repo_dir; struct gotweb_url diff_url, patch_url, tree_url; char *tmp, *body; diff_url = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; patch_url = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; tree_url = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; !}

Commit Briefs

{{ tailq-foreach rc &t->repo_commits entry }} {! diff_url.commit = rc->commit_id; patch_url.commit = rc->commit_id; tree_url.commit = rc->commit_id; tmp = strchr(rc->committer, '<'); if (tmp) *tmp = '\0'; body = strchr(rc->commit_msg, '\n'); if (body) { *body++ = '\0'; while (*body == '\n') body++; } !}

{{ render datetime(tp, rc->committer_time, TM_DIFF) }} {{" "}} {{ printf "%.10s", rc->commit_id }} {{" "}} {{ rc->committer }}

{{ if body && *body != '\0' }}
{{ rc->commit_msg }} {{ if rc->refs_str }} {{ " " }} ({{ rc->refs_str }}) {{ end }} {{ " " }} {{ "\n" }}

{{ body }}

{{ else }}

{{ rc->commit_msg }} {{ if rc->refs_str }} {{ " " }} ({{ rc->refs_str }}) {{ end }}

{{ end }}

{{ end }} {{ render gotweb_render_more(tp, BRIEFS) }}
{{ end }} {{ define gotweb_render_more(struct template *tp, int action) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct gotweb_url more = { .action = action, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, .commit = t->more_id, .headref = qs->headref, .folder = qs->folder[0] ? qs->folder : NULL, .file = qs->file[0] ? qs->file : NULL, }; if (action == TAGS) more.commit = t->tags_more_id; !} {{ if more.commit }} {{ end }} {{ end }} {{ define gotweb_render_navs(struct template *tp) }} {! struct request *c = tp->tp_arg; struct gotweb_url prev, next; int have_prev, have_next; gotweb_index_navs(c, &prev, &have_prev, &next, &have_next); !}
{{ end }} {{ define gotweb_render_commits(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_commit *rc; struct gotweb_url diff, patch, tree; diff = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, }; patch = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, }; tree = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, }; !}

Commits

{{ tailq-foreach rc &t->repo_commits entry }} {! diff.commit = rc->commit_id; patch.commit = rc->commit_id; tree.commit = rc->commit_id; !}
{{ "\n" }} {{ rc->commit_msg }}

{{ end }} {{ render gotweb_render_more(tp, COMMITS) }}
{{ end }} {{ define gotweb_render_blob(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct got_blob_object *blob = t->blob; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blame_url, raw_url; memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path[0] ? qs->path : NULL, briefs_url.commit = qs->commit[0] ? qs->commit : NULL, briefs_url.folder = qs->folder[0] ? qs->folder : NULL, briefs_url.file = qs->file[0] ? qs->file : NULL, memcpy(&blame_url, &briefs_url, sizeof(blame_url)); blame_url.action = BLAME; memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; !}

Blob


      {{ render got_output_blob_by_lines(tp, blob, gotweb_render_blob_line) }}
    
{{ end }} {{ define gotweb_render_blob_line(struct template *tp, const char *line, size_t no) }} {! char lineno[16]; int r; r = snprintf(lineno, sizeof(lineno), "%zu", no); if (r < 0 || (size_t)r >= sizeof(lineno)) return -1; !}
{{ lineno }}{{" "}} {{ line }}
{{ end }} {{ define tree_listing(struct template *tp) }} {! const struct got_error *error; struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = c->t->qs; struct gotweb_url url; char *readme = NULL; int binary; const uint8_t *buf; size_t len; !} {{ render got_output_repo_tree(c, &readme, gotweb_render_tree_item) }}
{{ if readme }} {! error = got_open_blob_for_output(&t->blob, &t->fd, &binary, c, qs->folder[0] ? qs->folder : NULL, readme, qs->commit[0] ? qs->commit : NULL); if (error) { free(readme); return (-1); } memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = BLOB; url.path = t->qs->path[0] ? t->qs->path : NULL; url.file = readme; url.folder = t->qs->folder[0] ? t->qs->folder : ""; url.commit = t->qs->commit[0] ? t->qs->commit : NULL; !} {{ if !binary }}

{{ readme }}

        {!
		for (;;) {
			error = got_object_blob_read_block(&len, t->blob);
			if (error) {
				free(readme);
				return (-1);
			}
			if (len == 0)
				break;
			buf = got_object_blob_get_read_buf(t->blob);
			if (tp_write_htmlescape(tp, buf, len) == -1) {
				free(readme);
				return (-1);
			}
		}
        !}
      
{{ end }} {{ end }} {{ finally }} {! free(readme); !} {{ end }} {{ define gotweb_render_tree(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); !}

Tree


{{ render tree_listing(tp) }}
{{ end }} {{ define gotweb_render_tree_item(struct template *tp, struct got_tree_entry *te) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); const char *modestr = ""; const char *name; const char *folder; char *dir = NULL; mode_t mode; struct gotweb_url url = { .index_page = -1, .commit = rc->commit_id, .path = qs->path[0] ? qs->path : NULL, }; name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); folder = qs->folder[0] ? qs->folder : ""; if (S_ISDIR(mode)) { if (asprintf(&dir, "%s/%s", folder, name) == -1) return (-1); url.action = TREE; url.folder = dir; } else { url.action = BLOB; url.folder = folder; url.file = name; } if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) modestr = "@"; else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; !} {{ if S_ISDIR(mode) }} {{ name }}{{ modestr }} {{ else }} {{ name }}{{ modestr }} {! url.action = COMMITS; !} commits {{ " | " }} {! url.action = BLAME; !} blame {{ end }} {{ finally }} {! free(dir); !} {{ end }} {{ define gotweb_render_tags(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; !}

Tags

{{ if TAILQ_EMPTY(&t->repo_tags) }}
This repository contains no tags
{{ else }} {{ tailq-foreach rt &t->repo_tags entry }} {{ render tag_item(tp, rt) }} {{ end }} {{ render gotweb_render_more(tp, TAGS) }} {{ end }}
{{ end }} {{ define tag_item(struct template *tp, struct repo_tag *rt) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *tag_name = rt->tag_name; char *msg = rt->tag_commit; char *nl; struct gotweb_url url = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; if (msg) { nl = strchr(msg, '\n'); if (nl) *nl = '\0'; } !}
{{ render datetime(tp, rt->tagger_time, TM_DIFF) }}
{{ tag_name }}

{{ end }} {{ define gotweb_render_tag(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; const char *tag_name; rt = TAILQ_LAST(&t->repo_tags, repo_tags_head); tag_name = rt->tag_name; if (strncmp(tag_name, "refs/", 5) == 0) tag_name += 5; !}

Tag

{{ end }} {{ define gotweb_render_diff(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; FILE *fp = t->fp; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); char *line = NULL; size_t linesize = 0; ssize_t linelen; struct gotweb_url patch_url, tree_url = { .action = TREE, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, .commit = rc->commit_id, }; memcpy(&patch_url, &tree_url, sizeof(patch_url)); patch_url.action = PATCH; !}

Commit Diff


    {{ while (linelen = getline(&line, &linesize, fp)) != -1 }}
      {{ render diff_line(tp, line) }}
    {{ end }}
  
{{ finally }} {! free(line); !} {{ end }} {{ define diff_line(struct template *tp, char *line )}} {! const char *color = NULL; char *nl; if (!strncmp(line, "-", 1)) color = "diff_minus"; else if (!strncmp(line, "+", 1)) color = "diff_plus"; else if (!strncmp(line, "@@", 2)) color = "diff_chunk_header"; else if (!strncmp(line, "commit +", 8) || !strncmp(line, "commit -", 8) || !strncmp(line, "blob +", 6) || !strncmp(line, "blob -", 6) || !strncmp(line, "file +", 6) || !strncmp(line, "file -", 6)) color = "diff_meta"; else if (!strncmp(line, "from:", 5) || !strncmp(line, "via:", 4)) color = "diff_author"; else if (!strncmp(line, "date:", 5)) color = "diff_date"; nl = strchr(line, '\n'); if (nl) *nl = '\0'; !} {{ line }}{{"\n"}} {{ end }} {{ define gotweb_render_branches(struct template *tp, struct got_reflist_head *refs) }} {! struct got_reflist_entry *re; !}

Branches

{{ tailq-foreach re refs entry }} {{ if !got_ref_is_symbolic(re->ref) }} {{ render branch(tp, re) }} {{ end }} {{ end }}
{{ end }} {{ define branch(struct template *tp, struct got_reflist_entry *re) }} {! const struct got_error *err; struct request *c = tp->tp_arg; const struct querystring *qs = c->t->qs; const char *refname; time_t age; struct gotweb_url url = { .action = SUMMARY, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, }; refname = got_ref_get_name(re->ref); err = got_get_repo_age(&age, c, refname); if (err) { log_warnx("%s: %s", __func__, err->msg); return -1; } if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; url.headref = refname; !}
{{ render datetime(tp, age, TM_DIFF) }}

{{ end }} {{ define gotweb_render_summary(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct got_reflist_head *refs = &t->refs; !}
{{ render gotweb_render_briefs(tp) }}
{{ render gotweb_render_branches(tp, refs) }}
{{ render gotweb_render_tags(tp) }}

Tree

{{ render tree_listing(tp) }}
{{ end }} {{ define gotweb_render_blame(struct template *tp) }} {! const struct got_error *err; struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blob_url, raw_url; memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path[0] ? qs->path : NULL; briefs_url.commit = qs->commit[0] ? qs->commit : NULL, briefs_url.folder = qs->folder[0] ? qs->folder : NULL, briefs_url.file = qs->file[0] ? qs->file : NULL, memcpy(&blob_url, &briefs_url, sizeof(blob_url)); blob_url.action = BLOB; memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; !}

Blame


    {!
	err = got_output_file_blame(c, &blame_line);
	if (err && err->code != GOT_ERR_CANCELLED)
		log_warnx("%s: got_output_file_blame: %s", __func__,
		    err->msg);
	if (err)
		return (-1);
    !}
  
{{ end }} {{ define blame_line(struct template *tp, const char *line, struct blame_line *bline, int lprec, int lcur) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *committer, *s; struct gotweb_url url = { .action = DIFF, .index_page = -1, .path = repo_dir->name, .commit = bline->id_str, }; s = strchr(bline->committer, '<'); committer = s ? s + 1 : bline->committer; s = strchr(committer, '@'); if (s) *s = '\0'; !}
{{ printf "%*d ", lprec, lcur }} {{ printf "%.8s", bline->id_str }} {{" "}} {{ bline->datebuf }} {{" "}} {{ printf "%.9s", committer }} {{" "}} {{ line }}
{{ end }} {{ define gotweb_render_patch(struct template *tp) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct tm tm; char buf[BUFSIZ], datebuf[64]; size_t r; int w; if (gmtime_r(&rc->committer_time, &tm) == NULL || asctime_r(&tm, datebuf) == NULL) return (-1); datebuf[strcspn(datebuf, "\n")] = '\0'; !} commit {{ rc->commit_id }} {{ "\n" }} from: {{ rc->author | unsafe }} {{ "\n" }} {{ if strcmp(rc->committer, rc->author) != 0 }} via: {{ rc->committer | unsafe }} {{ "\n" }} {{ end }} date: {{ datebuf }} {{ " UTC" }} {{ "\n" }} {{ "\n" }} {{ rc->commit_msg | unsafe }} {{ "\n" }} {! if (template_flush(tp) == -1) return (-1); for (;;) { r = fread(buf, 1, sizeof(buf), t->fp); if (r == 0) break; w = fcgi_write(c, buf, r); if (w == -1) break; } !} {{ end }} {{ define gotweb_render_rss(struct template *tp) }} {! struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_tag *rt; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }; !} Tags of {{ repo_dir->name }} {{ if srv->show_repo_description }} {{ repo_dir->description }} {{ end }} {{ tailq-foreach rt &t->repo_tags entry }} {{ render rss_tag_item(tp, rt) }} {{ end }} {{ end }} {{ define rss_tag_item(struct template *tp, struct repo_tag *rt) }} {! struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct tm tm; char rfc822[128]; int r; char *tag_name = rt->tag_name; struct gotweb_url tag = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; if (gmtime_r(&rt->tagger_time, &tm) == NULL) return -1; r = strftime(rfc822, sizeof(rfc822), "%a, %d %b %Y %H:%M:%S GMT", &tm); if (r == 0) return 0; !} {{ repo_dir->name }} {{" "}} {{ tag_name }} {{ rt->tag_commit }}]]> {{ render rss_author(tp, rt->tagger) }} {{ rt->commit_id }} {{ rfc822 }} {{ end }} {{ define rss_author(struct template *tp, char *author) }} {! char *t, *mail; /* what to do if the author name contains a paren? */ if (strchr(author, '(') != NULL || strchr(author, ')') != NULL) return 0; t = strchr(author, '<'); if (t == NULL) return 0; *t = '\0'; mail = t+1; while (isspace((unsigned char)*--t)) *t = '\0'; t = strchr(mail, '>'); if (t == NULL) return 0; *t = '\0'; !} {{ mail }} {{" "}} ({{ author }}) {{ end }} {{ define gotweb_render_unauthorized(struct template *tp) }}

Wrong or missing authentication code

{{ end }} got-portable-0.119/gotwebd/got_operations.c0000664000175000017500000007173615066536113014465 /* * Copyright (c) 2020-2022 Tracey Emery * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_object.h" #include "got_reference.h" #include "got_repository.h" #include "got_path.h" #include "got_cancel.h" #include "got_diff.h" #include "got_commit_graph.h" #include "got_blame.h" #include "got_privsep.h" #include "got_opentemp.h" #include "gotwebd.h" #include "log.h" static const struct got_error *got_init_repo_commit(struct repo_commit **); static const struct got_error *got_init_repo_tag(struct repo_tag **); static const struct got_error *got_get_repo_commit(struct request *, struct repo_commit *, struct got_commit_object *, struct got_reflist_head *, struct got_object_id *); static const struct got_error *got_gotweb_dupfd(int *, int *); static const struct got_error *got_gotweb_openfile(FILE **, int *); static const struct got_error *got_gotweb_blame_cb(void *, int, int, struct got_commit_object *,struct got_object_id *); const struct got_error * got_gotweb_closefile(FILE *f) { const struct got_error *err = NULL; err = got_opentemp_truncate(f); if (fclose(f) == EOF && err == NULL) err = got_error_from_errno("fclose"); return err; } static const struct got_error * got_gotweb_openfile(FILE **f, int *priv_fd) { int fd; fd = dup(*priv_fd); if (fd == -1) return got_error_from_errno("dup"); *f = fdopen(fd, "w+"); if (*f == NULL) { close(fd); return got_error(GOT_ERR_PRIVSEP_NO_FD); } return NULL; } static const struct got_error * got_gotweb_dupfd(int *priv_fd, int *fd) { *fd = dup(*priv_fd); if (*fd == -1) return got_error_from_errno("dup"); return NULL; } const struct got_error * got_get_repo_owner(char **owner, struct request *c) { struct transport *t = c->t; struct got_repository *repo = t->repo; const char *gitconfig_owner; *owner = NULL; gitconfig_owner = got_repo_get_gitconfig_owner(repo); if (gitconfig_owner) { *owner = strdup(gitconfig_owner); if (*owner == NULL) return got_error_from_errno("strdup"); } return NULL; } static const struct got_error * get_ref_commit_timestamp(time_t *timestamp, struct got_reference *ref, struct got_repository *repo) { const struct got_error *error; struct got_object_id *id = NULL; int obj_type; struct got_commit_object *commit = NULL; /* We might have a cached timestamp available. */ *timestamp = got_ref_get_cached_committer_time(ref); if (*timestamp != 0) return NULL; error = got_ref_resolve(&id, repo, ref); if (error) return error; error = got_object_get_type(&obj_type, repo, id); if (error || obj_type != GOT_OBJ_TYPE_COMMIT) goto done; error = got_object_open_as_commit(&commit, repo, id); if (error) goto done; *timestamp = got_object_commit_get_committer_time(commit); done: free(id); if (commit) got_object_commit_close(commit); return error; } /* * Find the youngest branch tip in the repository, or the age of * a specific branch tip if a name was provided by the caller. */ const struct got_error * got_get_repo_age(time_t *repo_age, struct request *c, const char *refname) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; *repo_age = 0; if (refname) { struct got_reference *ref; error = got_ref_open(&ref, repo, refname, 0); if (error) return error; error = get_ref_commit_timestamp(repo_age, ref, repo); got_ref_close(ref); } else { struct got_reflist_head refs; struct got_reflist_entry *re; TAILQ_INIT(&refs); error = got_ref_list(&refs, repo, "refs/heads", got_ref_cmp_by_commit_timestamp_descending, repo); if (error) return error; re = TAILQ_FIRST(&refs); if (re) { error = get_ref_commit_timestamp(repo_age, re->ref, repo); } got_ref_list_free(&refs); } return error; } static const struct got_error * got_get_repo_commit(struct request *c, struct repo_commit *repo_commit, struct got_commit_object *commit, struct got_reflist_head *refs, struct got_object_id *id) { const struct got_error *error = NULL; struct got_reflist_entry *re; struct got_object_id *id2 = NULL; struct got_object_qid *parent_id; struct transport *t = c->t; const struct querystring *qs = c->t->qs; char *commit_msg = NULL, *commit_msg0; TAILQ_FOREACH(re, refs, entry) { char *s; const char *name; struct got_tag_object *tag = NULL; struct got_object_id *ref_id; int cmp; if (got_ref_is_symbolic(re->ref)) continue; name = got_ref_get_name(re->ref); if (strncmp(name, "refs/", 5) == 0) name += 5; if (strncmp(name, "got/", 4) == 0) continue; if (strncmp(name, "heads/", 6) == 0) name += 6; if (strncmp(name, "remotes/", 8) == 0) { name += 8; if (strstr(name, "/" GOT_REF_HEAD) != NULL) continue; } error = got_ref_resolve(&ref_id, t->repo, re->ref); if (error) return error; if (strncmp(name, "tags/", 5) == 0) { error = got_object_open_as_tag(&tag, t->repo, ref_id); if (error) { if (error->code != GOT_ERR_OBJ_TYPE) { free(ref_id); continue; } /* * Ref points at something other * than a tag. */ error = NULL; tag = NULL; } } cmp = got_object_id_cmp(tag ? got_object_tag_get_object_id(tag) : ref_id, id); free(ref_id); if (tag) got_object_tag_close(tag); if (cmp != 0) continue; s = repo_commit->refs_str; if (asprintf(&repo_commit->refs_str, "%s%s%s", s ? s : "", s ? ", " : "", name) == -1) { error = got_error_from_errno("asprintf"); free(s); repo_commit->refs_str = NULL; return error; } free(s); } error = got_object_id_str(&repo_commit->commit_id, id); if (error) return error; error = got_object_id_str(&repo_commit->tree_id, got_object_commit_get_tree_id(commit)); if (error) return error; if (qs->action == DIFF || qs->action == PATCH) { parent_id = STAILQ_FIRST( got_object_commit_get_parent_ids(commit)); if (parent_id != NULL) { id2 = got_object_id_dup(&parent_id->id); error = got_object_id_str(&repo_commit->parent_id, id2); if (error) return error; free(id2); } else { repo_commit->parent_id = strdup("/dev/null"); if (repo_commit->parent_id == NULL) { error = got_error_from_errno("strdup"); return error; } } } repo_commit->committer_time = got_object_commit_get_committer_time(commit); repo_commit->author = strdup(got_object_commit_get_author(commit)); if (repo_commit->author == NULL) { error = got_error_from_errno("strdup"); return error; } repo_commit->committer = strdup(got_object_commit_get_committer(commit)); if (repo_commit->committer == NULL) { error = got_error_from_errno("strdup"); return error; } error = got_object_commit_get_logmsg(&commit_msg0, commit); if (error) return error; commit_msg = commit_msg0; while (*commit_msg == '\n') commit_msg++; repo_commit->commit_msg = strdup(commit_msg); if (repo_commit->commit_msg == NULL) error = got_error_from_errno("strdup"); free(commit_msg0); return error; } const struct got_error * got_get_repo_commits(struct request *c, size_t limit) { const struct got_error *error = NULL; struct got_object_id *id = NULL; struct got_commit_graph *graph = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_reference *ref = NULL; struct repo_commit *repo_commit = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; const struct querystring *qs = t->qs; char *file_path = NULL; int chk_next = 0; if (limit == 0) return got_error(GOT_ERR_RANGE); if (limit > 1) { /* * Traverse one commit more than requested to provide * the next button. */ limit++; chk_next = 1; } TAILQ_INIT(&refs); if (qs->file[0]) { if (asprintf(&file_path, "%s/%s", qs->folder[0] ? qs->folder : "", qs->file) == -1) return got_error_from_errno("asprintf"); } if (qs->commit[0]) { error = got_repo_match_object_id_prefix(&id, qs->commit, GOT_OBJ_TYPE_COMMIT, repo); if (error) goto done; } else { error = got_ref_open(&ref, repo, qs->headref, 0); if (error) goto done; error = got_ref_resolve(&id, repo, ref); if (error) goto done; } error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL); if (error) goto done; if (qs->file[0]) { error = got_commit_graph_open(&graph, file_path, 0); if (error) goto done; } else { error = got_commit_graph_open(&graph, "/", 0); if (error) goto done; } error = got_commit_graph_bfsort(graph, id, repo, NULL, NULL); if (error) goto done; for (;;) { struct got_object_id next_id; error = got_commit_graph_iter_next(&next_id, graph, repo, NULL, NULL); if (error) { if (error->code == GOT_ERR_ITER_COMPLETED) error = NULL; goto done; } error = got_object_open_as_commit(&commit, repo, &next_id); if (error) goto done; error = got_init_repo_commit(&repo_commit); if (error) goto done; error = got_get_repo_commit(c, repo_commit, commit, &refs, &next_id); if (error) { gotweb_free_repo_commit(repo_commit); goto done; } if (--limit == 0 && chk_next) { t->more_id = strdup(repo_commit->commit_id); if (t->more_id == NULL) error = got_error_from_errno("strdup"); gotweb_free_repo_commit(repo_commit); goto done; } TAILQ_INSERT_TAIL(&t->repo_commits, repo_commit, entry); if (limit == 0) goto done; if (commit) { got_object_commit_close(commit); commit = NULL; } } done: if (ref) got_ref_close(ref); if (commit) got_object_commit_close(commit); if (graph) got_commit_graph_close(graph); got_ref_list_free(&refs); free(file_path); free(id); return error; } const struct got_error * got_get_repo_tags(struct request *c, size_t limit) { const struct got_error *error = NULL; struct got_object_id *id = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_reference *ref; struct got_reflist_entry *re; struct server *srv = c->srv; struct transport *t = c->t; struct got_repository *repo = t->repo; const struct querystring *qs = t->qs; struct repo_dir *repo_dir = t->repo_dir; struct got_tag_object *tag = NULL; char *repo_path = NULL, *id_str = NULL; char *tag_commit = NULL, *tag_commit0 = NULL; char *commit_msg = NULL, *commit_msg0 = NULL; int chk_next = 0, chk_multi = 1, commit_found = 0; TAILQ_INIT(&refs); if (limit == 0) return got_error(GOT_ERR_RANGE); if (asprintf(&repo_path, "%s/%s", srv->repos_path, repo_dir->name) == -1) return got_error_from_errno("asprintf"); if (qs->commit[0] == '\0' && (qs->action == TAGS || qs->action == RSS)) { error = got_ref_open(&ref, repo, qs->headref, 0); if (error) goto done; error = got_ref_resolve(&id, repo, ref); got_ref_close(ref); if (error) goto done; } else if (qs->commit[0] == '\0' && qs->action == TAG) { error = got_error_msg(GOT_ERR_EOF, "commit id missing"); goto done; } else { error = got_repo_match_object_id_prefix(&id, qs->commit, GOT_OBJ_TYPE_COMMIT, repo); if (error) goto done; } if (qs->action != SUMMARY && qs->action != TAGS) { error = got_object_open_as_commit(&commit, repo, id); if (error) goto done; error = got_object_commit_get_logmsg(&commit_msg0, commit); if (error) goto done; if (commit) { got_object_commit_close(commit); commit = NULL; } } error = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo); if (error) goto done; if (limit == 1) chk_multi = 0; TAILQ_FOREACH(re, &refs, entry) { struct repo_tag *new_repo_tag = NULL; error = got_init_repo_tag(&new_repo_tag); if (error) goto done; TAILQ_INSERT_TAIL(&t->repo_tags, new_repo_tag, entry); new_repo_tag->tag_name = strdup(got_ref_get_name(re->ref)); if (new_repo_tag->tag_name == NULL) { error = got_error_from_errno("strdup"); goto done; } free(id); id = NULL; free(id_str); id_str = NULL; error = got_ref_resolve(&id, repo, re->ref); if (error) goto done; if (tag) got_object_tag_close(tag); error = got_object_open_as_tag(&tag, repo, id); if (error) { if (error->code != GOT_ERR_OBJ_TYPE) goto done; /* "lightweight" tag */ error = got_object_open_as_commit(&commit, repo, id); if (error) goto done; new_repo_tag->tagger = strdup(got_object_commit_get_committer(commit)); if (new_repo_tag->tagger == NULL) { error = got_error_from_errno("strdup"); goto done; } new_repo_tag->tagger_time = got_object_commit_get_committer_time(commit); error = got_object_id_str(&id_str, id); if (error) goto done; } else { new_repo_tag->tagger = strdup(got_object_tag_get_tagger(tag)); if (new_repo_tag->tagger == NULL) { error = got_error_from_errno("strdup"); goto done; } new_repo_tag->tagger_time = got_object_tag_get_tagger_time(tag); error = got_object_id_str(&id_str, got_object_tag_get_object_id(tag)); if (error) goto done; } new_repo_tag->commit_id = strdup(id_str); if (new_repo_tag->commit_id == NULL) goto done; if (commit_found == 0 && qs->commit[0] && strncmp(id_str, qs->commit, strlen(id_str)) != 0) { if (commit) { got_object_commit_close(commit); commit = NULL; } TAILQ_REMOVE(&t->repo_tags, new_repo_tag, entry); gotweb_free_repo_tag(new_repo_tag); continue; } else commit_found = 1; /* * check for one more commit before breaking, * so we know whether to navigate through briefs * commits and summary */ if (chk_next) { t->tags_more_id = strdup(new_repo_tag->commit_id); if (t->tags_more_id == NULL) { error = got_error_from_errno("strdup"); goto done; } if (commit) { got_object_commit_close(commit); commit = NULL; } TAILQ_REMOVE(&t->repo_tags, new_repo_tag, entry); gotweb_free_repo_tag(new_repo_tag); goto done; } if (commit) { error = got_object_commit_get_logmsg(&tag_commit0, commit); if (error) goto done; got_object_commit_close(commit); commit = NULL; } else { tag_commit0 = strdup(got_object_tag_get_message(tag)); if (tag_commit0 == NULL) { error = got_error_from_errno("strdup"); goto done; } } tag_commit = tag_commit0; while (*tag_commit == '\n') tag_commit++; new_repo_tag->tag_commit = strdup(tag_commit); if (new_repo_tag->tag_commit == NULL) { error = got_error_from_errno("strdup"); free(tag_commit0); goto done; } free(tag_commit0); if (qs->action != SUMMARY && qs->action != TAGS) { commit_msg = commit_msg0; while (*commit_msg == '\n') commit_msg++; new_repo_tag->commit_msg = strdup(commit_msg); if (new_repo_tag->commit_msg == NULL) { error = got_error_from_errno("strdup"); goto done; } } if (limit && --limit == 0) { if (chk_multi == 0) break; chk_next = 1; } } done: if (commit) got_object_commit_close(commit); if (tag) got_object_tag_close(tag); got_ref_list_free(&refs); free(commit_msg0); free(repo_path); free(id); free(id_str); return error; } int got_output_repo_tree(struct request *c, char **readme, int (*cb)(struct template *, struct got_tree_entry *)) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_commit_object *commit = NULL; struct got_repository *repo = t->repo; const struct querystring *qs = t->qs; struct repo_commit *rc = NULL; struct got_object_id *tree_id = NULL, *commit_id = NULL; struct got_reflist_head refs; struct got_tree_object *tree = NULL; struct got_tree_entry *te; const char *name; mode_t mode; char *escaped_name = NULL; int nentries, i; TAILQ_INIT(&refs); *readme = NULL; rc = TAILQ_FIRST(&t->repo_commits); error = got_repo_match_object_id(&commit_id, NULL, rc->commit_id, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&tree_id, repo, commit, qs->folder[0] ? qs->folder : "/"); if (error) goto done; error = got_object_open_as_tree(&tree, repo, tree_id); if (error) goto done; nentries = got_object_tree_get_nentries(tree); for (i = 0; i < nentries; i++) { te = got_object_tree_get_entry(tree, i); name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); if (!S_ISDIR(mode) && (!strcasecmp(name, "README") || !strcasecmp(name, "README.md") || !strcasecmp(name, "README.txt"))) { free(*readme); *readme = strdup(name); } if (cb(c->tp, te) == -1) { error = got_error(GOT_ERR_CANCELLED); break; } } done: free(escaped_name); got_ref_list_free(&refs); if (commit) got_object_commit_close(commit); if (tree) got_object_tree_close(tree); free(commit_id); free(tree_id); if (error) { free(*readme); *readme = NULL; if (error->code != GOT_ERR_CANCELLED) log_warnx("%s: %s", __func__, error->msg); return -1; } return 0; } const struct got_error * got_open_blob_for_output(struct got_blob_object **blob, int *fd, int *binary, struct request *c, const char *directory, const char *file, const char *commitstr) { const struct got_error *error = NULL; struct got_repository *repo = c->t->repo; struct got_commit_object *commit = NULL; struct got_object_id *commit_id = NULL; struct got_object_id *blob_id = NULL; struct got_reflist_head refs; char *path = NULL; int obj_type; TAILQ_INIT(&refs); *blob = NULL; *fd = -1; *binary = 0; error = got_ref_list(&refs, repo, "refs/heads", got_ref_cmp_by_name, NULL); if (error) goto done; if (asprintf(&path, "%s%s%s", directory ? directory : "", directory ? "/" : "", file) == -1) { error = got_error_from_errno("asprintf"); goto done; } if (commitstr == NULL) commitstr = GOT_REF_HEAD; error = got_repo_match_object_id(&commit_id, NULL, commitstr, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&blob_id, repo, commit, path); if (error) goto done; if (blob_id == NULL) { error = got_error(GOT_ERR_NO_OBJ); goto done; } error = got_object_get_type(&obj_type, repo, blob_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } error = got_gotweb_dupfd(&c->priv_fd[BLOB_FD_1], fd); if (error) goto done; error = got_object_open_as_blob(blob, repo, blob_id, BUF, *fd); if (error) goto done; error = got_object_blob_is_binary(binary, *blob); if (error) goto done; done: if (commit) got_object_commit_close(commit); if (error) { if (*fd != -1) close(*fd); if (*blob) got_object_blob_close(*blob); *fd = -1; *blob = NULL; } got_ref_list_free(&refs); free(commit_id); free(blob_id); free(path); return error; } int got_output_blob_by_lines(struct template *tp, struct got_blob_object *blob, int (*cb)(struct template *, const char *, size_t)) { const struct got_error *err; char *line = NULL; size_t linesize = 0; size_t lineno = 0; ssize_t linelen = 0; for (;;) { err = got_object_blob_getline(&line, &linelen, &linesize, blob); if (err || linelen == -1) break; lineno++; if (cb(tp, line, lineno) == -1) { err = got_error(GOT_ERR_CANCELLED); break; } } free(line); if (err) { if (err->code != GOT_ERR_CANCELLED) log_warnx("%s: got_object_blob_getline failed: %s", __func__, err->msg); return -1; } return 0; } struct blame_cb_args { struct blame_line *lines; int nlines; int nlines_prec; int lineno_cur; off_t *line_offsets; FILE *f; struct got_repository *repo; struct request *c; got_render_blame_line_cb cb; }; static const struct got_error * got_gotweb_blame_cb(void *arg, int nlines, int lineno, struct got_commit_object *commit, struct got_object_id *id) { const struct got_error *err = NULL; struct blame_cb_args *a = arg; struct blame_line *bline; struct request *c = a->c; char *line = NULL; size_t linesize = 0; off_t offset; struct tm tm; time_t committer_time; if (nlines != a->nlines || (lineno != -1 && lineno < 1) || lineno > a->nlines) return got_error(GOT_ERR_RANGE); if (lineno == -1) return NULL; /* no change in this commit */ /* Annotate this line. */ bline = &a->lines[lineno - 1]; if (bline->annotated) return NULL; err = got_object_id_str(&bline->id_str, id); if (err) return err; bline->committer = strdup(got_object_commit_get_committer(commit)); if (bline->committer == NULL) { err = got_error_from_errno("strdup"); goto done; } committer_time = got_object_commit_get_committer_time(commit); if (gmtime_r(&committer_time, &tm) == NULL) return got_error_from_errno("gmtime_r"); if (strftime(bline->datebuf, sizeof(bline->datebuf), "%F", &tm) == 0) { err = got_error(GOT_ERR_NO_SPACE); goto done; } bline->annotated = 1; /* Print lines annotated so far. */ bline = &a->lines[a->lineno_cur - 1]; if (!bline->annotated) goto done; offset = a->line_offsets[a->lineno_cur - 1]; if (fseeko(a->f, offset, SEEK_SET) == -1) { err = got_error_from_errno("fseeko"); goto done; } while (a->lineno_cur <= a->nlines && bline->annotated) { if (getline(&line, &linesize, a->f) == -1) { if (ferror(a->f)) err = got_error_from_errno("getline"); break; } if (a->cb(c->tp, line, bline, a->nlines_prec, a->lineno_cur) == -1) { err = got_error(GOT_ERR_CANCELLED); break; } a->lineno_cur++; bline = &a->lines[a->lineno_cur - 1]; } done: free(line); return err; } const struct got_error * got_output_file_blame(struct request *c, got_render_blame_line_cb cb) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; const struct querystring *qs = c->t->qs; struct got_object_id *obj_id = NULL, *commit_id = NULL; struct got_commit_object *commit = NULL; struct got_reflist_head refs; struct got_blob_object *blob = NULL; char *path = NULL; struct blame_cb_args bca; int i, obj_type, blobfd = -1, fd1 = -1, fd2 = -1; off_t filesize; FILE *f1 = NULL, *f2 = NULL; TAILQ_INIT(&refs); bca.f = NULL; bca.lines = NULL; bca.cb = cb; if (asprintf(&path, "%s/%s", qs->folder, qs->file) == -1) { error = got_error_from_errno("asprintf"); goto done; } error = got_repo_match_object_id(&commit_id, NULL, qs->commit, GOT_OBJ_TYPE_COMMIT, &refs, repo); if (error) goto done; error = got_object_open_as_commit(&commit, repo, commit_id); if (error) goto done; error = got_object_id_by_path(&obj_id, repo, commit, path); if (error) goto done; error = got_object_get_type(&obj_type, repo, obj_id); if (error) goto done; if (obj_type != GOT_OBJ_TYPE_BLOB) { error = got_error(GOT_ERR_OBJ_TYPE); goto done; } error = got_gotweb_openfile(&bca.f, &c->priv_fd[BLAME_FD_1]); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_2], &blobfd); if (error) goto done; error = got_object_open_as_blob(&blob, repo, obj_id, BUF, blobfd); if (error) goto done; error = got_object_blob_dump_to_file(&filesize, &bca.nlines, &bca.line_offsets, bca.f, blob); if (error || bca.nlines == 0) goto done; /* Don't include \n at EOF in the blame line count. */ if (bca.line_offsets[bca.nlines - 1] == filesize) bca.nlines--; bca.lines = calloc(bca.nlines, sizeof(*bca.lines)); if (bca.lines == NULL) { error = got_error_from_errno("calloc"); goto done; } bca.lineno_cur = 1; bca.nlines_prec = 0; i = bca.nlines; while (i > 0) { i /= 10; bca.nlines_prec++; } bca.repo = repo; bca.c = c; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_3], &fd1); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[BLAME_FD_4], &fd2); if (error) goto done; error = got_gotweb_openfile(&f1, &c->priv_fd[BLAME_FD_5]); if (error) goto done; error = got_gotweb_openfile(&f2, &c->priv_fd[BLAME_FD_6]); if (error) goto done; error = got_blame(path, commit_id, repo, GOT_DIFF_ALGORITHM_PATIENCE, got_gotweb_blame_cb, &bca, NULL, NULL, fd1, fd2, f1, f2); done: if (bca.lines) { free(bca.line_offsets); for (i = 0; i < bca.nlines; i++) { struct blame_line *bline = &bca.lines[i]; free(bline->id_str); free(bline->committer); } } free(bca.lines); if (blobfd != -1 && close(blobfd) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (bca.f) { const struct got_error *bca_err = got_gotweb_closefile(bca.f); if (error == NULL) error = bca_err; } if (f1) { const struct got_error *f1_err = got_gotweb_closefile(f1); if (error == NULL) error = f1_err; } if (f2) { const struct got_error *f2_err = got_gotweb_closefile(f2); if (error == NULL) error = f2_err; } if (commit) got_object_commit_close(commit); if (blob) got_object_blob_close(blob); free(commit_id); free(obj_id); free(path); got_ref_list_free(&refs); return error; } const struct got_error * got_open_diff_for_output(FILE **fp, struct request *c) { const struct got_error *error = NULL; struct transport *t = c->t; struct got_repository *repo = t->repo; struct repo_commit *rc = NULL; struct got_object_id *id1 = NULL, *id2 = NULL; struct got_reflist_head refs; FILE *f1 = NULL, *f2 = NULL, *f3 = NULL; int obj_type, fd1 = -1, fd2 = -1; *fp = NULL; TAILQ_INIT(&refs); error = got_gotweb_openfile(&f1, &c->priv_fd[DIFF_FD_1]); if (error) goto done; error = got_gotweb_openfile(&f2, &c->priv_fd[DIFF_FD_2]); if (error) goto done; error = got_gotweb_openfile(&f3, &c->priv_fd[DIFF_FD_3]); if (error) goto done; rc = TAILQ_FIRST(&t->repo_commits); if (rc->parent_id != NULL && strncmp(rc->parent_id, "/dev/null", 9) != 0) { error = got_repo_match_object_id(&id1, NULL, rc->parent_id, GOT_OBJ_TYPE_ANY, &refs, repo); if (error) goto done; } error = got_repo_match_object_id(&id2, NULL, rc->commit_id, GOT_OBJ_TYPE_ANY, &refs, repo); if (error) goto done; error = got_object_get_type(&obj_type, repo, id2); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_4], &fd1); if (error) goto done; error = got_gotweb_dupfd(&c->priv_fd[DIFF_FD_5], &fd2); if (error) goto done; switch (obj_type) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, repo, f3); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, "", "", GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, repo, f3); break; case GOT_OBJ_TYPE_COMMIT: error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd1, fd2, id1, id2, NULL, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, repo, f3); break; default: error = got_error(GOT_ERR_OBJ_TYPE); } if (error) goto done; if (fseek(f3, 0, SEEK_SET) == -1) { error = got_ferror(f3, GOT_ERR_IO); goto done; } *fp = f3; done: if (fd1 != -1 && close(fd1) == -1 && error == NULL) error = got_error_from_errno("close"); if (fd2 != -1 && close(fd2) == -1 && error == NULL) error = got_error_from_errno("close"); if (f1) { const struct got_error *f1_err = got_gotweb_closefile(f1); if (error == NULL) error = f1_err; } if (f2) { const struct got_error *f2_err = got_gotweb_closefile(f2); if (error == NULL) error = f2_err; } if (error && f3) { got_gotweb_closefile(f3); *fp = NULL; } got_ref_list_free(&refs); free(id1); free(id2); return error; } static const struct got_error * got_init_repo_commit(struct repo_commit **rc) { *rc = calloc(1, sizeof(**rc)); if (*rc == NULL) return got_error_from_errno2(__func__, "calloc"); (*rc)->path = NULL; (*rc)->refs_str = NULL; (*rc)->commit_id = NULL; (*rc)->committer = NULL; (*rc)->author = NULL; (*rc)->parent_id = NULL; (*rc)->tree_id = NULL; (*rc)->commit_msg = NULL; return NULL; } static const struct got_error * got_init_repo_tag(struct repo_tag **rt) { *rt = calloc(1, sizeof(**rt)); if (*rt == NULL) return got_error_from_errno2(__func__, "calloc"); (*rt)->commit_id = NULL; (*rt)->tag_name = NULL; (*rt)->tag_commit = NULL; (*rt)->commit_msg = NULL; (*rt)->tagger = NULL; return NULL; } got-portable-0.119/gotwebd/pages.c0000664000175000017500000020673015066537254012531 #line 2 "../gotwebd/pages.tmpl" /* * Copyright (c) 2022 Omar Polo * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #line 19 "../gotwebd/pages.tmpl" #include "got_compat.h" #line 21 "../gotwebd/pages.tmpl" #include #include #include #line 25 "../gotwebd/pages.tmpl" #include #include #include #include #include #include #include #line 33 "../gotwebd/pages.tmpl" #include "got_error.h" #include "got_object.h" #include "got_reference.h" #line 37 "../gotwebd/pages.tmpl" #include "gotwebd.h" #include "log.h" #include "tmpl.h" #line 41 "../gotwebd/pages.tmpl" enum gotweb_ref_tm { TM_DIFF, TM_LONG, }; #line 46 "../gotwebd/pages.tmpl" static int breadcumbs(struct template *); static int datetime(struct template *, time_t, int); static int gotweb_render_blob_line(struct template *, const char *, size_t); static int gotweb_render_tree_item(struct template *, struct got_tree_entry *); static int blame_line(struct template *, const char *, struct blame_line *, int, int); #line 53 "../gotwebd/pages.tmpl" static inline int gotweb_render_more(struct template *, int); #line 55 "../gotwebd/pages.tmpl" static inline int tree_listing(struct template *); static inline int diff_line(struct template *, char *); static inline int tag_item(struct template *, struct repo_tag *); static inline int branch(struct template *, struct got_reflist_entry *); static inline int rss_tag_item(struct template *, struct repo_tag *); static inline int rss_author(struct template *, char *); #line 62 "../gotwebd/pages.tmpl" static inline char * nextsep(char *s, char **t) { char *q; #line 67 "../gotwebd/pages.tmpl" while (*s == '/') s++; *t = s; if (*s == '\0') return NULL; #line 73 "../gotwebd/pages.tmpl" q = strchr(s, '/'); if (q == NULL) q = strchr(s, '\0'); return q; } #line 81 "../gotwebd/pages.tmpl" int datetime(struct template *tp, time_t t, int fmt) { int tp_ret = 0; #line 83 "../gotwebd/pages.tmpl" struct tm tm; char rfc3339[64]; char datebuf[64]; #line 87 "../gotwebd/pages.tmpl" if (gmtime_r(&t, &tm) == NULL) return -1; #line 90 "../gotwebd/pages.tmpl" if (strftime(rfc3339, sizeof(rfc3339), "%FT%TZ", &tm) == 0) return -1; #line 93 "../gotwebd/pages.tmpl" if (fmt != TM_DIFF && asctime_r(&tm, datebuf) == NULL) return -1; #line 96 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; err: return tp_ret; } #line 105 "../gotwebd/pages.tmpl" int breadcumbs(struct template *tp) { int tp_ret = 0; #line 107 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; const struct querystring *qs = c->t->qs; struct gotweb_url url; const char *folder = qs->folder; const char *action = "tree"; char *t, *s = NULL, *dir = NULL; char ch; #line 115 "../gotwebd/pages.tmpl" memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = TREE; url.path = qs->path[0] ? qs->path : NULL; url.commit = qs->commit[0] ? qs->commit : NULL; #line 121 "../gotwebd/pages.tmpl" if (qs->action != TREE && qs->action != BLOB) { action = gotweb_action_name(qs->action); url.action = qs->action; } #line 126 "../gotwebd/pages.tmpl" if (*folder != '\0') { while (*folder == '/') folder++; dir = strdup(folder); if (dir == NULL) return (-1); s = dir; } #line 135 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 136 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, action)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 137 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; if (dir) { while ((s = nextsep(s, &t)) != NULL) { #line 141 "../gotwebd/pages.tmpl" ch = *s; *s = '\0'; url.folder = dir; #line 146 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 147 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t)) == -1) goto err; #line 149 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 149 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " / ")) == -1) goto err; #line 151 "../gotwebd/pages.tmpl" *s = ch; } } #line 155 "../gotwebd/pages.tmpl" if (qs->file[0]) { if ((tp_ret = tp_htmlescape(tp, qs->file)) == -1) goto err; } #line 159 "../gotwebd/pages.tmpl" err: free(dir); return tp_ret; } #line 164 "../gotwebd/pages.tmpl" int gotweb_render_page(struct template *tp, int (*body)(struct template *)) { int tp_ret = 0; #line 166 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; const struct querystring *qs = c->t->qs; struct gotweb_url u_path; const char *prfx = c->fcgi_params.document_uri; const char *css = srv->custom_css; #line 173 "../gotwebd/pages.tmpl" memset(&u_path, 0, sizeof(u_path)); u_path.index_page = -1; u_path.action = SUMMARY; #line 181 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 58)) == -1) goto err; #line 181 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, srv->site_name)) == -1) goto err; #line 185 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
action))) == -1) goto err; if ((tp_ret = tp_write(tp, "\">", 2)) == -1) goto err; #line 221 "../gotwebd/pages.tmpl" if ((tp_ret = body(tp)) == -1) goto err; #line 225 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 58)) == -1) goto err; #line 225 "../gotwebd/pages.tmpl" if (srv->show_site_owner) { if ((tp_ret = tp_htmlescape(tp, srv->site_owner)) == -1) goto err; } #line 232 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 27)) == -1) goto err; err: return tp_ret; } #line 234 "../gotwebd/pages.tmpl" int gotweb_render_error(struct template *tp) { int tp_ret = 0; #line 236 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; #line 240 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 22)) == -1) goto err; #line 240 "../gotwebd/pages.tmpl" if (t->error) { if ((tp_ret = tp_htmlescape(tp, t->error->msg)) == -1) goto err; } else { #line 244 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "See daemon logs for details", 27)) == -1) goto err; } #line 246 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 248 "../gotwebd/pages.tmpl" int gotweb_render_repo_table_hdr(struct template *tp) { int tp_ret = 0; #line 250 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; #line 257 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Project
", 63)) == -1) goto err; #line 257 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 261 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Description
", 56)) == -1) goto err; } if (srv->show_repo_owner) { #line 266 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Owner
", 44)) == -1) goto err; } if (srv->show_repo_age) { #line 271 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Last Change
", 48)) == -1) goto err; } #line 273 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 275 "../gotwebd/pages.tmpl" int gotweb_render_repo_fragment(struct template *tp, struct repo_dir *repo_dir) { int tp_ret = 0; #line 277 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }, briefs = { .action = BRIEFS, .index_page = -1, .path = repo_dir->name, }, commits = { .action = COMMITS, .index_page = -1, .path = repo_dir->name, }, tags = { .action = TAGS, .index_page = -1, .path = repo_dir->name, }, tree = { .action = TREE, .index_page = -1, .path = repo_dir->name, }, rss = { .action = RSS, .index_page = -1, .path = repo_dir->name, }; #line 307 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 10)) == -1) goto err; #line 309 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 311 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 39)) == -1) goto err; #line 311 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->description)) == -1) goto err; #line 313 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } if (srv->show_repo_owner) { #line 316 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 33)) == -1) goto err; #line 316 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->owner)) == -1) goto err; #line 318 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } if (srv->show_repo_age) { #line 321 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 31)) == -1) goto err; #line 321 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, repo_dir->age, TM_DIFF)) == -1) goto err; #line 323 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } #line 326 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &summary)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">summary", 13)) == -1) goto err; #line 327 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &briefs)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">briefs", 12)) == -1) goto err; #line 329 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &commits)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">commits", 13)) == -1) goto err; #line 331 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tags)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">tags", 10)) == -1) goto err; #line 333 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tree)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">tree", 10)) == -1) goto err; #line 335 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &rss)) == -1) goto err; #line 341 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "\">rss

", 33)) == -1) goto err; err: return tp_ret; } #line 343 "../gotwebd/pages.tmpl" int gotweb_render_briefs(struct template *tp) { int tp_ret = 0; #line 345 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = c->t->qs; struct repo_commit *rc; struct repo_dir *repo_dir = t->repo_dir; struct gotweb_url diff_url, patch_url, tree_url; char *tmp, *body; #line 353 "../gotwebd/pages.tmpl" diff_url = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; patch_url = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; tree_url = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, .headref = qs->headref, }; #line 376 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commit Briefs

", 81)) == -1) goto err; TAILQ_FOREACH(rc, &t->repo_commits, entry) { #line 378 "../gotwebd/pages.tmpl" diff_url.commit = rc->commit_id; patch_url.commit = rc->commit_id; tree_url.commit = rc->commit_id; #line 382 "../gotwebd/pages.tmpl" tmp = strchr(rc->committer, '<'); if (tmp) *tmp = '\0'; #line 386 "../gotwebd/pages.tmpl" body = strchr(rc->commit_msg, '\n'); if (body) { *body++ = '\0'; while (*body == '\n') body++; } #line 396 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 66)) == -1) goto err; #line 396 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_DIFF)) == -1) goto err; #line 398 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 398 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 400 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 24)) == -1) goto err; #line 400 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%.10s", rc->commit_id) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; #line 402 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 402 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 404 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 28)) == -1) goto err; #line 404 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; #line 407 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 11)) == -1) goto err; #line 407 "../gotwebd/pages.tmpl" if (body && *body != '\0') { #line 410 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">", 2)) == -1) goto err; #line 411 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 413 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 413 "../gotwebd/pages.tmpl" if (rc->refs_str) { if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 414 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 414 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->refs_str)) == -1) goto err; if ((tp_ret = tp_write(tp, ")", 8)) == -1) goto err; } if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 418 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 47)) == -1) goto err; #line 418 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ⋅⋅⋅ ")) == -1) goto err; #line 421 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; #line 421 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_write(tp, "

", 3)) == -1) goto err; #line 422 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, body)) == -1) goto err; #line 424 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 14)) == -1) goto err; #line 424 "../gotwebd/pages.tmpl" } else { #line 426 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">", 2)) == -1) goto err; #line 427 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 429 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 4)) == -1) goto err; #line 429 "../gotwebd/pages.tmpl" if (rc->refs_str) { if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 430 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 430 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->refs_str)) == -1) goto err; if ((tp_ret = tp_write(tp, ")", 8)) == -1) goto err; } #line 433 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 4)) == -1) goto err; } #line 437 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tp_arg, &diff_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">diff", 10)) == -1) goto err; #line 438 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &patch_url)) == -1) goto err; if ((tp_ret = tp_write(tp, "\">patch", 11)) == -1) goto err; #line 440 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tp_arg, &tree_url)) == -1) goto err; #line 445 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "\">tree

", 28)) == -1) goto err; } if ((tp_ret = gotweb_render_more(tp, BRIEFS)) == -1) goto err; #line 448 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 450 "../gotwebd/pages.tmpl" int gotweb_render_more(struct template *tp, int action) { int tp_ret = 0; #line 452 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct gotweb_url more = { .action = action, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, .commit = t->more_id, .headref = qs->headref, .folder = qs->folder[0] ? qs->folder : NULL, .file = qs->file[0] ? qs->file : NULL, }; #line 465 "../gotwebd/pages.tmpl" if (action == TAGS) more.commit = t->tags_more_id; #line 468 "../gotwebd/pages.tmpl" if (more.commit) { #line 471 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 34)) == -1) goto err; } err: return tp_ret; } #line 479 "../gotwebd/pages.tmpl" int gotweb_render_navs(struct template *tp) { int tp_ret = 0; #line 481 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct gotweb_url prev, next; int have_prev, have_next; #line 485 "../gotwebd/pages.tmpl" gotweb_index_navs(c, &prev, &have_prev, &next, &have_next); #line 489 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 40)) == -1) goto err; #line 489 "../gotwebd/pages.tmpl" if (have_prev) { if ((tp_ret = tp_write(tp, "Previous", 14)) == -1) goto err; } #line 496 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 25)) == -1) goto err; #line 496 "../gotwebd/pages.tmpl" if (have_next) { if ((tp_ret = tp_write(tp, "Next", 10)) == -1) goto err; } #line 503 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; err: return tp_ret; } #line 505 "../gotwebd/pages.tmpl" int gotweb_render_commits(struct template *tp) { int tp_ret = 0; #line 507 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_commit *rc; struct gotweb_url diff, patch, tree; #line 513 "../gotwebd/pages.tmpl" diff = (struct gotweb_url){ .action = DIFF, .index_page = -1, .path = repo_dir->name, }; patch = (struct gotweb_url){ .action = PATCH, .index_page = -1, .path = repo_dir->name, }; tree = (struct gotweb_url){ .action = TREE, .index_page = -1, .path = repo_dir->name, }; #line 533 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commits

", 79)) == -1) goto err; TAILQ_FOREACH(rc, &t->repo_commits, entry) { #line 535 "../gotwebd/pages.tmpl" diff.commit = rc->commit_id; patch.commit = rc->commit_id; tree.commit = rc->commit_id; #line 542 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Commit:
", 81)) == -1) goto err; #line 542 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 544 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
From:
", 30)) == -1) goto err; #line 544 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->author)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; #line 545 "../gotwebd/pages.tmpl" if (strcmp(rc->committer, rc->author) != 0) { #line 547 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Via:
", 17)) == -1) goto err; #line 547 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } #line 551 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 18)) == -1) goto err; #line 551 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 557 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 42)) == -1) goto err; #line 557 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 562 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
diff", 10)) == -1) goto err; #line 563 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "patch", 11)) == -1) goto err; #line 565 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "tree

", 28)) == -1) goto err; } if ((tp_ret = gotweb_render_more(tp, COMMITS)) == -1) goto err; #line 573 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 575 "../gotwebd/pages.tmpl" int gotweb_render_blob(struct template *tp) { int tp_ret = 0; #line 577 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct got_blob_object *blob = t->blob; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blame_url, raw_url; #line 584 "../gotwebd/pages.tmpl" memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path[0] ? qs->path : NULL, briefs_url.commit = qs->commit[0] ? qs->commit : NULL, briefs_url.folder = qs->folder[0] ? qs->folder : NULL, briefs_url.file = qs->file[0] ? qs->file : NULL, #line 592 "../gotwebd/pages.tmpl" memcpy(&blame_url, &briefs_url, sizeof(blame_url)); blame_url.action = BLAME; #line 595 "../gotwebd/pages.tmpl" memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; #line 606 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Blob

Date:
", 125)) == -1) goto err; #line 606 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 609 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 609 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 612 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
History", 13)) == -1) goto err; #line 615 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Blame", 11)) == -1) goto err; #line 619 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Raw File

", 56)) == -1) goto err;
#line 629 "../gotwebd/pages.tmpl"
if ((tp_ret = got_output_blob_by_lines(tp, blob, gotweb_render_blob_line)) == -1) goto err;
#line 633 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 18)) == -1) goto err; err: return tp_ret; } #line 636 "../gotwebd/pages.tmpl" int gotweb_render_blob_line(struct template *tp, const char *line, size_t no) { int tp_ret = 0; #line 638 "../gotwebd/pages.tmpl" char lineno[16]; int r; #line 641 "../gotwebd/pages.tmpl" r = snprintf(lineno, sizeof(lineno), "%zu", no); if (r < 0 || (size_t)r >= sizeof(lineno)) return -1; #line 645 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 2)) == -1) goto err; #line 646 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, lineno)) == -1) goto err; #line 646 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 28)) == -1) goto err; #line 647 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 649 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 13)) == -1) goto err; err: return tp_ret; } #line 651 "../gotwebd/pages.tmpl" int tree_listing(struct template *tp) { int tp_ret = 0; #line 653 "../gotwebd/pages.tmpl" const struct got_error *error; struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = c->t->qs; struct gotweb_url url; char *readme = NULL; int binary; const uint8_t *buf; size_t len; #line 664 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; #line 664 "../gotwebd/pages.tmpl" if ((tp_ret = got_output_repo_tree(c, &readme, gotweb_render_tree_item)) == -1) goto err; #line 666 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 8)) == -1) goto err; #line 666 "../gotwebd/pages.tmpl" if (readme) { #line 668 "../gotwebd/pages.tmpl" error = got_open_blob_for_output(&t->blob, &t->fd, &binary, c, qs->folder[0] ? qs->folder : NULL, readme, qs->commit[0] ? qs->commit : NULL); if (error) { free(readme); return (-1); } #line 676 "../gotwebd/pages.tmpl" memset(&url, 0, sizeof(url)); url.index_page = -1; url.action = BLOB; url.path = t->qs->path[0] ? t->qs->path : NULL; url.file = readme; url.folder = t->qs->folder[0] ? t->qs->folder : ""; url.commit = t->qs->commit[0] ? t->qs->commit : NULL; #line 684 "../gotwebd/pages.tmpl" if (!binary) { #line 686 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 2)) == -1) goto err; #line 687 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, readme)) == -1) goto err; #line 691 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 14)) == -1) goto err;
for (;;) {
error = got_object_blob_read_block(&len, t->blob);
if (error) {
free(readme);
return (-1);
}
if (len == 0)
break;
buf = got_object_blob_get_read_buf(t->blob);
if (tp_write_htmlescape(tp, buf, len) == -1) {
free(readme);
return (-1);
}
}
#line 708 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; } } #line 710 "../gotwebd/pages.tmpl" err: free(readme); return tp_ret; } #line 714 "../gotwebd/pages.tmpl" int gotweb_render_tree(struct template *tp) { int tp_ret = 0; #line 716 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); #line 727 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tree

Tree:
", 149)) == -1) goto err; #line 727 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->tree_id)) == -1) goto err; #line 730 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 30)) == -1) goto err; #line 730 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 733 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 733 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 737 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 22)) == -1) goto err; #line 737 "../gotwebd/pages.tmpl" if ((tp_ret = tree_listing(tp)) == -1) goto err; #line 739 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 742 "../gotwebd/pages.tmpl" int gotweb_render_tree_item(struct template *tp, struct got_tree_entry *te) { int tp_ret = 0; #line 744 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); const char *modestr = ""; const char *name; const char *folder; char *dir = NULL; mode_t mode; struct gotweb_url url = { .index_page = -1, .commit = rc->commit_id, .path = qs->path[0] ? qs->path : NULL, }; #line 759 "../gotwebd/pages.tmpl" name = got_tree_entry_get_name(te); mode = got_tree_entry_get_mode(te); #line 762 "../gotwebd/pages.tmpl" folder = qs->folder[0] ? qs->folder : ""; if (S_ISDIR(mode)) { if (asprintf(&dir, "%s/%s", folder, name) == -1) return (-1); #line 767 "../gotwebd/pages.tmpl" url.action = TREE; url.folder = dir; } else { url.action = BLOB; url.folder = folder; url.file = name; } #line 775 "../gotwebd/pages.tmpl" if (got_object_tree_entry_is_submodule(te)) modestr = "$"; else if (S_ISLNK(mode)) modestr = "@"; else if (S_ISDIR(mode)) modestr = "/"; else if (mode & S_IXUSR) modestr = "*"; #line 785 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 785 "../gotwebd/pages.tmpl" if (S_ISDIR(mode)) { #line 787 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 788 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, name)) == -1) goto err; #line 788 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, modestr)) == -1) goto err; #line 791 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 9)) == -1) goto err; #line 791 "../gotwebd/pages.tmpl" } else { #line 793 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 794 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, name)) == -1) goto err; #line 794 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, modestr)) == -1) goto err; #line 798 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 37)) == -1) goto err; #line 798 "../gotwebd/pages.tmpl" url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits", 13)) == -1) goto err; #line 802 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BLAME; if ((tp_ret = tp_write(tp, "blame", 16)) == -1) goto err; } #line 810 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 5)) == -1) goto err; #line 810 "../gotwebd/pages.tmpl" err: #line 812 "../gotwebd/pages.tmpl" free(dir); return tp_ret; } #line 816 "../gotwebd/pages.tmpl" int gotweb_render_tags(struct template *tp) { int tp_ret = 0; #line 818 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; #line 826 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tags

", 70)) == -1) goto err; #line 826 "../gotwebd/pages.tmpl" if (TAILQ_EMPTY(&t->repo_tags)) { #line 830 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
This repository contains no tags
", 60)) == -1) goto err; #line 830 "../gotwebd/pages.tmpl" } else { TAILQ_FOREACH(rt, &t->repo_tags, entry) { #line 832 "../gotwebd/pages.tmpl" if ((tp_ret = tag_item(tp, rt)) == -1) goto err; } #line 834 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_more(tp, TAGS)) == -1) goto err; } #line 837 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 839 "../gotwebd/pages.tmpl" int tag_item(struct template *tp, struct repo_tag *rt) { int tp_ret = 0; #line 841 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *tag_name = rt->tag_name; char *msg = rt->tag_commit; char *nl; struct gotweb_url url = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; #line 854 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; #line 857 "../gotwebd/pages.tmpl" if (msg) { nl = strchr(msg, '\n'); if (nl) *nl = '\0'; } #line 864 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 21)) == -1) goto err; #line 864 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rt->tagger_time, TM_DIFF)) == -1) goto err; #line 866 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 28)) == -1) goto err; #line 866 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 868 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
tag", 9)) == -1) goto err; #line 875 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BRIEFS; if ((tp_ret = tp_write(tp, "commit briefs", 19)) == -1) goto err; #line 878 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits

", 31)) == -1) goto err; err: return tp_ret; } #line 886 "../gotwebd/pages.tmpl" int gotweb_render_tag(struct template *tp) { int tp_ret = 0; #line 888 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_tag *rt; const char *tag_name; #line 893 "../gotwebd/pages.tmpl" rt = TAILQ_LAST(&t->repo_tags, repo_tags_head); tag_name = rt->tag_name; #line 896 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/", 5) == 0) tag_name += 5; #line 907 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tag

Commit:
", 150)) == -1) goto err; #line 907 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_id)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 908 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "(", 24)) == -1) goto err; #line 909 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 912 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, ")
Tagger:
", 33)) == -1) goto err; #line 912 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->tagger)) == -1) goto err; #line 915 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 23)) == -1) goto err; #line 915 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rt->tagger_time, TM_LONG)) == -1) goto err; #line 918 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 918 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_msg)) == -1) goto err; #line 922 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

", 37)) == -1) goto err;
#line 922 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_htmlescape(tp, rt->tag_commit)) == -1)
goto err;
#line 926 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 18)) == -1) goto err; err: return tp_ret; } #line 928 "../gotwebd/pages.tmpl" int gotweb_render_diff(struct template *tp) { int tp_ret = 0; #line 930 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; FILE *fp = t->fp; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); char *line = NULL; size_t linesize = 0; ssize_t linelen; struct gotweb_url patch_url, tree_url = { .action = TREE, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, .commit = rc->commit_id, }; #line 945 "../gotwebd/pages.tmpl" memcpy(&patch_url, &tree_url, sizeof(patch_url)); patch_url.action = PATCH; #line 955 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Commit Diff

Commit:
", 158)) == -1) goto err; #line 955 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 957 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
From:
", 30)) == -1) goto err; #line 957 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->author)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; #line 958 "../gotwebd/pages.tmpl" if (strcmp(rc->committer, rc->author) != 0) { #line 960 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Via:
", 17)) == -1) goto err; #line 960 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->committer)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } #line 964 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Date:
", 18)) == -1) goto err; #line 964 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 967 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 967 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 970 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
Patch", 11)) == -1) goto err; #line 973 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Tree

", 47)) == -1) goto err;
while ((linelen = getline(&line, &linesize, fp)) != -1) {
if ((tp_ret = diff_line(tp, line)) == -1) goto err;
}
#line 987 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; #line 987 "../gotwebd/pages.tmpl" err: free(line); return tp_ret; } #line 991 "../gotwebd/pages.tmpl" int diff_line(struct template *tp, char *line ) { int tp_ret = 0; #line 993 "../gotwebd/pages.tmpl" const char *color = NULL; char *nl; #line 996 "../gotwebd/pages.tmpl" if (!strncmp(line, "-", 1)) color = "diff_minus"; else if (!strncmp(line, "+", 1)) color = "diff_plus"; else if (!strncmp(line, "@@", 2)) color = "diff_chunk_header"; else if (!strncmp(line, "commit +", 8) || !strncmp(line, "commit -", 8) || !strncmp(line, "blob +", 6) || !strncmp(line, "blob -", 6) || !strncmp(line, "file +", 6) || !strncmp(line, "file -", 6)) color = "diff_meta"; else if (!strncmp(line, "from:", 5) || !strncmp(line, "via:", 4)) color = "diff_author"; else if (!strncmp(line, "date:", 5)) color = "diff_date"; #line 1014 "../gotwebd/pages.tmpl" nl = strchr(line, '\n'); if (nl) *nl = '\0'; #line 1018 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 1018 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 1018 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1018 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; err: return tp_ret; } #line 1022 "../gotwebd/pages.tmpl" int gotweb_render_branches(struct template *tp, struct got_reflist_head *refs) { int tp_ret = 0; #line 1024 "../gotwebd/pages.tmpl" struct got_reflist_entry *re; #line 1030 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Branches

", 78)) == -1) goto err; TAILQ_FOREACH(re, refs, entry) { if (!got_ref_is_symbolic(re->ref)) { if ((tp_ret = branch(tp, re)) == -1) goto err; } } #line 1036 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 6)) == -1) goto err; err: return tp_ret; } #line 1038 "../gotwebd/pages.tmpl" int branch(struct template *tp, struct got_reflist_entry *re) { int tp_ret = 0; #line 1040 "../gotwebd/pages.tmpl" const struct got_error *err; struct request *c = tp->tp_arg; const struct querystring *qs = c->t->qs; const char *refname; time_t age; struct gotweb_url url = { .action = SUMMARY, .index_page = -1, .path = qs->path[0] ? qs->path : NULL, }; #line 1051 "../gotwebd/pages.tmpl" refname = got_ref_get_name(re->ref); #line 1053 "../gotwebd/pages.tmpl" err = got_get_repo_age(&age, c, refname); if (err) { log_warnx("%s: %s", __func__, err->msg); return -1; } #line 1059 "../gotwebd/pages.tmpl" if (strncmp(refname, "refs/heads/", 11) == 0) refname += 11; #line 1062 "../gotwebd/pages.tmpl" url.headref = refname; #line 1066 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 60)) == -1) goto err; #line 1066 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, age, TM_DIFF)) == -1) goto err; #line 1069 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
summary", 13)) == -1) goto err; #line 1074 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = BRIEFS; if ((tp_ret = tp_write(tp, "commit briefs", 19)) == -1) goto err; #line 1077 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; url.action = COMMITS; if ((tp_ret = tp_write(tp, "commits

", 41)) == -1) goto err; err: return tp_ret; } #line 1086 "../gotwebd/pages.tmpl" int gotweb_render_summary(struct template *tp) { int tp_ret = 0; #line 1088 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct got_reflist_head *refs = &t->refs; #line 1094 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 53)) == -1) goto err; #line 1094 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { #line 1096 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Description:
", 25)) == -1) goto err; #line 1096 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t->repo_dir->description)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_owner) { #line 1100 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Owner:
", 19)) == -1) goto err; #line 1100 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, t->repo_dir->owner)) == -1) goto err; if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_age) { #line 1105 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Last Change:
", 25)) == -1) goto err; #line 1105 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, t->repo_dir->age, TM_DIFF)) == -1) goto err; #line 1107 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 5)) == -1) goto err; } if (srv->show_repo_cloneurl) { #line 1110 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Clone URL:
", 46)) == -1) goto err;
#line 1110 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_htmlescape(tp, t->repo_dir->url)) == -1)
goto err;
if ((tp_ret = tp_write(tp, "
", 11)) == -1) goto err; } #line 1114 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 33)) == -1) goto err; #line 1114 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_briefs(tp)) == -1) goto err; #line 1117 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 36)) == -1) goto err; #line 1117 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_branches(tp, refs)) == -1) goto err; #line 1120 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 32)) == -1) goto err; #line 1120 "../gotwebd/pages.tmpl" if ((tp_ret = gotweb_render_tags(tp)) == -1) goto err; #line 1127 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Tree

", 102)) == -1) goto err; #line 1127 "../gotwebd/pages.tmpl" if ((tp_ret = tree_listing(tp)) == -1) goto err; #line 1130 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; err: return tp_ret; } #line 1132 "../gotwebd/pages.tmpl" int gotweb_render_blame(struct template *tp) { int tp_ret = 0; #line 1134 "../gotwebd/pages.tmpl" const struct got_error *err; struct request *c = tp->tp_arg; struct transport *t = c->t; const struct querystring *qs = t->qs; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct gotweb_url briefs_url, blob_url, raw_url; #line 1141 "../gotwebd/pages.tmpl" memset(&briefs_url, 0, sizeof(briefs_url)); briefs_url.index_page = -1, briefs_url.action = BRIEFS, briefs_url.path = qs->path[0] ? qs->path : NULL; briefs_url.commit = qs->commit[0] ? qs->commit : NULL, briefs_url.folder = qs->folder[0] ? qs->folder : NULL, briefs_url.file = qs->file[0] ? qs->file : NULL, #line 1149 "../gotwebd/pages.tmpl" memcpy(&blob_url, &briefs_url, sizeof(blob_url)); blob_url.action = BLOB; #line 1152 "../gotwebd/pages.tmpl" memcpy(&raw_url, &briefs_url, sizeof(raw_url)); raw_url.action = BLOBRAW; #line 1163 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Blame

Date:
", 127)) == -1) goto err; #line 1163 "../gotwebd/pages.tmpl" if ((tp_ret = datetime(tp, rc->committer_time, TM_LONG)) == -1) goto err; #line 1166 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Message:
", 45)) == -1) goto err; #line 1166 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_msg)) == -1) goto err; #line 1169 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
Actions:
History", 13)) == -1) goto err; #line 1172 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Blob", 10)) == -1) goto err; #line 1176 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " | ")) == -1) goto err; if ((tp_ret = tp_write(tp, "Raw File

", 52)) == -1) goto err;
err = got_output_file_blame(c, &blame_line);
if (err && err->code != GOT_ERR_CANCELLED)
log_warnx("%s: got_output_file_blame: %s", __func__,
err->msg);
if (err)
return (-1);
#line 1195 "../gotwebd/pages.tmpl"
if ((tp_ret = tp_write(tp, "
", 12)) == -1) goto err; err: return tp_ret; } #line 1198 "../gotwebd/pages.tmpl" int blame_line(struct template *tp, const char *line, struct blame_line *bline, int lprec, int lcur) { int tp_ret = 0; #line 1200 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; char *committer, *s; struct gotweb_url url = { .action = DIFF, .index_page = -1, .path = repo_dir->name, .commit = bline->id_str, }; #line 1211 "../gotwebd/pages.tmpl" s = strchr(bline->committer, '<'); committer = s ? s + 1 : bline->committer; #line 1214 "../gotwebd/pages.tmpl" s = strchr(committer, '@'); if (s) *s = '\0'; #line 1219 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 51)) == -1) goto err; #line 1219 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%*d ", lprec, lcur) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; #line 1221 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 2)) == -1) goto err; #line 1222 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%.8s", bline->id_str) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; #line 1225 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 11)) == -1) goto err; #line 1225 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 1226 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, bline->datebuf)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1227 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 27)) == -1) goto err; #line 1228 "../gotwebd/pages.tmpl" if (asprintf(&tp->tp_tmp, "%.9s", committer) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) == -1) goto err; free(tp->tp_tmp); tp->tp_tmp = NULL; if ((tp_ret = tp_write(tp, "", 7)) == -1) goto err; #line 1229 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; if ((tp_ret = tp_write(tp, "", 25)) == -1) goto err; #line 1230 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, line)) == -1) goto err; #line 1232 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "
", 13)) == -1) goto err; err: return tp_ret; } #line 1234 "../gotwebd/pages.tmpl" int gotweb_render_patch(struct template *tp) { int tp_ret = 0; #line 1236 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_commit *rc = TAILQ_FIRST(&t->repo_commits); struct tm tm; char buf[BUFSIZ], datebuf[64]; size_t r; int w; #line 1244 "../gotwebd/pages.tmpl" if (gmtime_r(&rc->committer_time, &tm) == NULL || asctime_r(&tm, datebuf) == NULL) return (-1); #line 1248 "../gotwebd/pages.tmpl" datebuf[strcspn(datebuf, "\n")] = '\0'; #line 1250 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "commit ", 7)) == -1) goto err; #line 1250 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rc->commit_id)) == -1) goto err; #line 1250 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_write(tp, "from: ", 6)) == -1) goto err; #line 1251 "../gotwebd/pages.tmpl" if ((tp_ret = tp_writes(tp, rc->author)) == -1) goto err; #line 1251 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if (strcmp(rc->committer, rc->author) != 0) { if ((tp_ret = tp_write(tp, "via: ", 5)) == -1) goto err; #line 1253 "../gotwebd/pages.tmpl" if ((tp_ret = tp_writes(tp, rc->committer)) == -1) goto err; #line 1253 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; } #line 1255 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "date: ", 6)) == -1) goto err; #line 1255 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, datebuf)) == -1) goto err; #line 1255 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " UTC")) == -1) goto err; #line 1255 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; if ((tp_ret = tp_writes(tp, rc->commit_msg)) == -1) goto err; #line 1257 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, "\n")) == -1) goto err; #line 1259 "../gotwebd/pages.tmpl" if (template_flush(tp) == -1) return (-1); for (;;) { r = fread(buf, 1, sizeof(buf), t->fp); if (r == 0) break; w = fcgi_write(c, buf, r); if (w == -1) break; } err: return tp_ret; } #line 1272 "../gotwebd/pages.tmpl" int gotweb_render_rss(struct template *tp) { int tp_ret = 0; #line 1274 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct server *srv = c->srv; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct repo_tag *rt; struct gotweb_url summary = { .action = SUMMARY, .index_page = -1, .path = repo_dir->name, }; #line 1288 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "Tags of ", 138)) == -1) goto err; #line 1288 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->name)) == -1) goto err; #line 1291 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 10)) == -1) goto err; #line 1294 "../gotwebd/pages.tmpl" if (srv->show_repo_description) { if ((tp_ret = tp_write(tp, "", 13)) == -1) goto err; #line 1295 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->description)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 14)) == -1) goto err; } TAILQ_FOREACH(rt, &t->repo_tags, entry) { #line 1298 "../gotwebd/pages.tmpl" if ((tp_ret = rss_tag_item(tp, rt)) == -1) goto err; } #line 1302 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 16)) == -1) goto err; err: return tp_ret; } #line 1304 "../gotwebd/pages.tmpl" int rss_tag_item(struct template *tp, struct repo_tag *rt) { int tp_ret = 0; #line 1306 "../gotwebd/pages.tmpl" struct request *c = tp->tp_arg; struct transport *t = c->t; struct repo_dir *repo_dir = t->repo_dir; struct tm tm; char rfc822[128]; int r; char *tag_name = rt->tag_name; struct gotweb_url tag = { .action = TAG, .index_page = -1, .path = repo_dir->name, .commit = rt->commit_id, }; #line 1320 "../gotwebd/pages.tmpl" if (strncmp(tag_name, "refs/tags/", 10) == 0) tag_name += 10; #line 1323 "../gotwebd/pages.tmpl" if (gmtime_r(&rt->tagger_time, &tm) == NULL) return -1; r = strftime(rfc822, sizeof(rfc822), "%a, %d %b %Y %H:%M:%S GMT", &tm); if (r == 0) return 0; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 13)) == -1) goto err; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, repo_dir->name)) == -1) goto err; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 1330 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, tag_name)) == -1) goto err; #line 1333 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 37)) == -1) goto err; #line 1337 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->tag_commit)) == -1) goto err; #line 1339 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "]]>", 23)) == -1) goto err; #line 1339 "../gotwebd/pages.tmpl" if ((tp_ret = rss_author(tp, rt->tagger)) == -1) goto err; if ((tp_ret = tp_write(tp, "", 26)) == -1) goto err; #line 1340 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rt->commit_id)) == -1) goto err; #line 1342 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 16)) == -1) goto err; #line 1342 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, rfc822)) == -1) goto err; #line 1345 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 17)) == -1) goto err; err: return tp_ret; } #line 1347 "../gotwebd/pages.tmpl" int rss_author(struct template *tp, char *author) { int tp_ret = 0; #line 1349 "../gotwebd/pages.tmpl" char *t, *mail; #line 1351 "../gotwebd/pages.tmpl" /* what to do if the author name contains a paren? */ if (strchr(author, '(') != NULL || strchr(author, ')') != NULL) return 0; #line 1355 "../gotwebd/pages.tmpl" t = strchr(author, '<'); if (t == NULL) return 0; *t = '\0'; mail = t+1; #line 1361 "../gotwebd/pages.tmpl" while (isspace((unsigned char)*--t)) *t = '\0'; #line 1364 "../gotwebd/pages.tmpl" t = strchr(mail, '>'); if (t == NULL) return 0; *t = '\0'; #line 1370 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "", 8)) == -1) goto err; #line 1370 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, mail)) == -1) goto err; #line 1370 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, " ")) == -1) goto err; #line 1370 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "(", 1)) == -1) goto err; #line 1370 "../gotwebd/pages.tmpl" if ((tp_ret = tp_htmlescape(tp, author)) == -1) goto err; #line 1372 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, ")", 10)) == -1) goto err; err: return tp_ret; } #line 1374 "../gotwebd/pages.tmpl" int gotweb_render_unauthorized(struct template *tp) { int tp_ret = 0; #line 1376 "../gotwebd/pages.tmpl" if ((tp_ret = tp_write(tp, "

Wrong or missing authentication code

", 43)) == -1) goto err; err: return tp_ret; } got-portable-0.119/gotwebd/Makefile.am0000664000175000017500000000712715066536113013312 sbin_PROGRAMS = gotwebd include $(top_builddir)/Makefile.common # /home/n6tadam/projects/got/gotwebd/../template/template -o pages.c pages.tmpl BUILT_SOURCES = pages.c CLEANFILES = pages.c parse.c pages.c: $(top_srcdir)/gotwebd/pages.tmpl ${MAKE} -C $(top_builddir)/template $(top_builddir)/template/template -o pages.c $(top_srcdir)/gotwebd/pages.tmpl gotwebd_SOURCES = config.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c \ $(top_srcdir)/template/tmpl.c \ auth.c \ fcgi.c \ got_operations.c \ gotweb.c \ gotwebd.c \ login.c \ pages.c \ parse.y \ sockets.c gotwebd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = $(top_srcdir)/gotwebd/*.h \ $(top_srcdir)/gotwebd/*.tmpl \ $(top_srcdir)/template/tmpl.h \ gotwebd.8 gotwebd.conf.5 man5_MANS = gotwebd.conf.5 man8_MANS = gotwebd.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/template \ -lopenbsd-compat -lm LDADD += $(libbsd_LIBS) \ $(libcrypto_LIBS) \ $(libevent_LIBS) \ $(zlib_LIBS) \ $(libuuid_LIBS) \ $(libutil_LIBS) \ $(libmd_LIBS) if HOST_FREEBSD LDADD += -lmd endif AM_CPPFLAGS += $(libbsd_CFLAGS) \ $(libcrypto_CFLAGS) \ $(libevent_CFLAGS) \ $(zlib_CFLAGS) \ $(libuuid_CFLAGS) \ $(libmd_CFLAGS) #realinstall: # if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \ # fi # ${INSTALL} -c -o root -g daemon -m 0755 ${PROG} ${BINDIR}/${PROG} # if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \ # fi # if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \ # fi # ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ # ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR} # #.include got-portable-0.119/gotwebd/config.c0000664000175000017500000001747115066536113012672 /* * Copyright (c) 2020-2021 Tracey Emery * Copyright (c) 2015 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" int config_init(struct gotwebd *env) { int i; strlcpy(env->httpd_chroot, D_HTTPD_CHROOT, sizeof(env->httpd_chroot)); env->prefork = GOTWEBD_NUMPROC; TAILQ_INIT(&env->servers); TAILQ_INIT(&env->sockets); TAILQ_INIT(&env->addresses); STAILQ_INIT(&env->access_rules); for (i = 0; i < PRIV_FDS__MAX; i++) env->priv_fd[i] = -1; for (i = 0; i < GOTWEB_PACK_NUM_TEMPFILES; i++) env->pack_fds[i] = -1; return 0; } int config_getcfg(struct gotwebd *env, struct imsg *imsg) { /* nothing to do but tell gotwebd configuration is done */ if (sockets_compose_main(env, GOTWEBD_IMSG_CFG_DONE, NULL, 0) == -1) fatal("sockets_compose_main IMSG_CFG_DONE"); return 0; } int config_getserver(struct gotwebd *env, struct imsg *imsg) { struct server *srv; uint8_t *p = imsg->data; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) fatalx("%s: wrong size", __func__); memcpy(srv, p, sizeof(*srv)); STAILQ_INIT(&srv->access_rules); TAILQ_INIT(&srv->repos); /* log server info */ log_debug("%s: server=%s", __func__, srv->name); TAILQ_INSERT_TAIL(&env->servers, srv, entry); return 0; } int config_setsock(struct gotwebd *env, struct socket *sock, uid_t uid, gid_t gid) { /* open listening sockets */ if (sockets_privinit(env, sock, uid, gid) == -1) return -1; if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_SOCK, sock->fd, &sock->conf, sizeof(sock->conf)) == -1) fatal("main_compose_sockets IMSG_CFG_SOCK"); if (main_compose_gotweb(env, GOTWEBD_IMSG_CFG_SOCK, sock->fd, &sock->conf, sizeof(sock->conf)) == -1) fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SOCK"); return 0; } int config_getsock(struct gotwebd *env, struct imsg *imsg) { struct socket *sock = NULL; struct socket_conf sock_conf; uint8_t *p = imsg->data; if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) fatalx("%s: wrong size", __func__); memcpy(&sock_conf, p, sizeof(sock_conf)); if (IMSG_DATA_SIZE(imsg) != sizeof(sock_conf)) { log_warnx("%s: imsg size error", __func__); return 1; } /* create a new socket */ if ((sock = calloc(1, sizeof(*sock))) == NULL) { return 1; } memcpy(&sock->conf, &sock_conf, sizeof(sock->conf)); sock->fd = imsg_get_fd(imsg); TAILQ_INSERT_TAIL(&env->sockets, sock, entry); /* log new socket info */ log_debug("%s: id=%d af_type=%s socket_path=%s", __func__, sock->conf.id, sock->conf.af_type == AF_UNIX ? "unix" : (sock->conf.af_type == AF_INET ? "inet" : (sock->conf.af_type == AF_INET6 ? "inet6" : "unknown")), *sock->conf.unix_socket_name != '\0' ? sock->conf.unix_socket_name : "none"); return 0; } int config_setfd(struct gotwebd *env) { int i, j, fd; log_info("%s: Allocating %d file descriptors", __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES); for (i = 0; i < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; i++) { for (j = 0; j < env->prefork; j++) { fd = got_opentempfd(); if (fd == -1) fatal("got_opentemp"); if (imsg_compose_event(&env->iev_gotweb[j], GOTWEBD_IMSG_CFG_FD, 0, -1, fd, NULL, 0) == -1) fatal("imsg_compose_event GOTWEBD_IMSG_CFG_FD"); if (imsgbuf_flush(&env->iev_gotweb[j].ibuf) == -1) fatal("imsgbuf_flush"); imsg_event_add(&env->iev_gotweb[j]); } } return 0; } int config_getfd(struct gotwebd *env, struct imsg *imsg) { int i; if (imsg_get_len(imsg) != 0) fatalx("%s: wrong size", __func__); for (i = 0; i < nitems(env->priv_fd); ++i) { if (env->priv_fd[i] == -1) { env->priv_fd[i] = imsg_get_fd(imsg); log_debug("%s: assigning priv_fd %d", __func__, env->priv_fd[i]); return 0; } } for (i = 0; i < nitems(env->pack_fds); ++i) { if (env->pack_fds[i] == -1) { env->pack_fds[i] = imsg_get_fd(imsg); log_debug("%s: assigning pack_fd %d", __func__, env->pack_fds[i]); return 0; } } return 1; } void config_set_access_rules(struct imsgev *iev, struct gotwebd_access_rule_list *rules) { struct gotwebd_access_rule *rule; STAILQ_FOREACH(rule, rules, entry) { if (imsg_compose_event(iev, GOTWEBD_IMSG_CFG_ACCESS_RULE, 0, -1, -1, rule, sizeof(*rule)) == -1) fatal("imsg_compose_event " "GOTWEBD_IMSG_CFG_ACCESS_RULE"); } } void config_get_access_rule(struct gotwebd_access_rule_list *rules, struct imsg *imsg) { struct gotwebd_access_rule *rule; size_t len; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("malloc"); if (imsg_get_data(imsg, rule, sizeof(*rule))) fatalx("%s: invalid CFG_ACCESS_RULE message", __func__); switch (rule->access) { case GOTWEBD_ACCESS_DENIED: case GOTWEBD_ACCESS_PERMITTED: break; default: fatalx("%s: invalid CFG_ACCESS_RULE message", __func__); } len = strnlen(rule->identifier, sizeof(rule->identifier)); if (len == 0 || len >= sizeof(rule->identifier)) fatalx("%s: invalid CFG_ACCESS_RULE message", __func__); STAILQ_INSERT_TAIL(rules, rule, entry); } void config_free_access_rules(struct gotwebd_access_rule_list *rules) { struct gotwebd_access_rule *rule; while (!STAILQ_EMPTY(rules)) { rule = STAILQ_FIRST(rules); STAILQ_REMOVE(rules, rule, gotwebd_access_rule, entry); free(rule); } } void config_free_repos(struct gotwebd_repolist *repos) { struct gotwebd_repo *repo; while (!TAILQ_EMPTY(repos)) { repo = TAILQ_FIRST(repos); TAILQ_REMOVE(repos, repo, entry); config_free_access_rules(&repo->access_rules); free(repo); } } void config_set_repository(struct imsgev *iev, struct gotwebd_repo *repo) { if (imsg_compose_event(iev, GOTWEBD_IMSG_CFG_REPO, 0, -1, -1, repo, sizeof(*repo)) == -1) fatal("imsg_compose_event GOTWEBD_IMSG_CFG_REPO"); } void config_get_repository(struct gotwebd_repolist *repos, struct imsg *imsg) { struct gotwebd_repo *repo; size_t len; repo = calloc(1, sizeof(*repo)); if (repo == NULL) fatal("malloc"); if (imsg_get_data(imsg, repo, sizeof(*repo))) fatalx("%s: invalid CFG_REPO message", __func__); switch (repo->auth_config) { case GOTWEBD_AUTH_DISABLED: case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: break; default: fatalx("%s: invalid CFG_REPO message", __func__); } len = strnlen(repo->name, sizeof(repo->name)); if (len == 0 || len >= sizeof(repo->name)) fatalx("%s: invalid CFG_REPO message", __func__); if (strchr(repo->name, '/') != NULL) { fatalx("repository names must not contain slashes: %s", repo->name); } if (strchr(repo->name, '\n') != NULL) { fatalx("repository names must not contain linefeeds: %s", repo->name); } STAILQ_INIT(&repo->access_rules); TAILQ_INSERT_TAIL(repos, repo, entry); } got-portable-0.119/gotwebd/parse.y0000664000175000017500000007447415066536113012573 /* * Copyright (c) 2016-2019, 2020-2021 Tracey Emery * Copyright (c) 2004, 2005 Esben Norby * Copyright (c) 2004 Ryan McBride * Copyright (c) 2002, 2003, 2004 Henning Brauer * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. * Copyright (c) 2001 Theo de Raadt. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ %{ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; int lineno; int errors; } *file; struct file *newfile(const char *, int); static void closefile(struct file *); int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); int lgetc(int); int lungetc(int); int findeol(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { TAILQ_ENTRY(sym) entry; int used; int persist; char *nam; char *val; }; int symset(const char *, const char *, int); char *symget(const char *); static int errors; static struct gotwebd *gotwebd; static struct server *new_srv; static struct server *conf_new_server(const char *); int getservice(const char *); int n; int get_addrs(const char *, const char *); struct address *get_unix_addr(const char *); int addr_dup_check(struct addresslist *, struct address *); void add_addr(struct address *); static struct gotwebd_repo *new_repo; static struct gotwebd_repo *conf_new_repo(struct server *, const char *); static void conf_new_access_rule( struct gotwebd_access_rule_list *, enum gotwebd_access, char *); typedef struct { union { long long number; char *string; } v; int lineno; } YYSTYPE; %} %token LISTEN GOTWEBD_LOGIN WWW SITE_NAME SITE_OWNER SITE_LINK LOGO %token LOGO_URL SHOW_REPO_OWNER SHOW_REPO_AGE SHOW_REPO_DESCRIPTION %token MAX_REPOS_DISPLAY REPOS_PATH MAX_COMMITS_DISPLAY ON ERROR %token SHOW_SITE_OWNER SHOW_REPO_CLONEURL PORT PREFORK RESPECT_EXPORTOK %token SERVER CHROOT CUSTOM_CSS SOCKET %token SUMMARY_COMMITS_DISPLAY SUMMARY_TAGS_DISPLAY USER AUTHENTICATION %token ENABLE DISABLE INSECURE REPOSITORY PERMIT DENY %token STRING %token NUMBER %type boolean %type listen_addr %type numberstring %% grammar : /* empty */ | grammar '\n' | grammar varset '\n' | grammar main '\n' | grammar server '\n' | grammar error '\n' { file->errors++; } ; varset : STRING '=' STRING { char *s = $1; while (*s++) { if (isspace((unsigned char)*s)) { yyerror("macro name cannot contain " "whitespace"); free($1); free($3); YYERROR; } } if (symset($1, $3, 0) == -1) fatal("cannot store variable"); free($1); free($3); } ; numberstring : STRING | NUMBER { if (asprintf(&$$, "%lld", (long long)$1) == -1) { yyerror("asprintf: %s", strerror(errno)); YYERROR; } } ; boolean : STRING { if (strcasecmp($1, "1") == 0 || strcasecmp($1, "on") == 0) $$ = 1; else if (strcasecmp($1, "0") == 0 || strcasecmp($1, "off") == 0) $$ = 0; else { yyerror("invalid boolean value '%s'", $1); free($1); YYERROR; } free($1); } | ON { $$ = 1; } | NUMBER { if ($1 != 0 && $1 != 1) { yyerror("invalid boolean value '%lld'", $1); YYERROR; } $$ = $1; } ; listen_addr : '*' { $$ = NULL; } | STRING ; main : PREFORK NUMBER { if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) { yyerror("prefork is %s: %lld", $2 <= 0 ? "too small" : "too large", $2); YYERROR; } gotwebd->prefork = $2; } | CHROOT STRING { if (*$2 == '\0') { yyerror("chroot path can't be an empty" " string"); free($2); YYERROR; } n = strlcpy(gotwebd->httpd_chroot, $2, sizeof(gotwebd->httpd_chroot)); if (n >= sizeof(gotwebd->httpd_chroot)) { yyerror("chroot path too long: %s", $2); free($2); YYERROR; } if (gotwebd->httpd_chroot[0] != '/') { yyerror("chroot path must be an absolute path: " "bad path %s", gotwebd->httpd_chroot); free($2); YYERROR; } free($2); } | LISTEN ON listen_addr PORT STRING { if (get_addrs($3, $5) == -1) { yyerror("could not get addrs"); YYERROR; } free($3); free($5); } | LISTEN ON listen_addr PORT NUMBER { char portno[32]; int n; n = snprintf(portno, sizeof(portno), "%lld", (long long)$5); if (n < 0 || (size_t)n >= sizeof(portno)) fatalx("port number too long: %lld", (long long)$5); if (get_addrs($3, portno) == -1) { yyerror("could not get addrs"); YYERROR; } free($3); } | LISTEN ON SOCKET STRING { struct address *h; h = get_unix_addr($4); if (h == NULL) { yyerror("can't listen on %s", $4); free($4); YYERROR; } add_addr(h); free($4); } | USER STRING { if (gotwebd->user != NULL) yyerror("user already specified"); free(gotwebd->user); gotwebd->user = $2; } | WWW USER STRING { if (gotwebd->www_user != NULL) yyerror("www user already specified"); free(gotwebd->www_user); gotwebd->www_user = $3; } | DISABLE AUTHENTICATION { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_DISABLED; } | ENABLE AUTHENTICATION { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_SECURE; } | ENABLE AUTHENTICATION INSECURE { if (gotwebd->auth_config != 0) { yyerror("ambiguous global authentication " "setting"); YYERROR; } gotwebd->auth_config = GOTWEBD_AUTH_INSECURE; } | PERMIT numberstring { conf_new_access_rule(&gotwebd->access_rules, GOTWEBD_ACCESS_PERMITTED, $2); } | DENY numberstring { conf_new_access_rule(&gotwebd->access_rules, GOTWEBD_ACCESS_DENIED, $2); } | GOTWEBD_LOGIN SOCKET STRING { struct address *h; h = get_unix_addr($3); if (h == NULL) { yyerror("can't listen on %s", $3); free($3); YYERROR; } if (gotwebd->login_sock != NULL) free(gotwebd->login_sock); gotwebd->login_sock = sockets_conf_new_socket(-1, h); free($3); } ; server : SERVER STRING { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, $2) == 0) { yyerror("server name exists '%s'", $2); free($2); YYERROR; } } new_srv = conf_new_server($2); log_debug("adding server %s", $2); free($2); } | SERVER STRING { struct server *srv; TAILQ_FOREACH(srv, &gotwebd->servers, entry) { if (strcmp(srv->name, $2) == 0) { yyerror("server name exists '%s'", $2); free($2); YYERROR; } } new_srv = conf_new_server($2); log_debug("adding server %s", $2); free($2); } '{' optnl serveropts2 '}' { } ; serveropts1 : REPOS_PATH STRING { n = strlcpy(new_srv->repos_path, $2, sizeof(new_srv->repos_path)); if (n >= sizeof(new_srv->repos_path)) { yyerror("%s: repos_path truncated", __func__); free($2); YYERROR; } free($2); } | SITE_NAME STRING { n = strlcpy(new_srv->site_name, $2, sizeof(new_srv->site_name)); if (n >= sizeof(new_srv->site_name)) { yyerror("%s: site_name truncated", __func__); free($2); YYERROR; } free($2); } | SITE_OWNER STRING { n = strlcpy(new_srv->site_owner, $2, sizeof(new_srv->site_owner)); if (n >= sizeof(new_srv->site_owner)) { yyerror("%s: site_owner truncated", __func__); free($2); YYERROR; } free($2); } | SITE_LINK STRING { n = strlcpy(new_srv->site_link, $2, sizeof(new_srv->site_link)); if (n >= sizeof(new_srv->site_link)) { yyerror("%s: site_link truncated", __func__); free($2); YYERROR; } free($2); } | LOGO STRING { n = strlcpy(new_srv->logo, $2, sizeof(new_srv->logo)); if (n >= sizeof(new_srv->logo)) { yyerror("%s: logo truncated", __func__); free($2); YYERROR; } free($2); } | LOGO_URL STRING { n = strlcpy(new_srv->logo_url, $2, sizeof(new_srv->logo_url)); if (n >= sizeof(new_srv->logo_url)) { yyerror("%s: logo_url truncated", __func__); free($2); YYERROR; } free($2); } | CUSTOM_CSS STRING { n = strlcpy(new_srv->custom_css, $2, sizeof(new_srv->custom_css)); if (n >= sizeof(new_srv->custom_css)) { yyerror("%s: custom_css truncated", __func__); free($2); YYERROR; } free($2); } | SHOW_SITE_OWNER boolean { new_srv->show_site_owner = $2; } | SHOW_REPO_OWNER boolean { new_srv->show_repo_owner = $2; } | SHOW_REPO_AGE boolean { new_srv->show_repo_age = $2; } | SHOW_REPO_DESCRIPTION boolean { new_srv->show_repo_description = $2; } | SHOW_REPO_CLONEURL boolean { new_srv->show_repo_cloneurl = $2; } | RESPECT_EXPORTOK boolean { new_srv->respect_exportok = $2; } | MAX_REPOS_DISPLAY NUMBER { if ($2 < 0) { yyerror("max_repos_display is too small: %lld", $2); YYERROR; } new_srv->max_repos_display = $2; } | MAX_COMMITS_DISPLAY NUMBER { if ($2 <= 1) { yyerror("max_commits_display is too small:" " %lld", $2); YYERROR; } new_srv->max_commits_display = $2; } | SUMMARY_COMMITS_DISPLAY NUMBER { if ($2 < 1) { yyerror("summary_commits_display is too small:" " %lld", $2); YYERROR; } new_srv->summary_commits_display = $2; } | SUMMARY_TAGS_DISPLAY NUMBER { if ($2 < 1) { yyerror("summary_tags_display is too small:" " %lld", $2); YYERROR; } new_srv->summary_tags_display = $2; } | DISABLE AUTHENTICATION { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_DISABLED; } | ENABLE AUTHENTICATION { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_SECURE; } | ENABLE AUTHENTICATION INSECURE { if (new_srv->auth_config != 0) { yyerror("ambiguous authentication " "setting for server %s", new_srv->name); YYERROR; } new_srv->auth_config = GOTWEBD_AUTH_INSECURE; } | PERMIT numberstring { conf_new_access_rule(&new_srv->access_rules, GOTWEBD_ACCESS_PERMITTED, $2); } | DENY numberstring { conf_new_access_rule(&new_srv->access_rules, GOTWEBD_ACCESS_DENIED, $2); } | repository ; serveropts2 : serveropts2 serveropts1 nl | serveropts1 optnl ; repository : REPOSITORY STRING { struct gotwebd_repo *repo; TAILQ_FOREACH(repo, &new_srv->repos, entry) { if (strcmp(repo->name, $2) == 0) { yyerror("duplicate repository " "'%s' in server '%s'", $2, new_srv->name); free($2); YYERROR; } } new_repo = conf_new_repo(new_srv, $2); free($2); } '{' optnl repoopts2 '}' { } ; repoopts2 : repoopts2 repoopts1 nl | repoopts1 optnl ; repoopts1 : DISABLE AUTHENTICATION { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_DISABLED; } | ENABLE AUTHENTICATION { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_SECURE; } | ENABLE AUTHENTICATION INSECURE { if (new_repo->auth_config != 0) { yyerror("ambiguous authentication " "setting for repository %s", new_repo->name); YYERROR; } new_repo->auth_config = GOTWEBD_AUTH_INSECURE; } | PERMIT numberstring { conf_new_access_rule(&new_repo->access_rules, GOTWEBD_ACCESS_PERMITTED, $2); } | DENY numberstring { conf_new_access_rule(&new_repo->access_rules, GOTWEBD_ACCESS_DENIED, $2); } ; nl : '\n' optnl ; optnl : '\n' optnl /* zero or more newlines */ | /* empty */ ; %% struct keywords { const char *k_name; int k_val; }; int yyerror(const char *fmt, ...) { va_list ap; char *msg; file->errors++; va_start(ap, fmt); if (vasprintf(&msg, fmt, ap) == -1) fatalx("yyerror vasprintf"); va_end(ap); logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); free(msg); return (0); } int kw_cmp(const void *k, const void *e) { return (strcmp(k, ((const struct keywords *)e)->k_name)); } int lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { { "authentication", AUTHENTICATION }, { "chroot", CHROOT }, { "custom_css", CUSTOM_CSS }, { "deny", DENY }, { "disable", DISABLE }, { "enable", ENABLE }, { "insecure", INSECURE }, { "listen", LISTEN }, { "login", GOTWEBD_LOGIN }, { "logo", LOGO }, { "logo_url", LOGO_URL }, { "max_commits_display", MAX_COMMITS_DISPLAY }, { "max_repos_display", MAX_REPOS_DISPLAY }, { "on", ON }, { "permit", PERMIT }, { "port", PORT }, { "prefork", PREFORK }, { "repos_path", REPOS_PATH }, { "repository", REPOSITORY }, { "respect_exportok", RESPECT_EXPORTOK }, { "server", SERVER }, { "show_repo_age", SHOW_REPO_AGE }, { "show_repo_cloneurl", SHOW_REPO_CLONEURL }, { "show_repo_description", SHOW_REPO_DESCRIPTION }, { "show_repo_owner", SHOW_REPO_OWNER }, { "show_site_owner", SHOW_SITE_OWNER }, { "site_link", SITE_LINK }, { "site_name", SITE_NAME }, { "site_owner", SITE_OWNER }, { "socket", SOCKET }, { "summary_commits_display", SUMMARY_COMMITS_DISPLAY }, { "summary_tags_display", SUMMARY_TAGS_DISPLAY }, { "user", USER }, { "www", WWW }, }; const struct keywords *p; p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), sizeof(keywords[0]), kw_cmp); if (p) return (p->k_val); else return (STRING); } #define MAXPUSHBACK 128 unsigned char *parsebuf; int parseindex; unsigned char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int lgetc(int quotec) { int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ if (parseindex >= 0) { c = parsebuf[parseindex++]; if (c != '\0') return (c); parsebuf = NULL; } else parseindex++; } if (pushback_index) return (pushback_buffer[--pushback_index]); if (quotec) { c = getc(file->stream); if (c == EOF) yyerror("reached end of file while parsing " "quoted string"); return (c); } c = getc(file->stream); while (c == '\\') { next = getc(file->stream); if (next != '\n') { c = next; break; } yylval.lineno = file->lineno; file->lineno++; c = getc(file->stream); } return (c); } int lungetc(int c) { if (c == EOF) return (EOF); if (parsebuf) { parseindex--; if (parseindex >= 0) return (c); } if (pushback_index < MAXPUSHBACK-1) return (pushback_buffer[pushback_index++] = c); else return (EOF); } int findeol(void) { int c; parsebuf = NULL; /* Skip to either EOF or the first real EOL. */ while (1) { if (pushback_index) c = pushback_buffer[--pushback_index]; else c = lgetc(0); if (c == '\n') { file->lineno++; break; } if (c == EOF) break; } return (ERROR); } int yylex(void) { unsigned char buf[8096]; unsigned char *p, *val; int quotec, next, c; int token; top: p = buf; c = lgetc(0); while (c == ' ' || c == '\t') c = lgetc(0); /* nothing */ yylval.lineno = file->lineno; if (c == '#') { c = lgetc(0); while (c != '\n' && c != EOF) c = lgetc(0); /* nothing */ } if (c == '$' && parsebuf == NULL) { while (1) { c = lgetc(0); if (c == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } if (isalnum(c) || c == '_') { *p++ = c; continue; } *p = '\0'; lungetc(c); break; } val = symget(buf); if (val == NULL) { yyerror("macro '%s' not defined", buf); return (findeol()); } parsebuf = val; parseindex = 0; goto top; } switch (c) { case '\'': case '"': quotec = c; while (1) { c = lgetc(quotec); if (c == EOF) return (0); if (c == '\n') { file->lineno++; continue; } else if (c == '\\') { next = lgetc(quotec); if (next == EOF) return (0); if (next == quotec || c == ' ' || c == '\t') c = next; else if (next == '\n') { file->lineno++; continue; } else lungetc(next); } else if (c == quotec) { *p = '\0'; break; } else if (c == '\0') { yyerror("syntax error"); return (findeol()); } if (p + 1 >= buf + sizeof(buf) - 1) { yyerror("string too long"); return (findeol()); } *p++ = c; } yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); return (STRING); } #define allowed_to_end_number(x) \ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') if (c == '-' || isdigit(c)) { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && isdigit(c)); lungetc(c); if (p == buf + 1 && buf[0] == '-') goto nodigits; if (c == EOF || allowed_to_end_number(c)) { const char *errstr = NULL; *p = '\0'; yylval.v.number = strtonum(buf, LLONG_MIN, LLONG_MAX, &errstr); if (errstr) { yyerror("\"%s\" invalid number: %s", buf, errstr); return (findeol()); } return (NUMBER); } else { nodigits: while (p > buf + 1) lungetc(*--p); c = *--p; if (c == '-') return (c); } } #define allowed_in_string(x) \ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ x != '{' && x != '}' && \ x != '!' && x != '=' && x != '#' && \ x != ',')) if (isalnum(c) || c == ':' || c == '_') { do { *p++ = c; if ((unsigned)(p-buf) >= sizeof(buf)) { yyerror("string too long"); return (findeol()); } c = lgetc(0); } while (c != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; token = lookup(buf); if (token == STRING) { yylval.v.string = strdup(buf); if (yylval.v.string == NULL) err(1, "yylex: strdup"); } return (token); } if (c == '\n') { yylval.lineno = file->lineno; file->lineno++; } if (c == EOF) return (0); return (c); } int check_file_secrecy(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) { log_warn("cannot stat %s", fname); return (-1); } if (st.st_uid != 0 && st.st_uid != getuid()) { log_warnx("%s: owner not root or current user", fname); return (-1); } if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { log_warnx("%s: group writable or world read/writable", fname); return (-1); } return (0); } struct file * newfile(const char *name, int secret) { struct file *nfile; nfile = calloc(1, sizeof(struct file)); if (nfile == NULL) { log_warn("calloc"); return (NULL); } nfile->name = strdup(name); if (nfile->name == NULL) { log_warn("strdup"); free(nfile); return (NULL); } nfile->stream = fopen(nfile->name, "r"); if (nfile->stream == NULL) { /* no warning, we don't require a conf file */ free(nfile->name); free(nfile); return (NULL); } else if (secret && check_file_secrecy(fileno(nfile->stream), nfile->name)) { fclose(nfile->stream); free(nfile->name); free(nfile); return (NULL); } nfile->lineno = 1; return (nfile); } static void closefile(struct file *xfile) { fclose(xfile->stream); free(xfile->name); free(xfile); } static void add_default_server(void) { new_srv = conf_new_server(D_SITENAME); log_debug("%s: adding default server %s", __func__, D_SITENAME); } int parse_config(const char *filename, struct gotwebd *env) { struct sym *sym, *next; struct server *srv; struct gotwebd_repo *repo; if (config_init(env) == -1) fatalx("failed to initialize configuration"); gotwebd = env; file = newfile(filename, 0); if (file != NULL) { /* we don't require a config file */ yyparse(); errors = file->errors; closefile(file); } /* Free macros and check which have not been used. */ TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { if ((gotwebd->gotwebd_verbose > 1) && !sym->used) fprintf(stderr, "warning: macro '%s' not used\n", sym->nam); if (!sym->persist) { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } /* just add default server if no config specified */ if (TAILQ_EMPTY(&gotwebd->servers)) add_default_server(); /* add the implicit listen on socket */ if (TAILQ_EMPTY(&gotwebd->addresses)) { char path[_POSIX_PATH_MAX]; struct address *h; if (strlcpy(path, gotwebd->httpd_chroot, sizeof(path)) >= sizeof(path)) { yyerror("chroot path too long: %s", gotwebd->httpd_chroot); } if (strlcat(path, D_UNIX_SOCKET, sizeof(path)) >= sizeof(path)) { yyerror("chroot path too long: %s", gotwebd->httpd_chroot); } h = get_unix_addr(path); if (h == NULL) yyerror("can't listen on %s", path); else add_addr(h); } if (errors) return (-1); /* setup our listening sockets */ sockets_parse_sockets(env); /* Add implicit login socket */ if (gotwebd->login_sock == NULL) { struct address *h; h = get_unix_addr(GOTWEBD_LOGIN_SOCKET); if (h == NULL) { fprintf(stderr, "cannot listen on %s", GOTWEBD_LOGIN_SOCKET); return (-1); } gotwebd->login_sock = sockets_conf_new_socket(-1, h); } /* Enable authentication if not explicitly configured. */ switch (env->auth_config) { case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: case GOTWEBD_AUTH_DISABLED: break; default: env->auth_config = GOTWEBD_AUTH_SECURE; break; } /* Inherit implicit authentication config from parent scope. */ TAILQ_FOREACH(srv, &env->servers, entry) { if (srv->auth_config == 0) srv->auth_config = env->auth_config; TAILQ_FOREACH(repo, &srv->repos, entry) { if (repo->auth_config == 0) repo->auth_config = srv->auth_config; } } return (0); } struct server * conf_new_server(const char *name) { struct server *srv = NULL; srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); n = strlcpy(srv->name, name, sizeof(srv->name)); if (n >= sizeof(srv->name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->repos_path, gotwebd->httpd_chroot, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcpy", __func__); n = strlcat(srv->repos_path, D_GOTPATH, sizeof(srv->repos_path)); if (n >= sizeof(srv->repos_path)) fatalx("%s: strlcat", __func__); n = strlcpy(srv->site_name, D_SITENAME, sizeof(srv->site_name)); if (n >= sizeof(srv->site_name)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_owner, D_SITEOWNER, sizeof(srv->site_owner)); if (n >= sizeof(srv->site_owner)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->site_link, D_SITELINK, sizeof(srv->site_link)); if (n >= sizeof(srv->site_link)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo, D_GOTLOGO, sizeof(srv->logo)); if (n >= sizeof(srv->logo)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->logo_url, D_GOTURL, sizeof(srv->logo_url)); if (n >= sizeof(srv->logo_url)) fatalx("%s: strlcpy", __func__); n = strlcpy(srv->custom_css, D_GOTWEBCSS, sizeof(srv->custom_css)); if (n >= sizeof(srv->custom_css)) fatalx("%s: strlcpy", __func__); srv->show_site_owner = D_SHOWSOWNER; srv->show_repo_owner = D_SHOWROWNER; srv->show_repo_age = D_SHOWAGE; srv->show_repo_description = D_SHOWDESC; srv->show_repo_cloneurl = D_SHOWURL; srv->respect_exportok = D_RESPECTEXPORTOK; srv->max_repos_display = D_MAXREPODISP; srv->max_commits_display = D_MAXCOMMITDISP; srv->summary_commits_display = D_MAXSLCOMMDISP; srv->summary_tags_display = D_MAXSLTAGDISP; STAILQ_INIT(&srv->access_rules); TAILQ_INIT(&srv->repos); TAILQ_INSERT_TAIL(&gotwebd->servers, srv, entry); return srv; }; int symset(const char *nam, const char *val, int persist) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) break; } if (sym != NULL) { if (sym->persist == 1) return (0); else { free(sym->nam); free(sym->val); TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } sym = calloc(1, sizeof(*sym)); if (sym == NULL) return (-1); sym->nam = strdup(nam); if (sym->nam == NULL) { free(sym); return (-1); } sym->val = strdup(val); if (sym->val == NULL) { free(sym->nam); free(sym); return (-1); } sym->used = 0; sym->persist = persist; TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } int cmdline_symset(char *s) { char *sym, *val; int ret; val = strrchr(s, '='); if (val == NULL) return (-1); sym = strndup(s, val - s); if (sym == NULL) fatal("%s: strndup", __func__); ret = symset(sym, val + 1, 1); free(sym); return (ret); } char * symget(const char *nam) { struct sym *sym; TAILQ_FOREACH(sym, &symhead, entry) { if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); } } return (NULL); } int get_addrs(const char *hostname, const char *servname) { struct addrinfo hints, *res0, *res; int error; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct address *h; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; error = getaddrinfo(hostname, servname, &hints, &res0); if (error) { log_warnx("%s: could not parse \"%s:%s\": %s", __func__, hostname, servname, gai_strerror(error)); return (-1); } for (res = res0; res; res = res->ai_next) { if ((h = calloc(1, sizeof(*h))) == NULL) fatal(__func__); if (hostname == NULL) { strlcpy(h->ifname, "*", sizeof(h->ifname)); } else { if (strlcpy(h->ifname, hostname, sizeof(h->ifname)) >= sizeof(h->ifname)) { log_warnx("%s: address truncated: %s", __func__, hostname); freeaddrinfo(res0); free(h); return (-1); } } h->ai_family = res->ai_family; h->ai_socktype = res->ai_socktype; h->ai_protocol = res->ai_protocol; memcpy(&h->ss, res->ai_addr, res->ai_addrlen); h->slen = res->ai_addrlen; switch (res->ai_family) { case AF_INET: sin = (struct sockaddr_in *)res->ai_addr; h->port = ntohs(sin->sin_port); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)res->ai_addr; h->port = ntohs(sin6->sin6_port); break; default: fatalx("unknown address family %d", res->ai_family); } add_addr(h); } freeaddrinfo(res0); return (0); } struct address * get_unix_addr(const char *path) { struct address *h; struct sockaddr_un *sun; if ((h = calloc(1, sizeof(*h))) == NULL) fatal("%s: calloc", __func__); h->ai_family = AF_UNIX; h->ai_socktype = SOCK_STREAM; h->ai_protocol = PF_UNSPEC; h->slen = sizeof(*sun); sun = (struct sockaddr_un *)&h->ss; sun->sun_family = AF_UNIX; if (strlcpy(sun->sun_path, path, sizeof(sun->sun_path)) >= sizeof(sun->sun_path)) { log_warnx("socket path too long: %s", sun->sun_path); return NULL; } return h; } int addr_dup_check(struct addresslist *al, struct address *h) { struct address *a; TAILQ_FOREACH(a, al, entry) { if (a->ai_family != h->ai_family || a->ai_socktype != h->ai_socktype || a->ai_protocol != h->ai_protocol || a->slen != h->slen || memcmp(&a->ss, &h->ss, a->slen) != 0) continue; return -1; } return 0; } void add_addr(struct address *h) { if (addr_dup_check(&gotwebd->addresses, h) == 0) { TAILQ_INSERT_TAIL(&gotwebd->addresses, h, entry); return; } free(h); } struct gotwebd_repo * gotwebd_new_repo(const char *name) { struct gotwebd_repo *repo; repo = calloc(1, sizeof(*repo)); if (repo == NULL) return NULL; STAILQ_INIT(&repo->access_rules); if (strlcpy(repo->name, name, sizeof(repo->name)) >= sizeof(repo->name)) { free(repo); errno = ENOSPC; return NULL; } return repo; } static struct gotwebd_repo * conf_new_repo(struct server *server, const char *name) { struct gotwebd_repo *repo; if (name[0] == '\0') { fatalx("syntax error: empty repository name found in %s", file->name); } if (strchr(name, '/') != NULL) fatalx("repository names must not contain slashes: %s", name); if (strchr(name, '\n') != NULL) fatalx("repository names must not contain linefeeds: %s", name); repo = gotwebd_new_repo(name); if (repo == NULL) fatal("gotwebd_new_repo"); TAILQ_INSERT_TAIL(&server->repos, repo, entry); return repo; }; static void conf_new_access_rule(struct gotwebd_access_rule_list *rules, enum gotwebd_access access, char *identifier) { struct gotwebd_access_rule *rule; rule = calloc(1, sizeof(*rule)); if (rule == NULL) fatal("calloc"); rule->access = access; if (strlcpy(rule->identifier, identifier, sizeof(rule->identifier)) >= sizeof(rule->identifier)) fatalx("identifier too long (max %zu bytes): %s", sizeof(rule->identifier) - 1, identifier); STAILQ_INSERT_TAIL(rules, rule, entry); } got-portable-0.119/gotwebd/gotwebd.conf.50000664000175000017500000003170615066535721013727 .\" .\" Copyright (c) 2020 Tracey Emery .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTWEBD.CONF 5 .Os .Sh NAME .Nm gotwebd.conf .Nd gotwebd configuration file .Sh DESCRIPTION .Nm is the run-time configuration file for .Xr gotwebd 8 . .Pp The file format is line-based, with one configuration directive per line. Comments can be put anywhere in the file using a hash mark .Pq Sq # , and extend to the end of the current line. Arguments names not beginning with a letter, digit or underscore, as well as reserved words .Pq such as Ic listen , Ic server No or Ic user , must be quoted. Arguments containing whitespace should be surrounded by double quotes .Pq \&" . .Pp Macros can be defined that are later expanded in context. Macro names must start with a letter, digit, or underscore, and may contain any of those characters, but may not be reserved words. Macros are not expanded inside quotes. For example: .Bd -literal -offset indent lan_addr = "192.168.0.1" listen on $lan_addr port 9090 .Ed .Sh GLOBAL CONFIGURATION The available global configuration directives are as follows: .Bl -tag -width Ds .It Ic chroot Ar path Set the path to the .Xr chroot 2 environment of .Xr httpd 8 . If not specified, it defaults to .Pa /var/www , the home directory of the www user. Setting the .Ar path to .Pa / effectively disables chroot. .It Ic disable authentication Disable authentication, allowing any browser to view any repository not hidden via the .Ic respect_exportok directive. Authentication can also be configured on a per-server or per-repository basis. .It Ic enable authentication Oo Ic insecure Oc Enable authentication, requiring browsers to present a login token cookie before read-only repository access is granted. Authentication can also be configured on a per-server or per-repository basis. .Pp Browsers presenting a valid login token cookie will be mapped to the user account which obtained the login token over SSH from the .Cm weblogin command of .Xr gotsh 1 . .Pp Unauthenticated browsers will be mapped to the user account which runs .Xr httpd 8 . This user account can be set with the .Ic www user directive. Attempts to read repositories as this user will be denied unless authentication is disabled for the repository. .Pp Unless the .Ic insecure keyword is used, the login token cookie will be marked as .Dq Secure , which causes browsers to only send the cookie when connected to the web server over a TLS connection. .It Ic listen on Ar address Ic port Ar number Configure an address and port for incoming FastCGI connections. Valid .Ar address arguments are hostnames, IPv4 and IPv6 addresses. The .Ar port argument may be number or a service name defined in .Xr services 5 . May be specified multiple times to build up a list of listening sockets. .It Ic listen on socket Ar path Configure a .Ux Ns -domain socket for incoming FastCGI connections. May be specified multiple times to build up a list of listening sockets. .Pp While the specified .Ar path must be absolute, it should usually point inside the web server's chroot directory such that the web server can access the socket. .It Ic login socket Ar path Set the .Ar path to the .Ux Ns -domain socket for .Xr gotsh 1 .Ic weblogin commands. By default the path .Pa /var/run/gotweb-login.sock will be used. .It Ic prefork Ar number Spawn enough processes such that .Ar number requests can be handled in parallel. By default, .Xr gotwebd 8 will handle up to 3 requests in parallel. The maximum allowed is 32. .It Ic user Ar user Set the .Ar user which will run .Xr gotwebd 8 . If not specified, the user _gotwebd will be used. .It Ic www user Ar user Set the .Ar user which runs .Xr httpd 8 . Needed to ensure that the web server can access .Ux Ns -domain sockets created by .Xr gotwebd 8 . If not specified, the user www will be used. .El .Pp If no .Ic listen directive is used, .Xr gotwebd 8 will listen on the .Ux Ns -domain socket at .Pa /var/www/run/gotweb.sock . .Sh SERVER CONFIGURATION At least one server context must exist for .Xr gotwebd 8 to function. In case no server context is defined in the configuration file, a default server context will be used which uses default parameters for all applicable settings. .Pp A server context is declared with a unique .Ar name , followed by server-specific configuration directives inside curly braces: .Pp .Ic server Ar name Brq ... .Pp If more than one server is defined, each .Ar name should match the hostname which browsers use to reach the corresponding server. The first server defined is used if the requested hostname is not matched by any server block. .Pp The available server configuration directives are as follows: .Bl -tag -width Ds .It Ic custom_css Ar path Set the path to a custom Cascading Style Sheet (CSS) to be used. If this option is not specified then the default style sheet .Sq gotweb.css will be used. .Pp This path must be valid in the web server's URL space since browsers will attempt to fetch it. .It Ic logo Ar path Set the path to an image file containing a logo to be displayed. Defaults to .Sq got.png . .Pp This path must be valid in the web server's URL space since browsers will attempt to fetch it. .It Ic disable authentication Disable authentication for this server, allowing any browser to view any repository not hidden via the .Ic respect_exportok directive. Authentication can also configured on a per-repository basis. .Pp If not specified, the global configuration context determines whether authentication is disabled. .It Ic enable authentication Oo Ic insecure Oc Enable authentication, requiring browsers to present a login token cookie before read-only repository access is granted. Authentication can also configured on a per-repository basis. .Pp If not specified, the global configuration context determines whether authentication is enabled. .It Ic logo_url Ar url Set a hyperlink for the logo. Defaults to .Lk https://gameoftrees.org . .It Ic max_commits_display Ar number Set the maximum amount of commits and tags displayed per page. Defaults to 25. .It Ic max_repos_display Ar number Set the maximum amount of repositories displayed on the index screen. Defaults to 25. Set to zero to show all the repositories without pagination. .It Ic repos_path Ar path Set the path to the directory which contains Git repositories that the server should publish. This path is absolute. Repositories can be served even if they reside outside the web server's chroot directory. .Pp Defaults to .Pa /got/public inside the web server's chroot directory. The .Cm chroot directive must be used before the server declaration in order to take effect. .It Ic repository Ar name Brq ... Set options which apply to a particular repository served by this server. .Pp A repository context is declared with a unique .Ar name , followed by repository-specific configuration directives inside curly braces. .Pp The repository will be looked up within the server's .Ar repos_path , where the directory .Ar name can exist with or without a .Dq .git suffix. .Pp For each repository, access rules can be configured using the .Ic permit and .Ic deny configuration directives. Multiple access rules can be specified, and the last matching rule determines the action taken. .Pp If no access rules are set in a repository context, or if a repository exists in the server's .Ar repos_path without being mentioned in .Nm at all, then the access rules set in the server and global configuration contexts apply. If no rule matches then the repository will be inaccessible if authentication is enabled. .Pp The available repository configuration directives are as follows: .Bl -tag -width Ds .It Ic deny Ar identity Deny repository access to users with the username .Ar identity . Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic permit Ar identity Permit repository access to users with the username .Ar identity . Group names may be matched by prepending a colon .Pq Sq \&: to .Ar identity . Numeric IDs are also accepted. .It Ic disable authentication Disable authentication, allowing any browser to view the repository. Any access rules configured with .Ic permit or .Ic deny directives for this repository will be ignored. .Pp If not specified, the server context or global context determines whether authentication is disabled. .It Ic enable authentication Oo Ic insecure Oc Enable authentication, requiring browsers to present a login token cookie before read-only repository access is granted. .Pp If not specified, the server context or global context determines whether authentication is enabled. .El .It Ic respect_exportok Ar on | off Set whether to display the repository only if it contains the magic .Pa git-daemon-export-ok file, regardless of whether authentication is enabled and has failed or succeeded. Disabled by default. .It Ic show_repo_age Ar on | off Toggle display of last repository modification date. Enabled by default. .It Ic show_repo_cloneurl Ar on | off Toggle display of clone URLs for a repository. This requires the creation of a .Pa cloneurl file inside the repository which contains one URL per line. Enabled by default. .It Ic show_repo_description Ar on | off Toggle display of the repository description. Enabled by default. The .Pa description file in the repository should be updated with an appropriate description. .It Ic show_repo_owner Ar on | off Set whether to display the repository owner. Enabled by default. This requires the creation of an .Pa owner file in the repository or adding an .Sq owner field under the [gotweb] or [gitweb] section in the .Pa config file inside the repository. For example: .Bd -literal -offset indent [gotweb] owner = "Your Name" .Ed .Pp The .Pa owner file has priority over the .Pa config if present. .It Ic site_link Ar string Set the displayed site link name for the index page. Defaults to .Sq Repos . .It Ic site_name Ar string Set the displayed site name title. Defaults to .Sq Gotweb . .It Ic site_owner Ar string Set the displayed site owner. Defaults to .Sq Got Owner . .It Ic show_site_owner Ar on | off Toggle display of the site owner. Enabled by default. .It Ic summary_commits_display Ar number The maximum number of commits to show in the summary page. Defaults to 10. .It Ic summary_tags_display Ar number The maximum number of tags to show in the summary page. Defaults to 3. .El .Sh FILES .Bl -tag -width Ds -compact .It Pa /etc/gotwebd.conf Default location of the .Nm configuration file. .It Pa /var/www/run/gotweb.sock Default location for the .Xr gotwebd 8 .Ux Ns -domain socket. .El .Sh EXAMPLES A sample configuration which allows public browsing: .Bd -literal -offset indent www user "www" # www username needs quotes since www is a keyword server "localhost" { site_name "my public repos" site_owner "Flan Hacker" site_link "Flan' Projects" disable authentication } .Ed .Pp Another example, this time listening on a local port instead of the implicit .Ux Ns -domain socket, and serving repositories located outside the web server's chroot: .Bd -literal -offset indent listen on 127.0.0.1 port 9000 listen on ::1 port 9000 server "localhost" { site_name "my public repos" repos_path "/var/git" disable authentication } .Ed .Pp The following example illustrates the use of directives related to authentication: .Bd -literal -offset indent # 3 scopes: global, per-server, per-repository disable authentication # override the default which is 'enable' # Allow user "admin" to read anything unless overridden with a # "deny" rule later. permit "admin" server "public.example.com" { # inherit global default, i.e. authentication is disabled repos_path "/var/www/got/public" } server "secure.example.com" { enable authentication # override global default permit flan_squee # grant access to flan_squee permit :developers # grant access to developers group repos_path "/var/git" repository "got" { # /var/git/got and /var/git/got.git # Grant access to users who have authenticated as # the anonymous user to gotsh(1), which anyone with # an SSH client sbould be able to do. # Dumb web crawlers will remain locked out. permit anonymous } repository "public" { # As an exception, allow any web browsers and # web crawlers to view this repository. disable authentication } repository "secret" { deny admin # not even the admin can read this } } .Ed .Sh SEE ALSO .Xr got 1 , .Xr httpd.conf 5 , .Xr services 5 , .Xr gotwebd 8 , .Xr httpd 8 got-portable-0.119/gotwebd/gotwebd.c0000664000175000017500000006577415066536113013071 /* * Copyright (c) 2016, 2019, 2020-2021 Tracey Emery * Copyright (c) 2015 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "got_opentemp.h" #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" __dead void usage(void); int main(int, char **); int gotwebd_configure(struct gotwebd *, uid_t, gid_t); void gotwebd_configure_done(struct gotwebd *); void gotwebd_sighdlr(int sig, short event, void *arg); void gotwebd_shutdown(void); void gotwebd_dispatch_server(int, short, void *); void gotwebd_dispatch_fcgi(int, short, void *); void gotwebd_dispatch_login(int, short, void *); void gotwebd_dispatch_auth(int, short, void *); void gotwebd_dispatch_gotweb(int, short, void *); struct gotwebd *gotwebd_env; void imsg_event_add(struct imsgev *iev) { if (iev->handler == NULL) { imsgbuf_flush(&iev->ibuf); return; } iev->events = EV_READ; if (imsgbuf_queuelen(&iev->ibuf)) iev->events |= EV_WRITE; event_del(&iev->ev); event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); event_add(&iev->ev, NULL); } int imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, pid_t pid, int fd, const void *data, size_t datalen) { int ret; ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen); if (ret == -1) return (ret); imsg_event_add(iev); return (ret); } static int send_imsg(struct imsgev *iev, uint32_t type, int fd, const void *data, uint16_t len) { int ret, d = -1; if (fd != -1 && (d = dup(fd)) == -1) goto err; ret = imsg_compose_event(iev, type, 0, -1, d, data, len); if (ret == -1) goto err; if (d != -1) { d = -1; /* Flush imsg to prevent fd exhaustion. 'd' will be closed. */ if (imsgbuf_flush(&iev->ibuf) == -1) goto err; imsg_event_add(iev); } return 0; err: if (d != -1) close(d); return -1; } int main_compose_sockets(struct gotwebd *env, uint32_t type, int fd, const void *data, uint16_t len) { return send_imsg(env->iev_sockets, type, fd, data, len); } int main_compose_login(struct gotwebd *env, uint32_t type, int fd, const void *data, uint16_t len) { return send_imsg(env->iev_login, type, fd, data, len); } int main_compose_gotweb(struct gotwebd *env, uint32_t type, int fd, const void *data, uint16_t len) { size_t i; int ret = 0; for (i = 0; i < env->prefork; i++) { ret = send_imsg(&env->iev_gotweb[i], type, fd, data, len); if (ret) break; } return ret; } int main_compose_auth(struct gotwebd *env, uint32_t type, int fd, const void *data, uint16_t len) { size_t i; int ret = 0; for (i = 0; i < env->prefork; i++) { ret = send_imsg(&env->iev_auth[i], type, fd, data, len); if (ret) break; } return ret; } int sockets_compose_main(struct gotwebd *env, uint32_t type, const void *d, uint16_t len) { return (imsg_compose_event(env->iev_parent, type, 0, -1, -1, d, len)); } void gotwebd_dispatch_login(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_dispatch_server(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_DONE: gotwebd_configure_done(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_dispatch_fcgi(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_DONE: gotwebd_configure_done(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_dispatch_auth(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_DONE: gotwebd_configure_done(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_dispatch_gotweb(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_DONE: gotwebd_configure_done(env); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_sighdlr(int sig, short event, void *arg) { /* struct privsep *ps = arg; */ switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGTERM: case SIGINT: gotwebd_shutdown(); break; default: fatalx("unexpected signal"); } } static void spawn_process(struct gotwebd *env, const char *argv0, struct imsgev *iev, enum gotwebd_proc_type proc_type, const char *username, const char *www_user, void (*handler)(int, short, void *)) { const char *argv[10]; int argc = 0; int p[2]; pid_t pid; char usernames[_PW_NAME_LEN * 2 + 1 + 1]; int ret; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif ret = snprintf(usernames, sizeof(usernames), "%s:%s", username, www_user); if (ret == -1) fatal("snprintf"); if ((size_t)ret >= sizeof(usernames)) fatalx("usernames too long"); if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, p) == -1) fatal("socketpair"); switch (pid = fork()) { case -1: fatal("fork"); case 0: /* child */ break; default: /* parent */ close(p[0]); if (imsgbuf_init(&iev->ibuf, p[1]) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); iev->handler = handler; iev->data = iev; event_set(&iev->ev, p[1], EV_READ, handler, iev); event_add(&iev->ev, NULL); return; } close(p[1]); argv[argc++] = argv0; if (proc_type == GOTWEBD_PROC_SOCKETS) { char *s; argv[argc++] = "-S"; argv[argc++] = usernames; if (asprintf(&s, "-S%d", env->prefork) == -1) fatal("asprintf"); argv[argc++] = s; } else if (proc_type == GOTWEBD_PROC_LOGIN) { argv[argc++] = "-L"; argv[argc++] = usernames; } else if (proc_type == GOTWEBD_PROC_FCGI) { argv[argc++] = "-F"; argv[argc++] = usernames; } else if (proc_type == GOTWEBD_PROC_AUTH) { argv[argc++] = "-A"; argv[argc++] = usernames; } else if (proc_type == GOTWEBD_PROC_GOTWEB) { argv[argc++] = "-G"; argv[argc++] = usernames; } if (strcmp(env->gotwebd_conffile, GOTWEBD_CONF) != 0) { argv[argc++] = "-f"; argv[argc++] = env->gotwebd_conffile; } if (env->gotwebd_debug) argv[argc++] = "-d"; if (env->gotwebd_verbose > 0) argv[argc++] = "-v"; if (env->gotwebd_verbose > 1) argv[argc++] = "-v"; argv[argc] = NULL; if (p[0] != GOTWEBD_SOCK_FILENO) { if (dup2(p[0], GOTWEBD_SOCK_FILENO) == -1) fatal("dup2"); } else if (fcntl(p[0], F_SETFD, 0) == -1) fatal("fcntl"); /* obnoxious cast */ execvp(argv0, (char * const *)argv); fatal("execvp %s", argv0); } __dead void usage(void) { fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", getprogname()); exit(1); } static void get_usernames(const char **gotwebd_username, const char **www_username, char *optarg) { static char usernames[_PW_NAME_LEN * 2 + 1 + 1]; char *colon; if (strlcpy(usernames, optarg, sizeof(usernames)) >= sizeof(usernames)) fatalx("usernames too long"); colon = strchr(usernames, ':'); if (colon == NULL) fatalx("bad username option parameter"); *colon = '\0'; *gotwebd_username = &usernames[0]; *www_username = colon + 1; } int main(int argc, char **argv) { struct event sigint, sigterm, sighup, sigpipe, sigusr1; struct event_base *evb; struct gotwebd *env; struct passwd *pw; int ch, i, gotwebd_ngroups = NGROUPS_MAX; int no_action = 0; int proc_type = GOTWEBD_PROC_PARENT; const char *conffile = GOTWEBD_CONF; const char *gotwebd_username = GOTWEBD_DEFAULT_USER; const char *www_username = GOTWEBD_WWW_USER; gid_t gotwebd_groups[NGROUPS_MAX]; gid_t www_gid; const char *argv0, *errstr; if ((argv0 = argv[0]) == NULL) argv0 = "gotwebd"; /* log to stderr until daemonized */ log_init(1, LOG_DAEMON); env = calloc(1, sizeof(*env)); if (env == NULL) fatal("%s: calloc", __func__); config_init(env); while ((ch = getopt(argc, argv, "A:D:dG:f:F:L:nS:vW:")) != -1) { switch (ch) { case 'A': proc_type = GOTWEBD_PROC_AUTH; get_usernames(&gotwebd_username, &www_username, optarg); break; case 'D': if (cmdline_symset(optarg) < 0) log_warnx("could not parse macro definition %s", optarg); break; case 'd': env->gotwebd_debug = 1; break; case 'G': proc_type = GOTWEBD_PROC_GOTWEB; get_usernames(&gotwebd_username, &www_username, optarg); break; case 'f': conffile = optarg; break; case 'F': proc_type = GOTWEBD_PROC_FCGI; get_usernames(&gotwebd_username, &www_username, optarg); break; case 'L': proc_type = GOTWEBD_PROC_LOGIN; get_usernames(&gotwebd_username, &www_username, optarg); break; case 'n': no_action = 1; break; case 'S': proc_type = GOTWEBD_PROC_SOCKETS; i = strtonum(optarg, 1, INT_MAX, &errstr); if (errstr) { get_usernames(&gotwebd_username, &www_username, optarg); } else env->prefork = i; break; case 'v': if (env->gotwebd_verbose < 3) env->gotwebd_verbose++; break; default: usage(); } } argc -= optind; if (argc > 0) usage(); gotwebd_env = env; env->gotwebd_conffile = conffile; if (proc_type == GOTWEBD_PROC_PARENT) { if (parse_config(env->gotwebd_conffile, env) == -1) exit(1); if (no_action) { fprintf(stderr, "configuration OK\n"); exit(0); } if (env->user) gotwebd_username = env->user; if (env->www_user) www_username = env->www_user; } if (proc_type == GOTWEBD_PROC_SOCKETS) { env->worker_load = calloc(env->prefork, sizeof(env->worker_load[0])); if (env->worker_load == NULL) fatal("calloc"); } pw = getpwnam(www_username); if (pw == NULL) fatalx("unknown user %s", www_username); env->www_uid = pw->pw_uid; www_gid = pw->pw_gid; pw = getpwnam(gotwebd_username); if (pw == NULL) fatalx("unknown user %s", gotwebd_username); if (getgrouplist(gotwebd_username, pw->pw_gid, gotwebd_groups, &gotwebd_ngroups) == -1) fatalx("too many groups for user %s", gotwebd_username); /* check for root privileges */ if (geteuid()) fatalx("need root privileges"); log_init(env->gotwebd_debug, LOG_DAEMON); log_setverbose(env->gotwebd_verbose); switch (proc_type) { case GOTWEBD_PROC_LOGIN: setproctitle("login"); log_procinit("login"); if (setgroups(1, &pw->pw_gid) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); gotwebd_login(env, GOTWEBD_SOCK_FILENO); return 1; case GOTWEBD_PROC_SOCKETS: setproctitle("sockets"); log_procinit("sockets"); if (chroot(env->httpd_chroot) == -1) fatal("chroot %s", env->httpd_chroot); if (chdir("/") == -1) fatal("chdir /"); if (setgroups(1, &pw->pw_gid) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); sockets(env, GOTWEBD_SOCK_FILENO); return 1; case GOTWEBD_PROC_FCGI: setproctitle("fcgi"); log_procinit("fcgi"); if (chroot(env->httpd_chroot) == -1) fatal("chroot %s", env->httpd_chroot); if (chdir("/") == -1) fatal("chdir /"); if (setgroups(gotwebd_ngroups, gotwebd_groups) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); gotwebd_fcgi(env, GOTWEBD_SOCK_FILENO); return 1; case GOTWEBD_PROC_AUTH: setproctitle("auth"); log_procinit("auth"); if (setgroups(1, &pw->pw_gid) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); gotwebd_auth(env, GOTWEBD_SOCK_FILENO); return 1; case GOTWEBD_PROC_GOTWEB: setproctitle("gotweb"); log_procinit("gotweb"); if (setgroups(gotwebd_ngroups, gotwebd_groups) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); gotweb(env, GOTWEBD_SOCK_FILENO); return 1; default: break; } if (!env->gotwebd_debug && daemon(1, 0) == -1) fatal("daemon"); evb = event_init(); env->iev_sockets = calloc(1, sizeof(*env->iev_sockets)); if (env->iev_sockets == NULL) fatal("calloc"); env->iev_login = calloc(1, sizeof(*env->iev_login)); if (env->iev_login == NULL) fatal("calloc"); env->iev_fcgi = calloc(1, sizeof(*env->iev_fcgi)); if (env->iev_fcgi == NULL) fatal("calloc"); env->iev_auth = calloc(env->prefork, sizeof(*env->iev_auth)); if (env->iev_auth == NULL) fatal("calloc"); env->iev_gotweb = calloc(env->prefork, sizeof(*env->iev_gotweb)); if (env->iev_gotweb == NULL) fatal("calloc"); spawn_process(env, argv0, env->iev_sockets, GOTWEBD_PROC_SOCKETS, gotwebd_username, www_username, gotwebd_dispatch_server); spawn_process(env, argv0, env->iev_login, GOTWEBD_PROC_LOGIN, gotwebd_username, www_username, gotwebd_dispatch_login); spawn_process(env, argv0, env->iev_fcgi, GOTWEBD_PROC_FCGI, gotwebd_username, www_username, gotwebd_dispatch_fcgi); for (i = 0; i < env->prefork; ++i) { spawn_process(env, argv0, &env->iev_auth[i], GOTWEBD_PROC_AUTH, gotwebd_username, www_username, gotwebd_dispatch_auth); spawn_process(env, argv0, &env->iev_gotweb[i], GOTWEBD_PROC_GOTWEB, gotwebd_username, www_username, gotwebd_dispatch_gotweb); } if (chdir("/") == -1) fatal("chdir /"); log_procinit("gotwebd"); log_info("%s startup", getprogname()); signal_set(&sigint, SIGINT, gotwebd_sighdlr, env); signal_set(&sigterm, SIGTERM, gotwebd_sighdlr, env); signal_set(&sighup, SIGHUP, gotwebd_sighdlr, env); signal_set(&sigpipe, SIGPIPE, gotwebd_sighdlr, env); signal_set(&sigusr1, SIGUSR1, gotwebd_sighdlr, env); signal_add(&sigint, NULL); signal_add(&sigterm, NULL); signal_add(&sighup, NULL); signal_add(&sigpipe, NULL); signal_add(&sigusr1, NULL); if (gotwebd_configure(env, pw->pw_uid, www_gid) == -1) fatalx("configuration failed"); if (setgroups(1, &pw->pw_gid) == -1 || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) fatal("failed to drop privileges"); #ifdef PROFILE if (unveil("gmon.out", "rwc") != 0) err(1, "gmon.out"); #endif if (unveil(GOTWEBD_CONF, "r") == -1) err(1, "unveil"); if (unveil(NULL, NULL) != 0) err(1, "unveil"); #ifndef PROFILE if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif event_dispatch(); event_base_free(evb); log_debug("%s gotwebd exiting", getprogname()); return (0); } static void connect_children(struct gotwebd *env) { struct imsgev *iev_gotweb, *iev_auth; int pipe[2]; int i; int sock_flags = SOCK_STREAM | SOCK_NONBLOCK; #ifdef SOCK_CLOEXEC sock_flags |= SOCK_CLOEXEC; #endif if (socketpair(AF_UNIX, sock_flags, PF_UNSPEC, pipe) == -1) fatal("socketpair"); if (main_compose_sockets(env, GOTWEBD_IMSG_CTL_PIPE, pipe[0], NULL, 0)) fatal("main_compose_sockets"); if (send_imsg(env->iev_fcgi, GOTWEBD_IMSG_CTL_PIPE, pipe[1], NULL, 0)) fatal("send_imsg"); for (i = 0; i < env->prefork; i++) { iev_gotweb = &env->iev_gotweb[i]; iev_auth = &env->iev_auth[i]; if (socketpair(AF_UNIX, SOCK_STREAM | sock_flags, PF_UNSPEC, pipe) == -1) fatal("socketpair"); if (main_compose_sockets(env, GOTWEBD_IMSG_CTL_PIPE, pipe[0], NULL, 0)) fatal("send_imsg"); if (send_imsg(iev_auth, GOTWEBD_IMSG_CTL_PIPE, pipe[1], NULL, 0)) fatal("send_imsg"); if (socketpair(AF_UNIX, SOCK_STREAM | sock_flags, PF_UNSPEC, pipe) == -1) fatal("socketpair"); if (send_imsg(iev_auth, GOTWEBD_IMSG_CTL_PIPE, pipe[0], NULL, 0)) fatal("send_imsg"); if (send_imsg(iev_gotweb, GOTWEBD_IMSG_CTL_PIPE, pipe[1], NULL, 0)) fatal("send_imsg"); } } int gotwebd_configure(struct gotwebd *env, uid_t uid, gid_t gid) { struct server *srv; struct socket *sock; struct gotwebd_repo *repo; char secret[32]; int i; /* gotweb need to reload its config. */ env->gotweb_pending = env->prefork; env->auth_pending = env->prefork; /* send global access rules */ for (i = 0; i < env->prefork; ++i) { config_set_access_rules(&env->iev_auth[i], &env->access_rules); config_set_access_rules(&env->iev_gotweb[i], &env->access_rules); } /* send our gotweb servers */ TAILQ_FOREACH(srv, &env->servers, entry) { if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) fatal("send_imsg GOTWEBD_IMSG_CFG_SRV"); if (main_compose_auth(env, GOTWEBD_IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SRV"); if (main_compose_gotweb(env, GOTWEBD_IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SRV"); if (main_compose_login(env, GOTWEBD_IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) fatal("main_compose_gotweb GOTWEBD_IMSG_CFG_SRV"); /* send per-server access rules */ for (i = 0; i < env->prefork; ++i) { config_set_access_rules(&env->iev_auth[i], &srv->access_rules); config_set_access_rules(&env->iev_gotweb[i], &srv->access_rules); } /* send repositories and per-repository access rules */ TAILQ_FOREACH(repo, &srv->repos, entry) { for (i = 0; i < env->prefork; i++) { config_set_repository(&env->iev_auth[i], repo); config_set_repository(&env->iev_gotweb[i], repo); config_set_access_rules(&env->iev_auth[i], &repo->access_rules); config_set_access_rules(&env->iev_gotweb[i], &repo->access_rules); } } for (i = 0; i < env->prefork; i++) { if (imsgbuf_flush(&env->iev_auth[i].ibuf) == -1) fatal("imsgbuf_flush"); imsg_event_add(&env->iev_auth[i]); if (imsgbuf_flush(&env->iev_gotweb[i].ibuf) == -1) fatal("imsgbuf_flush"); imsg_event_add(&env->iev_gotweb[i]); } } /* send our sockets */ TAILQ_FOREACH(sock, &env->sockets, entry) { if (config_setsock(env, sock, uid, gid) == -1) fatalx("%s: send socket error", __func__); } /* send the temp files */ if (config_setfd(env) == -1) fatalx("%s: send priv_fd error", __func__); /* Connect servers and gotwebs. */ connect_children(env); if (main_compose_auth(env, GOTWEBD_IMSG_AUTH_CONF, -1, &env->auth_config, sizeof(env->auth_config)) == -1) fatal("send_imsg GOTWEB_IMSG_AUTH_CONF"); if (main_compose_gotweb(env, GOTWEBD_IMSG_AUTH_CONF, -1, &env->auth_config, sizeof(env->auth_config)) == -1) fatal("main_compose_gotweb GOTWEB_IMSG_AUTH_CONF"); if (main_compose_auth(env, GOTWEBD_IMSG_WWW_UID, -1, &env->www_uid, sizeof(env->www_uid)) == -1) fatal("main_compose_auth GOTWEB_IMSG_WWW_UID"); if (main_compose_gotweb(env, GOTWEBD_IMSG_WWW_UID, -1, &env->www_uid, sizeof(env->www_uid)) == -1) fatal("main_compose_gotweb GOTWEB_IMSG_WWW_UID"); arc4random_buf(secret, sizeof(secret)); if (main_compose_login(env, GOTWEBD_IMSG_LOGIN_SECRET, -1, secret, sizeof(secret)) == -1) fatal("main_compose_login GOTWEB_IMSG_LOGIN_SECRET"); if (main_compose_auth(env, GOTWEBD_IMSG_LOGIN_SECRET, -1, secret, sizeof(secret)) == -1) fatal("main_compose_auth GOTWEB_IMSG_LOGIN_SECRET"); arc4random_buf(secret, sizeof(secret)); if (main_compose_auth(env, GOTWEBD_IMSG_AUTH_SECRET, -1, secret, sizeof(secret)) == -1) fatal("main_compose_auth GOTWEB_IMSG_AUTH_SECRET"); #ifdef __APPLE__ memset_s(secret, sizeof(*secret), 0, sizeof(*secret)); #elif defined(__NetBSD__) explicit_memset(secret, sizeof(*secret), 0); #else explicit_bzero(secret, sizeof(secret)); #endif if (login_privinit(env, uid, gid) == -1) fatalx("cannot open authentication socket"); if (main_compose_login(env, GOTWEBD_IMSG_CFG_SOCK, env->login_sock->fd, NULL, 0) == -1) fatal("main_compose_login GOTWEBD_IMSG_CFG_SOCK"); if (main_compose_sockets(env, GOTWEBD_IMSG_CFG_DONE, -1, NULL, 0) == -1) fatal("send_imsg GOTWEBD_IMSG_CFG_DONE"); return (0); } void gotwebd_configure_done(struct gotwebd *env) { if (main_compose_sockets(env, GOTWEBD_IMSG_CTL_START, -1, NULL, 0) == -1) fatal("send_imsg GOTWEBD_IMSG_CTL_START"); if (env->gotweb_pending > 0) { env->gotweb_pending--; if (env->gotweb_pending == 0 && main_compose_gotweb(env, GOTWEBD_IMSG_CTL_START, -1, NULL, 0) == -1) fatal("main_compose_gotweb GOTWEBD_IMSG_CTL_START"); } if (env->auth_pending > 0) { env->auth_pending--; if (env->auth_pending == 0 && main_compose_auth(env, GOTWEBD_IMSG_CTL_START, -1, NULL, 0) == -1) fatal("main_compose_auth GOTWEBD_IMSG_CTL_START"); } if (main_compose_login(env, GOTWEBD_IMSG_CTL_START, -1, NULL, 0) == -1) fatal("send_imsg GOTWEBD_IMSG_CTL_START"); } void gotwebd_shutdown(void) { struct gotwebd *env = gotwebd_env; pid_t pid; int i, status; event_del(&env->iev_login->ev); imsgbuf_clear(&env->iev_login->ibuf); close(env->iev_login->ibuf.fd); env->iev_login->ibuf.fd = -1; free(env->iev_login); event_del(&env->iev_sockets->ev); imsgbuf_clear(&env->iev_sockets->ibuf); close(env->iev_sockets->ibuf.fd); env->iev_sockets->ibuf.fd = -1; free(env->iev_sockets); event_del(&env->iev_fcgi->ev); imsgbuf_clear(&env->iev_fcgi->ibuf); close(env->iev_fcgi->ibuf.fd); env->iev_fcgi->ibuf.fd = -1; free(env->iev_fcgi); for (i = 0; i < env->prefork; ++i) { event_del(&env->iev_auth[i].ev); imsgbuf_clear(&env->iev_auth[i].ibuf); close(env->iev_auth[i].ibuf.fd); env->iev_auth[i].ibuf.fd = -1; event_del(&env->iev_gotweb[i].ev); imsgbuf_clear(&env->iev_gotweb[i].ibuf); close(env->iev_gotweb[i].ibuf.fd); env->iev_gotweb[i].ibuf.fd = -1; } free(env->iev_auth); free(env->iev_gotweb); free(env->login_sock); do { pid = waitpid(WAIT_ANY, &status, 0); if (pid <= 0) continue; if (WIFSIGNALED(status)) log_warnx("lost child: pid %u terminated; signal %d", pid, WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) log_warnx("lost child: pid %u exited abnormally", pid); } while (pid != -1 || (pid == -1 && errno == EINTR)); while (!TAILQ_EMPTY(&gotwebd_env->addresses)) { struct address *h; h = TAILQ_FIRST(&gotwebd_env->addresses); TAILQ_REMOVE(&gotwebd_env->addresses, h, entry); free(h); } while (!TAILQ_EMPTY(&gotwebd_env->sockets)) { struct socket *sock; sock = TAILQ_FIRST(&gotwebd_env->sockets); TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); free(sock); } while (!TAILQ_EMPTY(&gotwebd_env->servers)) { struct server *srv; srv = TAILQ_FIRST(&gotwebd_env->servers); TAILQ_REMOVE(&gotwebd_env->servers, srv, entry); free(srv); } free(gotwebd_env); log_warnx("gotwebd terminating"); exit(0); } got-portable-0.119/gotwebd/gotwebd.80000664000175000017500000001052215066535721012777 .\" .\" Copyright (c) 2020 Stefan Sperling .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate$ .Dt GOTWEBD 8 .Os .Sh NAME .Nm gotwebd .Nd Game of Trees FastCGI server for web browsers .Sh SYNOPSIS .Nm .Op Fl dnv .Op Fl D Ar macro Ns = Ns Ar value .Op Fl f Ar file .Sh DESCRIPTION .Nm is a FastCGI server program which can display the contents of Git repositories via a web browser. The program has been designed to work out of the box with the .Xr httpd 8 web server. .Pp .Nm provides the following options: .Bl -tag -width tenletters .It Fl D Ar macro Ns = Ns Ar value Define .Ar macro to be set to .Ar value . Overrides the definition of .Ar macro in the configuration file. .It Fl d Do not daemonize. Send log output to stderr. .It Fl f Ar file Set the path to the configuration file. If not specified, the file .Pa /etc/gotwebd.conf will be used. .It Fl n Parse the configuration file, report errors if any, and exit. .It Fl v Verbose mode. Verbosity increases if this option is used multiple times. .El .Pp Enabling .Nm requires the following steps: .Bl -enum .It The .Xr httpd.conf 5 configuration file must be adjusted to run .Nm as a FastCGI helper program. The .Sx EXAMPLES section below contains an appropriate configuration file sample. .It httpd(8) must be enabled and started: .Bd -literal -offset indent # rcctl enable httpd # rcctl start httpd .Ed .It Optionally, the run-time behaviour of .Nm can be configured via the .Xr gotwebd.conf 5 configuration file. .It Git repositories must be created. These repositories may reside anywhere in the filesystem and must be readable, but should .Em not be writable, by the user .Nm runs as. The default location for repositories published by .Nm is .Pa /var/www/got/public . .It If the Git repositories served by .Nm do not receive changes from committers directly, they need to be kept up-to-date with a mechanism such as .Cm got fetch , .Xr git-fetch 1 , or .Xr rsync 1 , scheduled by .Xr cron 8 . .El .Sh FILES .Bl -tag -width /var/www/got/public/ -compact .It Pa /etc/gotwebd.conf Default location of the .Xr gotwebd.conf 5 configuration file. .It Pa /var/www/got/public/ Default location for Git repositories served by .Nm . This location can be adjusted in the .Xr gotwebd.conf 5 configuration file. .It Pa /var/www/bin/gotwebd/ Directory containing statically linked .Xr got 1 helper programs which are run by .Nm to read Git repositories. .It Pa /var/www/htdocs/gotwebd/ Directory containing HTML, CSS, and image files used by .Nm . .It Pa /var/www/run/gotweb.sock Default location for the .Nm listening socket. .It Pa /tmp/ Directory for temporary files created by .Nm . .El .Sh EXAMPLES Example configuration for .Xr httpd.conf 5 : .Bd -literal -offset indent types { include "/usr/share/misc/mime.types" } server "example.com" { listen on * port 80 root "/htdocs/gotwebd" location "/" { fastcgi socket "/run/gotweb.sock" } } .Ed .Pp Hosting multiple .Nm gotwebd instances on the same HTTP server under different path prefixes, with the first reached via the default .Ux Ns -domain socket, the second configured to listen on localhost port 9000: .Bd -literal -offset indent server "example.com" { listen on * port 80 location "/gotwebd-unix/" { fastcgi socket "/run/gotweb.sock" } location "/gotwebd-unix/*" { root "/htdocs/gotwebd" request strip 1 } location "/gotwebd-tcp/" { fastcgi socket tcp localhost 9000 } location "/gotwebd-tcp/*" { root "/htdocs/gotwebd" request strip 1 } } .Ed .Sh SEE ALSO .Xr got 1 , .Xr git-repository 5 , .Xr gotwebd.conf 5 , .Xr httpd.conf 5 , .Xr httpd 8 .Sh AUTHORS .An Omar Polo Aq Mt op@openbsd.org .An Stefan Sperling Aq Mt stsp@openbsd.org .An Tracey Emery Aq Mt tracey@traceyemery.net got-portable-0.119/gotwebd/gotwebd.h0000664000175000017500000004025215066536012013054 /* * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery * Copyright (c) 2015 Mike Larkin * Copyright (c) 2013 David Gwynne * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif /* GOTWEBD DEFAULTS */ #define GOTWEBD_CONF "/etc/gotwebd.conf" #ifndef GOTWEBD_DEFAULT_USER #define GOTWEBD_DEFAULT_USER "_gotwebd" #endif #ifndef GOTWEBD_WWW_USER #define GOTWEBD_WWW_USER "www" #endif #define GOTWEBD_LOGIN_CMD "weblogin" #define GOTWEBD_LOGIN_SOCKET "/var/run/gotweb-login.sock" #define GOTWEBD_LOGIN_TIMEOUT 300 /* in seconds */ #define GOTWEBD_MAXDESCRSZ 1024 #define GOTWEBD_MAXCLONEURLSZ 1024 #define GOTWEBD_CACHESIZE 1024 #define GOTWEBD_MAXCLIENTS 1024 #define GOTWEBD_MAXTEXT 511 #define GOTWEBD_MAXNAME 64 #define GOTWEBD_MAXPORT 6 #define GOTWEBD_NUMPROC 3 #define GOTWEBD_SOCK_FILENO 3 #define PROC_MAX_INSTANCES 32 /* GOTWEB DEFAULTS */ #define MAX_QUERYSTRING 2048 #define MAX_DOCUMENT_URI 255 #define MAX_SERVER_NAME 255 #define MAX_AUTH_COOKIE 255 #define MAX_IDENTIFIER_SIZE 32 #define GOTWEB_GIT_DIR ".git" #define D_HTTPD_CHROOT "/var/www" #define D_UNIX_SOCKET "/run/gotweb.sock" #define D_FCGI_PORT "9000" #define D_GOTPATH "/got/public" #define D_SITENAME "Gotweb" #define D_SITEOWNER "Got Owner" #define D_SITELINK "Repos" #define D_GOTLOGO "got.png" #define D_GOTURL "https://gameoftrees.org" #define D_GOTWEBCSS "gotweb.css" #define D_SHOWROWNER 1 #define D_SHOWSOWNER 1 #define D_SHOWAGE 1 #define D_SHOWDESC 1 #define D_SHOWURL 1 #define D_RESPECTEXPORTOK 0 #define D_MAXREPODISP 25 #define D_MAXSLCOMMDISP 10 #define D_MAXCOMMITDISP 25 #define D_MAXSLTAGDISP 3 #define BUF 8192 #define TIMEOUT_DEFAULT 120 #define FCGI_CONTENT_SIZE 65535 #define FCGI_PADDING_SIZE 255 #define FCGI_RECORD_SIZE \ (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE) #define FCGI_ALIGNMENT 8 #define FCGI_ALIGN(n) \ (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1)) #define FD_RESERVE 5 #define FCGI_BEGIN_REQUEST 1 #define FCGI_ABORT_REQUEST 2 #define FCGI_END_REQUEST 3 #define FCGI_PARAMS 4 #define FCGI_STDIN 5 #define FCGI_STDOUT 6 #define FCGI_STDERR 7 #define FCGI_DATA 8 #define FCGI_GET_VALUES 9 #define FCGI_GET_VALUES_RESULT 10 #define FCGI_UNKNOWN_TYPE 11 #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) #define FCGI_REQUEST_COMPLETE 0 #define FCGI_CANT_MPX_CONN 1 #define FCGI_OVERLOADED 2 #define FCGI_UNKNOWN_ROLE 3 #define GOTWEB_PACK_NUM_TEMPFILES (32 * 2) /* Forward declaration */ struct got_blob_object; struct got_tree_entry; struct got_reflist_head; enum gotwebd_proc_type { GOTWEBD_PROC_PARENT, GOTWEBD_PROC_SOCKETS, GOTWEBD_PROC_FCGI, GOTWEBD_PROC_LOGIN, GOTWEBD_PROC_AUTH, GOTWEBD_PROC_GOTWEB, }; enum imsg_type { GOTWEBD_IMSG_CFG_SRV, GOTWEBD_IMSG_CFG_SOCK, GOTWEBD_IMSG_CFG_FD, GOTWEBD_IMSG_CFG_ACCESS_RULE, GOTWEBD_IMSG_CFG_REPO, GOTWEBD_IMSG_CFG_DONE, GOTWEBD_IMSG_CTL_PIPE, GOTWEBD_IMSG_CTL_START, GOTWEBD_IMSG_LOGIN_SECRET, GOTWEBD_IMSG_AUTH_SECRET, GOTWEBD_IMSG_AUTH_CONF, GOTWEBD_IMSG_FCGI_PARSE_PARAMS, GOTWEBD_IMSG_FCGI_PARAMS, GOTWEBD_IMSG_WWW_UID, GOTWEBD_IMSG_REQ_ABORT, GOTWEBD_IMSG_REQ_PROCESS, }; struct imsgev { struct imsgbuf ibuf; void (*handler)(int, short, void *); struct event ev; void *data; short events; }; #define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE) struct env_val { SLIST_ENTRY(env_val) entry; char *val; }; SLIST_HEAD(env_head, env_val); struct fcgi_record_header { uint8_t version; uint8_t type; uint16_t id; uint16_t content_len; uint8_t padding_len; uint8_t reserved; }__attribute__((__packed__)); struct blame_line { int annotated; char *id_str; char *committer; char datebuf[11]; /* YYYY-MM-DD + NUL */ }; struct repo_dir { char *name; char *owner; char *description; char *url; time_t age; char *path; }; struct repo_tag { TAILQ_ENTRY(repo_tag) entry; char *commit_id; char *tag_name; char *tag_commit; char *commit_msg; char *tagger; time_t tagger_time; }; struct repo_commit { TAILQ_ENTRY(repo_commit) entry; char *path; char *refs_str; char *commit_id; /* id_str1 */ char *parent_id; /* id_str2 */ char *tree_id; char *author; char *committer; char *commit_msg; time_t committer_time; }; struct got_repository; struct transport { TAILQ_HEAD(repo_commits_head, repo_commit) repo_commits; TAILQ_HEAD(repo_tags_head, repo_tag) repo_tags; struct got_reflist_head refs; struct got_repository *repo; struct repo_dir *repo_dir; const struct querystring *qs; char *more_id; char *tags_more_id; unsigned int repos_total; unsigned int next_disp; unsigned int prev_disp; const struct got_error *error; struct got_blob_object *blob; int fd; FILE *fp; struct dirent **repos; int nrepos; }; enum socket_priv_fds { DIFF_FD_1, DIFF_FD_2, DIFF_FD_3, DIFF_FD_4, DIFF_FD_5, BLAME_FD_1, BLAME_FD_2, BLAME_FD_3, BLAME_FD_4, BLAME_FD_5, BLAME_FD_6, BLOB_FD_1, BLOB_FD_2, PRIV_FDS__MAX, }; struct gotwebd_fcgi_record { uint32_t request_id; uint8_t record[FCGI_RECORD_SIZE]; size_t record_len; }; enum query_actions { NO_ACTION = 0, BLAME, BLOB, BLOBRAW, BRIEFS, COMMITS, DIFF, ERR, INDEX, PATCH, SUMMARY, TAG, TAGS, TREE, RSS, }; struct querystring { enum query_actions action; char commit[GOT_OBJECT_ID_HEX_MAXLEN]; char file[NAME_MAX]; char folder[PATH_MAX]; char headref[MAX_DOCUMENT_URI]; int index_page; char path[PATH_MAX]; char login[MAX_AUTH_COOKIE]; }; struct gotwebd_fcgi_params { uint32_t request_id; struct querystring qs; char document_uri[MAX_DOCUMENT_URI]; char server_name[MAX_SERVER_NAME]; char auth_cookie[MAX_AUTH_COOKIE]; int https; }; struct template; struct request { TAILQ_ENTRY(request) entry; struct socket *sock; struct server *srv; struct transport *t; struct template *tp; struct event ev; struct event tmo; uint16_t id; int fd; int priv_fd[PRIV_FDS__MAX]; int sock_id; uint32_t request_id; int worker_idx; uint8_t *buf; size_t buf_len; uint8_t *outbuf; struct gotwebd_fcgi_params fcgi_params; int nparams; int nparams_parsed; int client_status; uid_t client_uid; char access_identifier[MAX_IDENTIFIER_SIZE]; }; TAILQ_HEAD(requestlist, request); struct fcgi_begin_request_body { uint16_t role; uint8_t flags; uint8_t reserved[5]; }__attribute__((__packed__)); struct fcgi_end_request_body { uint32_t app_status; uint8_t protocol_status; uint8_t reserved[3]; }__attribute__((__packed__)); struct address { TAILQ_ENTRY(address) entry; struct sockaddr_storage ss; socklen_t slen; int ai_family; int ai_socktype; int ai_protocol; in_port_t port; char ifname[IFNAMSIZ]; }; TAILQ_HEAD(addresslist, address); enum gotwebd_auth_config { GOTWEBD_AUTH_DISABLED = 0xf00000ff, GOTWEBD_AUTH_SECURE = 0x00808000, GOTWEBD_AUTH_INSECURE = 0x0f7f7f00 }; enum gotwebd_access { GOTWEBD_ACCESS_NO_MATCH = -2, GOTWEBD_ACCESS_DENIED = -1, GOTWEBD_ACCESS_PERMITTED = 1 }; struct gotwebd_access_rule { STAILQ_ENTRY(gotwebd_access_rule) entry; enum gotwebd_access access; char identifier[MAX_IDENTIFIER_SIZE]; }; STAILQ_HEAD(gotwebd_access_rule_list, gotwebd_access_rule); struct gotwebd_repo { TAILQ_ENTRY(gotwebd_repo) entry; char name[NAME_MAX]; enum gotwebd_auth_config auth_config; struct gotwebd_access_rule_list access_rules; }; TAILQ_HEAD(gotwebd_repolist, gotwebd_repo); struct server { TAILQ_ENTRY(server) entry; char name[GOTWEBD_MAXTEXT]; char repos_path[PATH_MAX]; char site_name[GOTWEBD_MAXNAME]; char site_owner[GOTWEBD_MAXNAME]; char site_link[GOTWEBD_MAXTEXT]; char logo[GOTWEBD_MAXTEXT]; char logo_url[GOTWEBD_MAXTEXT]; char custom_css[PATH_MAX]; size_t max_repos_display; size_t max_commits_display; size_t summary_commits_display; size_t summary_tags_display; int show_site_owner; int show_repo_owner; int show_repo_age; int show_repo_description; int show_repo_cloneurl; int respect_exportok; enum gotwebd_auth_config auth_config; struct gotwebd_access_rule_list access_rules; struct gotwebd_repolist repos; }; TAILQ_HEAD(serverlist, server); enum client_action { CLIENT_CONNECT, CLIENT_FCGI_BEGIN, CLIENT_FCGI_PARAMS, CLIENT_FCGI_STDIN, CLIENT_REQUEST, CLIENT_DISCONNECT, }; struct socket_conf { struct address addr; int id; int af_type; char unix_socket_name[PATH_MAX]; in_port_t fcgi_socket_port; }; struct socket { TAILQ_ENTRY(socket) entry; struct socket_conf conf; int fd; struct event evt; struct event ev; struct event pause; }; TAILQ_HEAD(socketlist, socket); struct passwd; struct gotwebd { struct serverlist servers; struct socketlist sockets; struct addresslist addresses; struct socket *login_sock; struct event login_pause_ev; enum gotwebd_auth_config auth_config; struct gotwebd_access_rule_list access_rules; int pack_fds[GOTWEB_PACK_NUM_TEMPFILES]; int priv_fd[PRIV_FDS__MAX]; char *user; char *www_user; const char *gotwebd_conffile; int gotwebd_debug; int gotwebd_verbose; struct imsgev *iev_parent; struct imsgev *iev_sockets; struct imsgev *iev_fcgi; struct imsgev *iev_login; struct imsgev *iev_gotsh; struct imsgev *iev_auth; struct imsgev *iev_gotweb; uint16_t prefork; int auth_pending; int gotweb_pending; int *worker_load; char httpd_chroot[PATH_MAX]; uid_t www_uid; }; /* * URL parameter for gotweb_render_url. NULL values and int set to -1 * are implicitly ignored, and string are properly escaped. */ struct gotweb_url { int action; int index_page; const char *commit; const char *file; const char *folder; const char *headref; const char *path; }; struct querystring_keys { const char *name; int element; }; struct action_keys { const char *name; int action; }; enum querystring_elements { ACTION, COMMIT, RFILE, FOLDER, HEADREF, INDEX_PAGE, PATH, LOGIN, }; extern struct gotwebd *gotwebd_env; typedef int (*got_render_blame_line_cb)(struct template *, const char *, struct blame_line *, int, int); /* gotwebd.c */ void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, int, const void *, size_t); int main_compose_sockets(struct gotwebd *, uint32_t, int, const void *, uint16_t); int main_compose_login(struct gotwebd *, uint32_t, int, const void *, uint16_t); int sockets_compose_main(struct gotwebd *, uint32_t, const void *, uint16_t); int main_compose_auth(struct gotwebd *, uint32_t, int, const void *, uint16_t); int main_compose_gotweb(struct gotwebd *, uint32_t, int, const void *, uint16_t); /* sockets.c */ void sockets(struct gotwebd *, int); void sockets_parse_sockets(struct gotwebd *); void sockets_socket_accept(int, short, void *); struct socket *sockets_conf_new_socket(int, struct address *); int sockets_privinit(struct gotwebd *, struct socket *, uid_t, gid_t); void sockets_rlimit(int); /* login.c */ char *login_gen_token(uint64_t, const char *, time_t, const char *, size_t, const char *); int login_check_token(uid_t *, char **, const char *, const char *, size_t, const char *); int login_privinit(struct gotwebd *, uid_t, gid_t); void gotwebd_login(struct gotwebd *, int); /* auth.c */ void gotwebd_auth(struct gotwebd *, int); /* gotweb.c */ struct server *gotweb_get_server(const char *); struct gotwebd_repo * gotweb_get_repository(struct server *, const char *); int gotweb_reply(struct request *c, int status, const char *ctype, struct gotweb_url *); void gotweb_index_navs(struct request *, struct gotweb_url *, int *, struct gotweb_url *, int *); int gotweb_render_age(struct template *, time_t); const struct got_error *gotweb_init_transport(struct transport **); const char *gotweb_action_name(int); int gotweb_render_url(struct request *, struct gotweb_url *); int gotweb_render_absolute_url(struct request *, struct gotweb_url *); void gotweb_free_repo_commit(struct repo_commit *); void gotweb_free_repo_tag(struct repo_tag *); int gotweb_process_request(struct request *); void gotweb_free_transport(struct transport *); void gotweb(struct gotwebd *, int); /* pages.tmpl */ int gotweb_render_page(struct template *, int (*)(struct template *)); int gotweb_render_error(struct template *); int gotweb_render_repo_table_hdr(struct template *); int gotweb_render_repo_fragment(struct template *, struct repo_dir *); int gotweb_render_briefs(struct template *); int gotweb_render_navs(struct template *); int gotweb_render_commits(struct template *); int gotweb_render_blob(struct template *); int gotweb_render_tree(struct template *); int gotweb_render_tags(struct template *); int gotweb_render_tag(struct template *); int gotweb_render_diff(struct template *); int gotweb_render_branches(struct template *, struct got_reflist_head *); int gotweb_render_summary(struct template *); int gotweb_render_blame(struct template *); int gotweb_render_patch(struct template *); int gotweb_render_rss(struct template *); int gotweb_render_unauthorized(struct template *); /* parse.y */ struct gotwebd_repo * gotwebd_new_repo(const char *); int parse_config(const char *, struct gotwebd *); int cmdline_symset(char *); /* fcgi.c */ void fcgi_init_querystring(struct querystring *); void fcgi_cleanup_request(struct request *); void fcgi_create_end_record(struct request *); int fcgi_write(void *, const void *, size_t); void gotwebd_fcgi(struct gotwebd *, int); /* got_operations.c */ const struct got_error *got_gotweb_closefile(FILE *); const struct got_error *got_get_repo_owner(char **, struct request *); const struct got_error *got_get_repo_age(time_t *, struct request *, const char *); const struct got_error *got_get_repo_commits(struct request *, size_t); const struct got_error *got_get_repo_tags(struct request *, size_t); const struct got_error *got_get_repo_heads(struct request *); const struct got_error *got_open_diff_for_output(FILE **, struct request *); int got_output_repo_tree(struct request *, char **, int (*)(struct template *, struct got_tree_entry *)); const struct got_error *got_open_blob_for_output(struct got_blob_object **, int *, int *, struct request *, const char *, const char *, const char *); int got_output_blob_by_lines(struct template *, struct got_blob_object *, int (*)(struct template *, const char *, size_t)); const struct got_error *got_output_file_blame(struct request *, got_render_blame_line_cb); /* config.c */ int config_setserver(struct gotwebd *, struct server *); int config_getserver(struct gotwebd *, struct imsg *); int config_setsock(struct gotwebd *, struct socket *, uid_t, gid_t); int config_getsock(struct gotwebd *, struct imsg *); int config_setfd(struct gotwebd *); int config_getfd(struct gotwebd *, struct imsg *); int config_getcfg(struct gotwebd *, struct imsg *); void config_set_access_rules(struct imsgev *, struct gotwebd_access_rule_list *); void config_get_access_rule(struct gotwebd_access_rule_list *, struct imsg *); void config_free_access_rules(struct gotwebd_access_rule_list *); void config_set_repository(struct imsgev *, struct gotwebd_repo *); void config_get_repository(struct gotwebd_repolist *, struct imsg *); void config_free_repos(struct gotwebd_repolist *); int config_init(struct gotwebd *); got-portable-0.119/gotwebd/auth.c0000664000175000017500000005476415066536113012374 /* * Copyright (c) 2025 Stefan Sperling * Copyright (c) 2025 Omar Polo * Copyright (c) 2015 Ted Unangst * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "got_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include "got_error.h" #include "got_reference.h" #include "got_object.h" #include "gotwebd.h" #include "log.h" #include "tmpl.h" static char login_token_secret[32]; static char auth_token_secret[32]; static void auth_shutdown(void) { struct gotwebd *env = gotwebd_env; imsgbuf_clear(&env->iev_parent->ibuf); imsgbuf_clear(&env->iev_sockets->ibuf); imsgbuf_clear(&env->iev_gotweb->ibuf); free(env->iev_parent); free(env->iev_sockets); free(env->iev_gotweb); config_free_access_rules(&gotwebd_env->access_rules); while (!TAILQ_EMPTY(&gotwebd_env->servers)) { struct server *srv; srv = TAILQ_FIRST(&gotwebd_env->servers); TAILQ_REMOVE(&gotwebd_env->servers, srv, entry); config_free_access_rules(&srv->access_rules); config_free_repos(&srv->repos); free(srv); } while (!TAILQ_EMPTY(&gotwebd_env->sockets)) { struct socket *sock; sock = TAILQ_FIRST(&gotwebd_env->sockets); TAILQ_REMOVE(&gotwebd_env->sockets, sock, entry); free(sock); } free(env); exit(0); } static void auth_sighdlr(int sig, short event, void *arg) { switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); break; case SIGPIPE: log_info("%s: ignoring SIGPIPE", __func__); break; case SIGUSR1: log_info("%s: ignoring SIGUSR1", __func__); break; case SIGCHLD: break; case SIGINT: case SIGTERM: auth_shutdown(); break; default: log_warn("unexpected signal %d", sig); break; } } static int parseuid(const char *s, uid_t *uid) { struct passwd *pw; const char *errstr; if ((pw = getpwnam(s)) != NULL) { *uid = pw->pw_uid; if (*uid == UID_MAX) return -1; return 0; } *uid = strtonum(s, 0, UID_MAX - 1, &errstr); if (errstr) return -1; return 0; } static int uidcheck(const char *s, uid_t desired) { uid_t uid; if (parseuid(s, &uid) != 0) return -1; if (uid != desired) return -1; return 0; } static int parsegid(const char *s, gid_t *gid) { struct group *gr; const char *errstr; if ((gr = getgrnam(s)) != NULL) { *gid = gr->gr_gid; if (*gid == GID_MAX) return -1; return 0; } *gid = strtonum(s, 0, GID_MAX - 1, &errstr); if (errstr) return -1; return 0; } static int match_identifier(const char *identifier, gid_t *groups, int ngroups, uid_t euid, gid_t egid) { int i; if (identifier[0] == ':') { gid_t rgid; if (parsegid(identifier + 1, &rgid) == -1) return 0; if (rgid == egid) return 1; for (i = 0; i < ngroups; i++) { if (rgid == groups[i]) break; } if (i == ngroups) return 0; } else if (uidcheck(identifier, euid) != 0) return 0; return 1; } static enum gotwebd_access auth_check(const char **identifier, uid_t uid, struct gotwebd_access_rule_list *rules) { struct gotwebd_access_rule *rule; enum gotwebd_access access = GOTWEBD_ACCESS_NO_MATCH; struct passwd *pw; gid_t groups[NGROUPS_MAX]; int ngroups = NGROUPS_MAX; gid_t gid; if (identifier) *identifier = NULL; pw = getpwuid(uid); if (pw == NULL) return GOTWEBD_ACCESS_DENIED; gid = pw->pw_gid; if (getgrouplist(pw->pw_name, gid, groups, &ngroups) == -1) log_warnx("group membership list truncated"); STAILQ_FOREACH(rule, rules, entry) { if (!match_identifier(rule->identifier, groups, ngroups, uid, gid)) continue; access = rule->access; if (identifier) *identifier = rule->identifier; } return access; } static void auth_launch(struct gotwebd *env) { if (env->iev_sockets == NULL) fatal("sockets process not connected"); if (env->iev_gotweb == NULL) fatal("gotweb process not connected"); event_add(&env->iev_sockets->ev, NULL); event_add(&env->iev_gotweb->ev, NULL); } static void render_error(struct request *c, const struct got_error *error) { int status; log_warnx("%s", error->msg); c->t->error = error; if (error->code == GOT_ERR_LOGIN_FAILED) status = 401; else status = 400; if (gotweb_reply(c, status, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_error); } static void abort_request(uint32_t request_id) { if (imsg_compose_event(gotwebd_env->iev_sockets, GOTWEBD_IMSG_REQ_ABORT, GOTWEBD_PROC_GOTWEB, -1, -1, &request_id, sizeof(request_id)) == -1) log_warn("imsg_compose_event"); } static void forward_request(struct request *c) { struct gotwebd *env = gotwebd_env; const struct got_error *error; int ret; ret = imsg_compose_event(env->iev_gotweb, GOTWEBD_IMSG_REQ_PROCESS, GOTWEBD_PROC_AUTH, -1, c->fd, c, sizeof(*c)); if (ret == -1) { error = got_error_set_errno(ret, "could not forward request " "to gotweb process"); render_error(c, error); return; } c->fd = -1; } static void do_login(struct request *c) { const struct got_error *error = NULL; struct gotwebd *env = gotwebd_env; uid_t uid; struct server *srv; char *hostname = NULL; char *token = NULL; const char *identifier = NULL; const time_t validity = 24 * 60 * 60; /* 1 day */ struct gotweb_url url; struct gotwebd_repo *repo; int r; if (login_check_token(&uid, &hostname, c->fcgi_params.qs.login, login_token_secret, sizeof(login_token_secret), "login") == -1) { error = got_error(GOT_ERR_LOGIN_FAILED); goto err; } /* * The www user ID represents the case where no authentication * occurred. This user must not be allowed to log in. */ if (uid == env->www_uid) { error = got_error(GOT_ERR_LOGIN_FAILED); goto err; } c->client_uid = uid; if (strcmp(hostname, c->fcgi_params.server_name) != 0) { error = got_error_msg(GOT_ERR_LOGIN_FAILED, "wrong server name in login token"); goto err; } srv = gotweb_get_server(c->fcgi_params.server_name); if (srv == NULL) { error = got_error_msg(GOT_ERR_LOGIN_FAILED, "invalid server name for login"); goto err; } TAILQ_FOREACH(repo, &srv->repos, entry) { switch (auth_check(&identifier, uid, &repo->access_rules)) { case GOTWEBD_ACCESS_PERMITTED: goto logged_in; case GOTWEBD_ACCESS_DENIED: case GOTWEBD_ACCESS_NO_MATCH: break; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto err; } } switch (auth_check(&identifier, uid, &srv->access_rules)) { case GOTWEBD_ACCESS_PERMITTED: goto logged_in; case GOTWEBD_ACCESS_DENIED: error = got_error_msg(GOT_ERR_LOGIN_FAILED, "permission denied"); goto err; case GOTWEBD_ACCESS_NO_MATCH: break; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto err; } switch (auth_check(&identifier, uid, &env->access_rules)) { case GOTWEBD_ACCESS_PERMITTED: break; case GOTWEBD_ACCESS_DENIED: case GOTWEBD_ACCESS_NO_MATCH: error = got_error_msg(GOT_ERR_LOGIN_FAILED, "permission denied"); goto err; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto err; } logged_in: if (gotwebd_env->gotwebd_verbose > 0) { log_info("successful login of uid %u as %s for server \"%s\"", uid, identifier, hostname); } /* * Generate a long-lasting token for the browser cookie. * TODO: make validity configurable? */ token = login_gen_token(uid, hostname, validity, auth_token_secret, sizeof(auth_token_secret), "authentication"); if (token == NULL) { error = got_error_msg(GOT_ERR_LOGIN_FAILED, "failed to generate authentication cookie"); goto err; } r = tp_writef(c->tp, "Set-Cookie: gwdauth=%s;" " SameSite=Strict;%s Path=/; HttpOnly; Max-Age=%llu\r\n", token, env->auth_config == GOTWEBD_AUTH_SECURE ? " Secure;" : "", validity); #ifdef __APPLE__ memset_s(token, sizeof(*token), 0, sizeof(*token)); #elif defined(__NetBSD__) explicit_memset(token, sizeof(*token), 0); #else explicit_bzero(token, strlen(token)); #endif free(token); if (r == -1) { error = got_error_from_errno("tp_writef"); goto err; } memset(&url, 0, sizeof(url)); url.action = INDEX; gotweb_reply(c, 307, "text/html", &url); return; err: free(hostname); hostname = NULL; log_warnx("%s: %s", __func__, error->msg); c->t->error = error; if (error->code == GOT_ERR_LOGIN_FAILED) { if (gotweb_reply(c, 401, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_unauthorized); } else { if (gotweb_reply(c, 400, "text/html", NULL) == -1) return; gotweb_render_page(c->tp, gotweb_render_error); } } static void process_request(struct request *c) { const struct got_error *error = NULL; struct gotwebd *env = gotwebd_env; uid_t uid; struct server *srv; struct gotwebd_repo *repo = NULL; enum gotwebd_auth_config auth_config; char *hostname = NULL; const char *identifier = NULL; srv = gotweb_get_server(c->fcgi_params.server_name); if (srv == NULL) { log_warnx("request for unknown server name"); error = got_error(GOT_ERR_BAD_QUERYSTRING); goto done; } auth_config = srv->auth_config; if (c->fcgi_params.qs.path[0] != '\0') { repo = gotweb_get_repository(srv, c->fcgi_params.qs.path); if (repo) auth_config = repo->auth_config; } switch (auth_config) { case GOTWEBD_AUTH_SECURE: case GOTWEBD_AUTH_INSECURE: break; case GOTWEBD_AUTH_DISABLED: forward_request(c); return; default: fatalx("bad auth_config %d", env->auth_config); } if (login_check_token(&uid, &hostname, c->fcgi_params.auth_cookie, auth_token_secret, sizeof(auth_token_secret), "authentication") == -1) { error = got_error(GOT_ERR_LOGIN_FAILED); goto done; } /* * The www user ID represents the case where no authentication * occurred. This user is not allowed in authentication cookies. */ if (uid == env->www_uid) { error = got_error(GOT_ERR_LOGIN_FAILED); goto done; } c->client_uid = uid; if (strcmp(hostname, c->fcgi_params.server_name) != 0) { error = got_error_msg(GOT_ERR_LOGIN_FAILED, "bad server name in login token"); goto done; } if (repo) { switch (auth_check(&identifier, uid, &repo->access_rules)) { case GOTWEBD_ACCESS_DENIED: error = got_error_msg(GOT_ERR_LOGIN_FAILED, "permission denied"); goto done; case GOTWEBD_ACCESS_PERMITTED: goto permitted; case GOTWEBD_ACCESS_NO_MATCH: break; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto done; } } else if (c->fcgi_params.qs.action == INDEX) { int have_public_repo = 0; /* * The index page may contain a mix of repositories we have * access to and/or for which authentication is disabled. */ TAILQ_FOREACH(repo, &srv->repos, entry) { if (repo->auth_config == GOTWEBD_AUTH_DISABLED) have_public_repo = -1; switch (auth_check(&identifier, uid, &repo->access_rules)) { case GOTWEBD_ACCESS_PERMITTED: goto permitted; case GOTWEBD_ACCESS_DENIED: case GOTWEBD_ACCESS_NO_MATCH: break; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto done; } } /* We have access to public repositories only. */ if (have_public_repo) { identifier = ""; goto permitted; } } switch (auth_check(&identifier, uid, &srv->access_rules)) { case GOTWEBD_ACCESS_DENIED: error = got_error_msg(GOT_ERR_LOGIN_FAILED, "permission denied"); goto done; case GOTWEBD_ACCESS_PERMITTED: goto permitted; case GOTWEBD_ACCESS_NO_MATCH: break; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto done; } switch (auth_check(&identifier, uid, &env->access_rules)) { case GOTWEBD_ACCESS_DENIED: case GOTWEBD_ACCESS_NO_MATCH: error = got_error_msg(GOT_ERR_LOGIN_FAILED, "permission denied"); goto done; case GOTWEBD_ACCESS_PERMITTED: goto permitted; default: error = got_error_fmt(GOT_ERR_LOGIN_FAILED, "access check error for uid %u\n", uid); goto done; } permitted: /* * At this point, identifier should either be the empty string (if * the request is allowed because authentication is partly disabled), * or a user or group name. */ if (identifier == NULL) fatalx("have no known user identifier"); if (strlcpy(c->access_identifier, identifier, sizeof(c->access_identifier)) >= sizeof(c->access_identifier)) { error = got_error_msg(GOT_ERR_NO_SPACE, "identifier too long"); goto done; } if (gotwebd_env->gotwebd_verbose > 0) { log_info("authenticated UID %u as %s for server \"%s\"", uid, identifier, hostname); } done: free(hostname); if (error) render_error(c, error); else forward_request(c); } static struct request * recv_request(struct imsg *imsg) { const struct got_error *error = NULL; struct request *c; struct server *srv; size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZE; int fd = -1; uint8_t *outbuf = NULL; if (datalen != sizeof(*c)) { log_warnx("bad request size received over imsg"); return NULL; } fd = imsg_get_fd(imsg); if (fd == -1) { log_warnx("no client file descriptor"); return NULL; } c = calloc(1, sizeof(*c)); if (c == NULL) { log_warn("calloc"); return NULL; } outbuf = calloc(1, GOTWEBD_CACHESIZE); if (outbuf == NULL) { log_warn("calloc"); free(c); return NULL; } memcpy(c, imsg->data, sizeof(*c)); /* Non-NULL pointers, if any, are not from our address space. */ c->sock = NULL; c->srv = NULL; c->t = NULL; c->tp = NULL; c->buf = NULL; c->outbuf = outbuf; memset(&c->ev, 0, sizeof(c->ev)); memset(&c->tmo, 0, sizeof(c->tmo)); /* Use our own temporary file descriptors. */ memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd)); c->fd = fd; c->client_uid = gotwebd_env->www_uid; c->tp = template(c, fcgi_write, c->outbuf, GOTWEBD_CACHESIZE); if (c->tp == NULL) { log_warn("gotweb init template"); fcgi_cleanup_request(c); return NULL; } /* init the transport */ error = gotweb_init_transport(&c->t); if (error) { log_warnx("gotweb init transport: %s", error->msg); fcgi_cleanup_request(c); return NULL; } /* querystring */ c->t->qs = &c->fcgi_params.qs; /* get the gotwebd server */ srv = gotweb_get_server(c->fcgi_params.server_name); if (srv == NULL) { log_warnx("server '%s' not found", c->fcgi_params.server_name); fcgi_cleanup_request(c); return NULL; } c->srv = srv; return c; } static void auth_dispatch_sockets(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; struct request *c; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_REQ_PROCESS: c = recv_request(&imsg); if (c == NULL) break; if (c->fcgi_params.qs.login[0] != '\0') do_login(c); else process_request(c); /* * If we have not forwarded the request to the gotweb * process we must flush and clean up ourselves. */ if (c->fd != -1) { uint32_t request_id = c->request_id; if (template_flush(c->tp) == -1) { log_warn("request %u flush", c->request_id); } fcgi_create_end_record(c); abort_request(request_id); } fcgi_cleanup_request(c); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_sockets_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->iev_sockets != NULL) fatalx("sockets process already connected"); fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid login pipe fd"); iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct request)); iev->handler = auth_dispatch_sockets; iev->data = iev; event_set(&iev->ev, fd, EV_READ, auth_dispatch_sockets, iev); imsg_event_add(iev); env->iev_sockets = iev; } static void auth_dispatch_gotweb(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_REQ_ABORT: { uint32_t request_id; if (imsg_get_data(&imsg, &request_id, sizeof(request_id)) == -1) fatalx("invalid REQ_ABORT msg"); abort_request(request_id); break; } default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } static void recv_gotweb_pipe(struct gotwebd *env, struct imsg *imsg) { struct imsgev *iev; int fd; if (env->iev_gotweb != NULL) fatalx("gotweb process already connected"); fd = imsg_get_fd(imsg); if (fd == -1) fatalx("invalid login pipe fd"); iev = calloc(1, sizeof(*iev)); if (iev == NULL) fatal("calloc"); if (imsgbuf_init(&iev->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&iev->ibuf); imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct request)); iev->handler = auth_dispatch_gotweb; iev->data = iev; event_set(&iev->ev, fd, EV_READ, auth_dispatch_gotweb, iev); imsg_event_add(iev); env->iev_gotweb = iev; } static void auth_dispatch_main(int fd, short event, void *arg) { struct imsgev *iev = arg; struct imsgbuf *ibuf; struct imsg imsg; struct gotwebd *env = gotwebd_env; struct server *srv; struct gotwebd_repo *repo; ssize_t n; int shut = 0; ibuf = &iev->ibuf; if (event & EV_READ) { if ((n = imsgbuf_read(ibuf)) == -1) fatal("imsgbuf_read error"); if (n == 0) /* Connection closed */ shut = 1; } if (event & EV_WRITE) { if (imsgbuf_write(ibuf) == -1) fatal("imsgbuf_write"); } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) fatal("imsg_get"); if (n == 0) /* No more messages. */ break; switch (imsg.hdr.type) { case GOTWEBD_IMSG_CFG_ACCESS_RULE: if (TAILQ_EMPTY(&env->servers)) { /* global access rule */ config_get_access_rule(&env->access_rules, &imsg); } else { srv = TAILQ_LAST(&env->servers, serverlist); if (TAILQ_EMPTY(&srv->repos)) { /* per-server access rule */ config_get_access_rule( &srv->access_rules, &imsg); } else { /* per-repository access rule */ repo = TAILQ_LAST(&srv->repos, gotwebd_repolist); config_get_access_rule( &repo->access_rules, &imsg); } } break; case GOTWEBD_IMSG_CFG_SRV: config_getserver(gotwebd_env, &imsg); break; case GOTWEBD_IMSG_CFG_REPO: if (TAILQ_EMPTY(&env->servers)) fatalx("%s: unexpected CFG_REPO msg", __func__); srv = TAILQ_LAST(&env->servers, serverlist); config_get_repository(&srv->repos, &imsg); break; case GOTWEBD_IMSG_CTL_PIPE: if (env->iev_sockets == NULL) recv_sockets_pipe(env, &imsg); else recv_gotweb_pipe(env, &imsg); break; case GOTWEBD_IMSG_CTL_START: auth_launch(env); break; case GOTWEBD_IMSG_LOGIN_SECRET: if (imsg_get_data(&imsg, login_token_secret, sizeof(login_token_secret)) == -1) fatalx("invalid LOGIN_SECRET msg"); break; case GOTWEBD_IMSG_AUTH_SECRET: if (imsg_get_data(&imsg, auth_token_secret, sizeof(auth_token_secret)) == -1) fatalx("invalid AUTH_SECRET msg"); break; case GOTWEBD_IMSG_AUTH_CONF: if (imsg_get_data(&imsg, &env->auth_config, sizeof(env->auth_config)) == -1) fatalx("invalid AUTH_CONF msg"); break; case GOTWEBD_IMSG_WWW_UID: if (imsg_get_data(&imsg, &env->www_uid, sizeof(env->www_uid)) == -1) fatalx("invalid WWW_UID msg"); break; default: fatalx("%s: unknown imsg type %d", __func__, imsg.hdr.type); } imsg_free(&imsg); } if (!shut) imsg_event_add(iev); else { /* This pipe is dead. Remove its event handler */ event_del(&iev->ev); event_loopexit(NULL); } } void gotwebd_auth(struct gotwebd *env, int fd) { struct event sighup, sigint, sigusr1, sigchld, sigterm; struct event_base *evb; evb = event_init(); if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL) fatal("malloc"); if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1) fatal("imsgbuf_init"); imsgbuf_allow_fdpass(&env->iev_parent->ibuf); env->iev_parent->handler = auth_dispatch_main; env->iev_parent->data = env->iev_parent; event_set(&env->iev_parent->ev, fd, EV_READ, auth_dispatch_main, env->iev_parent); event_add(&env->iev_parent->ev, NULL); signal(SIGPIPE, SIG_IGN); signal_set(&sighup, SIGHUP, auth_sighdlr, env); signal_add(&sighup, NULL); signal_set(&sigint, SIGINT, auth_sighdlr, env); signal_add(&sigint, NULL); signal_set(&sigusr1, SIGUSR1, auth_sighdlr, env); signal_add(&sigusr1, NULL); signal_set(&sigchld, SIGCHLD, auth_sighdlr, env); signal_add(&sigchld, NULL); signal_set(&sigterm, SIGTERM, auth_sighdlr, env); signal_add(&sigterm, NULL); #ifndef PROFILE if (pledge("stdio getpw recvfd sendfd", NULL) == -1) fatal("pledge"); #endif event_dispatch(); event_base_free(evb); auth_shutdown(); } got-portable-0.119/gotwebd/Makefile.in0000664000175000017500000015033615066537207013331 # Makefile.in generated by automake 1.17 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2024 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) am__rm_f = rm -f $(am__rm_f_notfound) am__rm_rf = rm -rf $(am__rm_f_notfound) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = gotwebd$(EXEEXT) @HOST_FREEBSD_TRUE@am__append_1 = -lmd subdir = gotwebd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/got_compat.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" PROGRAMS = $(sbin_PROGRAMS) am__dirstamp = $(am__leading_dot)dirstamp am_gotwebd_OBJECTS = config.$(OBJEXT) \ $(top_builddir)/lib/blame.$(OBJEXT) \ $(top_builddir)/lib/bloom.$(OBJEXT) \ $(top_builddir)/lib/buf.$(OBJEXT) \ $(top_builddir)/lib/commit_graph.$(OBJEXT) \ $(top_builddir)/lib/date.$(OBJEXT) \ $(top_builddir)/lib/deflate.$(OBJEXT) \ $(top_builddir)/lib/delta.$(OBJEXT) \ $(top_builddir)/lib/delta_cache.$(OBJEXT) \ $(top_builddir)/lib/diff.$(OBJEXT) \ $(top_builddir)/lib/diff3.$(OBJEXT) \ $(top_builddir)/lib/diff_atomize_text.$(OBJEXT) \ $(top_builddir)/lib/diff_main.$(OBJEXT) \ $(top_builddir)/lib/diff_myers.$(OBJEXT) \ $(top_builddir)/lib/diff_output.$(OBJEXT) \ $(top_builddir)/lib/diff_output_edscript.$(OBJEXT) \ $(top_builddir)/lib/diff_output_plain.$(OBJEXT) \ $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT) \ $(top_builddir)/lib/diff_patience.$(OBJEXT) \ $(top_builddir)/lib/diffreg.$(OBJEXT) \ $(top_builddir)/lib/error.$(OBJEXT) \ $(top_builddir)/lib/fileindex.$(OBJEXT) \ $(top_builddir)/lib/gotconfig.$(OBJEXT) \ $(top_builddir)/lib/hash.$(OBJEXT) \ $(top_builddir)/lib/inflate.$(OBJEXT) \ $(top_builddir)/lib/lockfile.$(OBJEXT) \ $(top_builddir)/lib/log.$(OBJEXT) \ $(top_builddir)/lib/murmurhash2.$(OBJEXT) \ $(top_builddir)/lib/object.$(OBJEXT) \ $(top_builddir)/lib/object_cache.$(OBJEXT) \ $(top_builddir)/lib/object_create.$(OBJEXT) \ $(top_builddir)/lib/object_idset.$(OBJEXT) \ $(top_builddir)/lib/object_open_privsep.$(OBJEXT) \ $(top_builddir)/lib/object_parse.$(OBJEXT) \ $(top_builddir)/lib/object_qid.$(OBJEXT) \ $(top_builddir)/lib/opentemp.$(OBJEXT) \ $(top_builddir)/lib/pack.$(OBJEXT) \ $(top_builddir)/lib/patch.$(OBJEXT) \ $(top_builddir)/lib/path.$(OBJEXT) \ $(top_builddir)/lib/pollfd.$(OBJEXT) \ $(top_builddir)/lib/privsep.$(OBJEXT) \ $(top_builddir)/lib/rcsutil.$(OBJEXT) \ $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT) \ $(top_builddir)/lib/reference.$(OBJEXT) \ $(top_builddir)/lib/reference_parse.$(OBJEXT) \ $(top_builddir)/lib/repository.$(OBJEXT) \ $(top_builddir)/lib/sigs.$(OBJEXT) \ $(top_builddir)/lib/utf8.$(OBJEXT) \ $(top_builddir)/lib/worktree.$(OBJEXT) \ $(top_builddir)/lib/worktree_open.$(OBJEXT) \ $(top_builddir)/template/tmpl.$(OBJEXT) auth.$(OBJEXT) \ fcgi.$(OBJEXT) got_operations.$(OBJEXT) gotweb.$(OBJEXT) \ gotwebd.$(OBJEXT) login.$(OBJEXT) pages.$(OBJEXT) \ parse.$(OBJEXT) sockets.$(OBJEXT) gotwebd_OBJECTS = $(am_gotwebd_OBJECTS) gotwebd_LDADD = $(LDADD) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/etc/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/lib/$(DEPDIR)/blame.Po \ $(top_builddir)/lib/$(DEPDIR)/bloom.Po \ $(top_builddir)/lib/$(DEPDIR)/buf.Po \ $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po \ $(top_builddir)/lib/$(DEPDIR)/date.Po \ $(top_builddir)/lib/$(DEPDIR)/deflate.Po \ $(top_builddir)/lib/$(DEPDIR)/delta.Po \ $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/diff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff3.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_main.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po \ $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po \ $(top_builddir)/lib/$(DEPDIR)/diffreg.Po \ $(top_builddir)/lib/$(DEPDIR)/error.Po \ $(top_builddir)/lib/$(DEPDIR)/fileindex.Po \ $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po \ $(top_builddir)/lib/$(DEPDIR)/hash.Po \ $(top_builddir)/lib/$(DEPDIR)/inflate.Po \ $(top_builddir)/lib/$(DEPDIR)/lockfile.Po \ $(top_builddir)/lib/$(DEPDIR)/log.Po \ $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po \ $(top_builddir)/lib/$(DEPDIR)/object.Po \ $(top_builddir)/lib/$(DEPDIR)/object_cache.Po \ $(top_builddir)/lib/$(DEPDIR)/object_create.Po \ $(top_builddir)/lib/$(DEPDIR)/object_idset.Po \ $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/object_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/object_qid.Po \ $(top_builddir)/lib/$(DEPDIR)/opentemp.Po \ $(top_builddir)/lib/$(DEPDIR)/pack.Po \ $(top_builddir)/lib/$(DEPDIR)/patch.Po \ $(top_builddir)/lib/$(DEPDIR)/path.Po \ $(top_builddir)/lib/$(DEPDIR)/pollfd.Po \ $(top_builddir)/lib/$(DEPDIR)/privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po \ $(top_builddir)/lib/$(DEPDIR)/reference.Po \ $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po \ $(top_builddir)/lib/$(DEPDIR)/repository.Po \ $(top_builddir)/lib/$(DEPDIR)/sigs.Po \ $(top_builddir)/lib/$(DEPDIR)/utf8.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree.Po \ $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po \ $(top_builddir)/template/$(DEPDIR)/tmpl.Po ./$(DEPDIR)/auth.Po \ ./$(DEPDIR)/config.Po ./$(DEPDIR)/fcgi.Po \ ./$(DEPDIR)/got_operations.Po ./$(DEPDIR)/gotweb.Po \ ./$(DEPDIR)/gotwebd.Po ./$(DEPDIR)/login.Po \ ./$(DEPDIR)/pages.Po ./$(DEPDIR)/parse.Po \ ./$(DEPDIR)/sockets.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = YLWRAP = $(top_srcdir)/etc/ylwrap SOURCES = $(gotwebd_SOURCES) DIST_SOURCES = $(gotwebd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \ } man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man5_MANS) $(man8_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/etc/depcomp \ $(top_srcdir)/etc/ylwrap parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_CFLAGS = @AM_CFLAGS@ AM_CPPFLAGS = @AM_CPPFLAGS@ $(libbsd_CFLAGS) $(libcrypto_CFLAGS) \ $(libevent_CFLAGS) $(zlib_CFLAGS) $(libuuid_CFLAGS) \ $(libmd_CFLAGS) AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_LDFLAGS = @AM_LDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GITWRAPPER_LIBEXEC_PATHC = @GITWRAPPER_LIBEXEC_PATHC@ GOTD_EMPTY_PATHC = @GOTD_EMPTY_PATHC@ GOT_RELEASE = @GOT_RELEASE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBBSD_CFLAGS = @LIBBSD_CFLAGS@ LIBBSD_LIBS = @LIBBSD_LIBS@ LIBCRYPTO_CFLAGS = @LIBCRYPTO_CFLAGS@ LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@ LIBEVENT_CFLAGS = @LIBEVENT_CFLAGS@ LIBEVENT_CORE_CFLAGS = @LIBEVENT_CORE_CFLAGS@ LIBEVENT_CORE_LIBS = @LIBEVENT_CORE_LIBS@ LIBEVENT_LIBS = @LIBEVENT_LIBS@ LIBMD_CFLAGS = @LIBMD_CFLAGS@ LIBMD_LIBS = @LIBMD_LIBS@ LIBNCURSES_CFLAGS = @LIBNCURSES_CFLAGS@ LIBNCURSES_LIBS = @LIBNCURSES_LIBS@ LIBOBJS = @LIBOBJS@ LIBPANELW_CFLAGS = @LIBPANELW_CFLAGS@ LIBPANELW_LIBS = @LIBPANELW_LIBS@ LIBS = @LIBS@ LIBTLS_CFLAGS = @LIBTLS_CFLAGS@ LIBTLS_LIBS = @LIBTLS_LIBS@ LIBUUID_CFLAGS = @LIBUUID_CFLAGS@ LIBUUID_LIBS = @LIBUUID_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLATFORM = @PLATFORM@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB_CFLAGS = @ZLIB_CFLAGS@ ZLIB_LIBS = @ZLIB_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__rm_f_notfound = @am__rm_f_notfound@ am__tar = @am__tar@ am__untar = @am__untar@ am__xargs_n = @am__xargs_n@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libbsd_CFLAGS = @libbsd_CFLAGS@ libbsd_LIBS = @libbsd_LIBS@ libcrypto_CFLAGS = @libcrypto_CFLAGS@ libcrypto_LIBS = @libcrypto_LIBS@ libdir = @libdir@ libevent_CFLAGS = @libevent_CFLAGS@ libevent_LIBS = @libevent_LIBS@ libexecdir = @libexecdir@ libmd_CFLAGS = @libmd_CFLAGS@ libmd_LIBS = @libmd_LIBS@ libncurses_CFLAGS = @libncurses_CFLAGS@ libncurses_LIBS = @libncurses_LIBS@ libresolv_LIBS = @libresolv_LIBS@ libtls_CFLAGS = @libtls_CFLAGS@ libtls_LIBS = @libtls_LIBS@ libutil_LIBS = @libutil_LIBS@ libuuid_CFLAGS = @libuuid_CFLAGS@ libuuid_LIBS = @libuuid_LIBS@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ zlib_CFLAGS = @zlib_CFLAGS@ zlib_LIBS = @zlib_LIBS@ # /home/n6tadam/projects/got/gotwebd/../template/template -o pages.c pages.tmpl BUILT_SOURCES = pages.c CLEANFILES = pages.c parse.c gotwebd_SOURCES = config.c \ $(top_srcdir)/lib/blame.c \ $(top_srcdir)/lib/bloom.c \ $(top_srcdir)/lib/buf.c \ $(top_srcdir)/lib/commit_graph.c \ $(top_srcdir)/lib/date.c \ $(top_srcdir)/lib/deflate.c \ $(top_srcdir)/lib/delta.c \ $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/diff.c \ $(top_srcdir)/lib/diff3.c \ $(top_srcdir)/lib/diff_atomize_text.c \ $(top_srcdir)/lib/diff_main.c \ $(top_srcdir)/lib/diff_myers.c \ $(top_srcdir)/lib/diff_output.c \ $(top_srcdir)/lib/diff_output_edscript.c \ $(top_srcdir)/lib/diff_output_plain.c \ $(top_srcdir)/lib/diff_output_unidiff.c \ $(top_srcdir)/lib/diff_patience.c \ $(top_srcdir)/lib/diffreg.c \ $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/fileindex.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/hash.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/log.c \ $(top_srcdir)/lib/murmurhash2.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/object_qid.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/patch.c \ $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/pollfd.c \ $(top_srcdir)/lib/privsep.c \ $(top_srcdir)/lib/rcsutil.c \ $(top_srcdir)/lib/read_gitconfig_privsep.c \ $(top_srcdir)/lib/read_gotconfig_privsep.c \ $(top_srcdir)/lib/reference.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c \ $(top_srcdir)/lib/utf8.c \ $(top_srcdir)/lib/worktree.c \ $(top_srcdir)/lib/worktree_open.c \ $(top_srcdir)/template/tmpl.c \ auth.c \ fcgi.c \ got_operations.c \ gotweb.c \ gotwebd.c \ login.c \ pages.c \ parse.y \ sockets.c gotwebd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = $(top_srcdir)/gotwebd/*.h \ $(top_srcdir)/gotwebd/*.tmpl \ $(top_srcdir)/template/tmpl.h \ gotwebd.8 gotwebd.conf.5 man5_MANS = gotwebd.conf.5 man8_MANS = gotwebd.8 LDADD = -L$(top_builddir)/compat -L$(top_builddir)/template \ -lopenbsd-compat -lm $(libbsd_LIBS) $(libcrypto_LIBS) \ $(libevent_LIBS) $(zlib_LIBS) $(libuuid_LIBS) $(libutil_LIBS) \ $(libmd_LIBS) $(am__append_1) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gotwebd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gotwebd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && $(am__rm_f) $$files clean-sbinPROGRAMS: -$(am__rm_f) $(sbin_PROGRAMS) $(top_builddir)/lib/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib @: >>$(top_builddir)/lib/$(am__dirstamp) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/lib/$(DEPDIR) @: >>$(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/blame.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/bloom.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/buf.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/commit_graph.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/date.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/deflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/delta_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff3.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_atomize_text.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_main.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_myers.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_edscript.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_plain.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_output_unidiff.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diff_patience.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/diffreg.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/error.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/fileindex.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/gotconfig.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/hash.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/inflate.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/lockfile.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/log.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/murmurhash2.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_cache.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_create.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_idset.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_open_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/object_qid.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/opentemp.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pack.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/patch.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/path.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/pollfd.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/rcsutil.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gitconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/read_gotconfig_privsep.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/reference_parse.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/repository.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/sigs.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/utf8.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/lib/worktree_open.$(OBJEXT): \ $(top_builddir)/lib/$(am__dirstamp) \ $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/template/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/template @: >>$(top_builddir)/template/$(am__dirstamp) $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) $(top_builddir)/template/$(DEPDIR) @: >>$(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) $(top_builddir)/template/tmpl.$(OBJEXT): \ $(top_builddir)/template/$(am__dirstamp) \ $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) gotwebd$(EXEEXT): $(gotwebd_OBJECTS) $(gotwebd_DEPENDENCIES) $(EXTRA_gotwebd_DEPENDENCIES) @rm -f gotwebd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gotwebd_OBJECTS) $(gotwebd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f $(top_builddir)/lib/*.$(OBJEXT) -rm -f $(top_builddir)/template/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/blame.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/bloom.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/buf.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/commit_graph.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/date.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/deflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/delta_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff3.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_myers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diff_patience.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/diffreg.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/fileindex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/gotconfig.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/hash.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/inflate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/lockfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_create.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_idset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/object_qid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/opentemp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pack.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/patch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/pollfd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/rcsutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/reference_parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/repository.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/sigs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/utf8.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/lib/$(DEPDIR)/worktree_open.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/template/$(DEPDIR)/tmpl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fcgi.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/got_operations.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotweb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gotwebd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/login.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pages.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockets.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @: >>$@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) install-man5: $(man5_MANS) @$(NORMAL_INSTALL) @list1='$(man5_MANS)'; \ list2=''; \ test -n "$(man5dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.5[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ done; } uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -$(am__rm_f) $(CLEANFILES) distclean-generic: -$(am__rm_f) $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES) -$(am__rm_f) $(top_builddir)/lib/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/lib/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/template/$(DEPDIR)/$(am__dirstamp) -$(am__rm_f) $(top_builddir)/template/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -$(am__rm_f) $(BUILT_SOURCES) -$(am__rm_f) parse.c clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f $(top_builddir)/template/$(DEPDIR)/tmpl.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/fcgi.Po -rm -f ./$(DEPDIR)/got_operations.Po -rm -f ./$(DEPDIR)/gotweb.Po -rm -f ./$(DEPDIR)/gotwebd.Po -rm -f ./$(DEPDIR)/login.Po -rm -f ./$(DEPDIR)/pages.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/sockets.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man5 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/lib/$(DEPDIR)/blame.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/bloom.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/buf.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/commit_graph.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/date.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/deflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/delta_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff3.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_atomize_text.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_main.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_myers.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_edscript.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_plain.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_output_unidiff.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diff_patience.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/diffreg.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/error.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/fileindex.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/gotconfig.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/hash.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/inflate.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/lockfile.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/log.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/murmurhash2.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_cache.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_create.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_idset.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_open_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/object_qid.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/opentemp.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pack.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/patch.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/path.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/pollfd.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/rcsutil.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gitconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/read_gotconfig_privsep.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/reference_parse.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/repository.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/sigs.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/utf8.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree.Po -rm -f $(top_builddir)/lib/$(DEPDIR)/worktree_open.Po -rm -f $(top_builddir)/template/$(DEPDIR)/tmpl.Po -rm -f ./$(DEPDIR)/auth.Po -rm -f ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/fcgi.Po -rm -f ./$(DEPDIR)/got_operations.Po -rm -f ./$(DEPDIR)/gotweb.Po -rm -f ./$(DEPDIR)/gotwebd.Po -rm -f ./$(DEPDIR)/login.Po -rm -f ./$(DEPDIR)/pages.Po -rm -f ./$(DEPDIR)/parse.Po -rm -f ./$(DEPDIR)/sockets.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: all check install install-am install-exec install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man5 install-man8 install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-man uninstall-man5 uninstall-man8 \ uninstall-sbinPROGRAMS .PRECIOUS: Makefile include $(top_builddir)/Makefile.common pages.c: $(top_srcdir)/gotwebd/pages.tmpl ${MAKE} -C $(top_builddir)/template $(top_builddir)/template/template -o pages.c $(top_srcdir)/gotwebd/pages.tmpl #realinstall: # if [ ! -d ${DESTDIR}${PUB_REPOS_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PUB_REPOS_DIR}; \ # fi # ${INSTALL} -c -o root -g daemon -m 0755 ${PROG} ${BINDIR}/${PROG} # if [ ! -d ${DESTDIR}${HTTPD_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${HTTPD_DIR}; \ # fi # if [ ! -d ${DESTDIR}${PROG_DIR}/. ]; then \ # ${INSTALL} -d -o root -g daemon -m 755 ${DESTDIR}${PROG_DIR}; \ # fi # ${INSTALL} -c -o ${WWWUSR} -g ${WWWGRP} -m 0755 \ # ${.CURDIR}/files/htdocs/${PROG}/* ${DESTDIR}${PROG_DIR} # #.include # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Tell GNU make to disable its built-in pattern rules. %:: %,v %:: RCS/%,v %:: RCS/% %:: s.% %:: SCCS/s.% got-portable-0.119/include/0000775000175000017500000000000015066537274011330 5got-portable-0.119/include/got_serve.h0000664000175000017500000000164015066535721013412 /* * Copyright (c) 2022 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_serve(int infd, int outfd, const char *command, const char *repo_path, int gotd_sock, int chattygot); got-portable-0.119/include/got_compat2.h0000664000175000017500000002225015066536113013627 /* * Copyright (c) 2023 Thomas Adam * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _GOT_COMPAT_H_2 #define _GOT_COMPAT_H_2 #ifdef HAVE_STDINT_H #include #else #include #endif #include #include #if defined(__FreeBSD__) #include #include #elif defined(__APPLE__) #include #include #include "compat/bsd-poll.h" #define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #define st_atim st_atimespec #define st_ctim st_ctimespec #define st_mtim st_mtimespec #else /* Linux, etc... */ #include #include #include #endif #ifndef __GNUC__ #define __attribute__(a) #endif #ifndef _PW_NAME_LEN #define _PW_NAME_LEN 31 /* max length, not counting NUL */ #endif #ifndef UID_MAX # define UID_MAX UINT_MAX /* max value for a uid_t */ #endif #ifndef GID_MAX # define GID_MAX UINT_MAX /* max value for a gid_t */ #endif /* For flock. */ #ifndef O_EXLOCK #define O_EXLOCK 0 #endif #ifndef HAVE_FLOCK #define LOCK_SH 0 #define LOCK_EX 0 #define LOCK_NB 0 #define flock(fd, op) (0) #else #include #endif /* POSIX doesn't define WAIT_ANY, so provide it if it's not found. */ #ifndef WAIT_ANY #define WAIT_ANY (-1) #endif /* On FreeBSD (and possibly others), EAI_NODATA was removed, in favour of * using EAI_NONAME. */ #ifndef EAI_NODATA #define EAI_NODATA EAI_NONAME #endif #ifndef __dead #define __dead __attribute__ ((__noreturn__)) #endif #ifndef __unused #define __unused __attribute__ ((__unused__)) #endif #if !defined(__bounded__) && !defined(__OpenBSD__) #define __bounded__(a, b, c) #endif #ifndef __OpenBSD__ #define pledge(s, p) (0) #define unveil(s, p) (0) #endif #ifndef __FreeBSD__ #define cap_enter() (0) #endif #ifndef HAVE_B64_NTOP #undef b64_ntop #undef b64_pton int b64_ntop(u_char const *, size_t, char *, size_t); int b64_pton(char const *, u_char *, size_t); #endif #ifndef HAVE_SETRESGID #define setresgid(a, b, c) (0) #endif #ifndef HAVE_SETRESUID #define setresuid(a, b, c) (0) #endif #ifndef HAVE_LINUX_LANDLOCK_H #define landlock_no_fs() (0) #else int landlock_no_fs(void); #endif #ifndef INFTIM #define INFTIM -1 #endif #ifndef HAVE_BSD_UUID #include #define uuid_s_ok 0 #define uuid_s_bad_version 1 #define uuid_s_invalid_string_uuid 2 #define uuid_s_no_memory 3 /* Length of a node address (an IEEE 802 address). */ #define _UUID_NODE_LEN 6 struct uuid { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_version; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[_UUID_NODE_LEN]; }; int32_t uuid_equal(struct uuid *, struct uuid *, uint32_t *); int32_t uuid_is_nil(struct uuid *, uint32_t *); void uuid_create(uuid_t *, uint32_t *); void uuid_create_nil(struct uuid *, uint32_t *); void uuid_from_string(const char *, uuid_t *, uint32_t *); void uuid_to_string(uuid_t *, char **, uint32_t *); #else #include #endif #ifdef HAVE_QUEUE_H #include #endif #ifndef HAVE_TREE_H #include "compat/tree.h" #else #include #endif #ifdef HAVE_UTIL_H #include #endif #ifdef HAVE_LIBUTIL_H #include #endif #ifndef IOV_MAX # define IOV_MAX 1024 #endif #ifndef HAVE_IMSG #include "compat/imsg.h" #else #include #endif #ifndef HAVE_SIPHASH #include "compat/siphash.h" #else #include #endif /* Include Apple-specific headers. Mostly for crypto.*/ #if defined(__APPLE__) #define COMMON_DIGEST_FOR_OPENSSL #include #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) #define SHA256Init SHA256_Init #define SHA256Update SHA256_Update #define SHA256Final SHA256_Final #define SHA2_CTX SHA256_CTX #endif #ifndef __APPLE__ #ifdef HAVE_SHA_H # include #endif #ifdef HAVE_SHA1_H # include #endif #ifdef HAVE_SHA2_H # include #endif #ifdef HAVE_SHA256_H # include #endif #endif /* Catch-all for systems where the header files don't exist and/or the below * still are not defined. */ #ifndef SHA256_DIGEST_LENGTH #define SHA256_DIGEST_LENGTH 32 #endif #ifndef SHA256_DIGEST_STRING_LENGTH #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #endif #if defined(__DragonFly__) #include #endif #ifndef SHA1_DIGEST_LENGTH #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) #define SHA1_CTX SHA_CTX #define SHA1Init SHA1_Init #define SHA1Update SHA1_Update #define SHA1Final SHA1_Final #endif /* SOCK_NONBLOCK isn't available across BSDs... */ #if !defined(SOCK_NONBLOCK) && !defined(__linux__) #define SOCK_NONBLOCK 00004000 #endif #ifndef HAVE_ASPRINTF /* asprintf.c */ int asprintf(char **, const char *, ...); int vasprintf(char **, const char *, va_list); #endif #ifndef HAVE_EXPLICIT_BZERO /* explicit_bzero.c */ void explicit_bzero(void *, size_t); #endif #ifndef HAVE_GETDTABLECOUNT /* getdtablecount.c */ int getdtablecount(void); #endif #ifndef HAVE_CLOSEFROM /* closefrom.c */ void closefrom(int); #endif #ifndef HAVE_STRSEP /* strsep.c */ char *strsep(char **, const char *); #endif #ifndef HAVE_STRTONUM /* strtonum.c */ long long strtonum(const char *, long long, long long, const char **); #endif #ifndef HAVE_STRLCPY /* strlcpy.c */ size_t strlcpy(char *, const char *, size_t); #endif #ifndef HAVE_STRLCAT /* strlcat.c */ size_t strlcat(char *, const char *, size_t); #endif #ifndef HAVE_STRNLEN /* strnlen.c */ size_t strnlen(const char *, size_t); #endif #ifndef HAVE_STRNDUP /* strndup.c */ char *strndup(const char *, size_t); #endif #ifndef HAVE_GETPROGNAME /* getprogname.c */ const char *getprogname(void); #endif #ifndef HAVE_GETLINE /* getline.c */ ssize_t getline(char **, size_t *, FILE *); #endif #ifndef HAVE_FREEZERO /* freezero.c */ void freezero(void *, size_t); #endif #ifndef HAVE_GETDTABLECOUNT /* getdtablecount.c */ int getdtablecount(void); #endif #ifndef HAVE_REALLOCARRAY /* reallocarray.c */ void *reallocarray(void *, size_t, size_t); #endif #ifndef HAVE_RECALLOCARRAY /* recallocarray.c */ void *recallocarray(void *, size_t, size_t, size_t); #endif #ifndef HAVE_SETPROCTITLE /* setproctitle.c */ void setproctitle(const char *, ...); #endif #ifndef HAVE_FMT_SCALED /* fmt_scaled.c */ int fmt_scaled(long long, char *); int scan_scaled(char *, long long *); #define FMT_SCALED_STRSIZE 7 /* minus sign, 4 digits, suffix, null byte */ #endif #if !defined(HAVE_LIBBSD) && !defined(HAVE_GETOPT_OPTRESET) /* getopt.c */ extern int BSDopterr; extern int BSDoptind; extern int BSDoptopt; extern int BSDoptreset; extern char *BSDoptarg; int BSDgetopt(int, char *const *, const char *); #define getopt(ac, av, o) BSDgetopt(ac, av, o) #define opterr BSDopterr #define optind BSDoptind #define optopt BSDoptopt #define optreset BSDoptreset #define optarg BSDoptarg #endif /* Check for some of the non-portable timespec*() functions. * This should largely come from libbsd for systems which * aren't BSD, but this will depend on how old the library * is. */ #ifndef timespecisset #define timespecisset(tsp) \ ((tsp)->tv_sec || (tsp)->tv_nsec) #endif #ifndef timespecsub #define timespecsub(tsp, usp, vsp) \ do { \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ if ((vsp)->tv_nsec < 0) { \ (vsp)->tv_sec--; \ (vsp)->tv_nsec += 1000000000L; \ } \ } while (0) #endif #ifndef timespeccmp #define timespeccmp(tvp, uvp, cmp) \ (((tvp)->tv_sec == (uvp)->tv_sec) ? \ ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ ((tvp)->tv_sec cmp (uvp)->tv_sec)) #endif #ifndef HAVE_MERGESORT /* mergesort.c */ int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); #endif #endif /* got_object.h */ #define GOT_OBJECT_ID_MAXLEN SHA256_DIGEST_LENGTH #define GOT_OBJECT_ID_HEX_MAXLEN SHA256_DIGEST_STRING_LENGTH got-portable-0.119/include/got_dial.h0000664000175000017500000000310415066535721013174 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Apply any unveil(2) operations required to support the given protocol, * as obtained from the 'proto' output parameter of got_dial_parse_uri(). * This function must be called during initialization of the main program * if got_fetch.h or got_send.h functionality will be used. */ const struct got_error *got_dial_apply_unveil(const char *proto); /* * Attempt to parse a URI into the following parts: * A protocol scheme, hostname, port number (as a string), path on server, * and a repository name. If the URI lacks some of this information return * default values where applicable. * The caller should dispose of the returned values with free(3). */ const struct got_error *got_dial_parse_uri(char **proto, char **host, char **port, char **server_path, char **repo_name, const char *uri); got-portable-0.119/include/got_compat.h0000664000175000017500000004136215066537226013560 /* include/got_compat.h. Generated from got_compat.h.in by configure. */ /* include/got_compat.h.in. Generated from configure.ac by autoheader. */ /* GoT version string */ #define GOT_VERSION VERSION /* Got version number */ #define GOT_VERSION_NUMBER VERSION /* Define to 1 if you have the 'asprintf' function. */ #define HAVE_ASPRINTF 1 /* define if b64_ntop is present */ #define HAVE_B64_NTOP 1 /* BSD UUID */ /* #undef HAVE_BSD_UUID */ /* Define to 1 if you have the 'closefrom' function. */ #define HAVE_CLOSEFROM 1 /* Curses_h */ /* #undef HAVE_CURSES_H */ /* Define to 1 if you have the declaration of 'strerror_r', and to 0 if you don't. */ #define HAVE_DECL_STRERROR_R 1 /* Define to 1 if you have the header file, and it defines 'DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the 'dup2' function. */ #define HAVE_DUP2 1 /* libevent2 has event.h */ /* #undef HAVE_EVENT2_EVENT_H */ /* libevent */ /* #undef HAVE_EVENT_H */ /* Define to 1 if you have the 'explicit_bzero' function. */ #define HAVE_EXPLICIT_BZERO 1 /* Use F_CLOSEM fcntl for closefrom */ /* #undef HAVE_FCNTL_CLOSEM */ /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if you have the 'flock' function. */ #define HAVE_FLOCK 1 /* Define to 1 if you have the 'fmt_scaled' function. */ /* #undef HAVE_FMT_SCALED */ /* Define to 1 if you have the 'fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the 'freezero' function. */ /* #undef HAVE_FREEZERO */ /* Define to 1 if fseeko (and ftello) are declared in stdio.h. */ #define HAVE_FSEEKO 1 /* Define to 1 if you have the 'getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the 'getdtablecount' function. */ /* #undef HAVE_GETDTABLECOUNT */ /* Define to 1 if you have the 'getline' function. */ #define HAVE_GETLINE 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define if your getopt(3) defines and uses optreset */ /* #undef HAVE_GETOPT_OPTRESET */ /* Define to 1 if you have the 'getpagesize' function. */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the 'getprogname' function. */ /* #undef HAVE_GETPROGNAME */ /* Define to 1 if imsg is declared in libutil */ /* #undef HAVE_IMSG */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LANGINFO_H 1 /* BSD UUID */ #define HAVE_LIBBSD 1 /* Define to 1 if you have the 'panelw' library (-lpanelw). */ /* #undef HAVE_LIBPANELW */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBUTIL_H */ /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LINUX_LANDLOCK_H 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define to 1 if you have the 'localtime_r' function. */ #define HAVE_LOCALTIME_R 1 /* Define to 1 if your system has a GNU libc compatible 'malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the 'memchr' function. */ #define HAVE_MEMCHR 1 /* Define to 1 if you have the 'memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the 'memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the 'mergesort' function. */ /* #undef HAVE_MERGESORT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MINIX_CONFIG_H */ /* Define to 1 if you have the 'mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have a working 'mmap' system call. */ #define HAVE_MMAP 1 /* Define to 1 if you have the 'munmap' function. */ #define HAVE_MUNMAP 1 /* NCurses */ #define HAVE_NCURSES_H 1 /* Define to 1 if you have the header file, and it defines 'DIR'. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the 'nl_langinfo' function. */ #define HAVE_NL_LANGINFO 1 /* Define to 1 if you have the header file. */ #define HAVE_PATHS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_POLL_H 1 /* Define if you have /proc/$pid/fd */ #define HAVE_PROC_PID 1 /* Define if program_invocation_short_name is defined */ #define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 /* Define if PR_SET_NAME is defined */ #define HAVE_PR_SET_NAME 1 /* sys/queue.h */ #define HAVE_QUEUE_H 1 /* Define to 1 if your system has a GNU libc compatible 'realloc' function, and to 0 otherwise. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the 'reallocarray' function. */ #define HAVE_REALLOCARRAY 1 /* Define to 1 if you have the 'realpath' function. */ #define HAVE_REALPATH 1 /* Define to 1 if you have the 'recallocarray' function. */ /* #undef HAVE_RECALLOCARRAY */ /* Define to 1 if you have the 'regcomp' function. */ #define HAVE_REGCOMP 1 /* Define to 1 if you have the 'rmdir' function. */ #define HAVE_RMDIR 1 /* Define to 1 if you have the 'setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the 'setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ /* Define to 1 if you have the 'setresgid' function. */ #define HAVE_SETRESGID 1 /* Define to 1 if you have the 'setresuid' function. */ #define HAVE_SETRESUID 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA1_H 1 /* Define to 1 if you have the 'SHA256Update' function. */ /* #undef HAVE_SHA256UPDATE */ /* Define to 1 if you have the header file. */ #define HAVE_SHA256_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA2_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SHA_H 1 /* Define to 1 if you have the 'SipHash' function. */ /* #undef HAVE_SIPHASH */ /* Define to 1 if you have the 'socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ #define HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the 'strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the 'strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the 'strcspn' function. */ #define HAVE_STRCSPN 1 /* Define to 1 if you have the 'strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the 'strerror' function. */ #define HAVE_STRERROR 1 /* Define if you have 'strerror_r'. */ #define HAVE_STRERROR_R 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the 'strlcat' function. */ #define HAVE_STRLCAT 1 /* Define to 1 if you have the 'strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the 'strncasecmp' function. */ #define HAVE_STRNCASECMP 1 /* Define to 1 if you have the 'strndup' function. */ #define HAVE_STRNDUP 1 /* Define to 1 if you have the 'strnlen' function. */ #define HAVE_STRNLEN 1 /* Define to 1 if you have the 'strrchr' function. */ #define HAVE_STRRCHR 1 /* Define to 1 if you have the 'strsep' function. */ #define HAVE_STRSEP 1 /* Define to 1 if you have the 'strspn' function. */ #define HAVE_STRSPN 1 /* Define to 1 if you have the 'strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if you have the 'strtol' function. */ #define HAVE_STRTOL 1 /* Define to 1 if you have the 'strtonum' function. */ /* #undef HAVE_STRTONUM */ /* Define to 1 if you have the 'strtoul' function. */ #define HAVE_STRTOUL 1 /* Define to 1 if the system has the type 'struct ifgroupreq'. */ /* #undef HAVE_STRUCT_IFGROUPREQ */ /* Define to 1 if 'fd' is a member of 'struct pollfd'. */ #define HAVE_STRUCT_POLLFD_FD 1 /* Define to 1 if 'sa_len' is a member of 'struct sockaddr'. */ /* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */ /* Define to 1 if the system has the type 'struct sockaddr_storage'. */ #define HAVE_STRUCT_SOCKADDR_STORAGE 1 /* Define to 1 if 'ss_len' is a member of 'struct sockaddr_storage'. */ /* #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN */ /* Define to 1 if sysconf() present */ #define HAVE_SYSCONF 1 /* Define to 1 if you have the header file, and it defines 'DIR'. */ /* #undef HAVE_SYS_DIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file, and it defines 'DIR'. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_POLL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_QUEUE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TREE_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TLS_H 1 /* HAVE_TREE_H */ #define HAVE_TREE_H test x"$found_sys_tree_h" = "xyes" /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UTIL_H */ /* Define to 1 if you have the 'vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the header file. */ #define HAVE_WCHAR_H 1 /* Define to 1 if you have the 'wcwidth' function. */ #define HAVE_WCWIDTH 1 /* Define to 1 if 'fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if 'vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Define to 1 if the system has the type '_Bool'. */ #define HAVE__BOOL 1 /* ___progname */ #define HAVE___PROGNAME 1 /* Define to 1 if 'lstat' dereferences a symlink specified with a trailing slash. */ #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 /* Name of package */ #define PACKAGE "got-portable" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "thomas@xteddy.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "got-portable" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "got-portable 0.119" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "got-portable" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.119" /* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Define to 1 if strerror_r returns char *. */ #define STRERROR_R_CHAR_P 1 /* Enable extensions on AIX, Interix, z/OS. */ #ifndef _ALL_SOURCE # define _ALL_SOURCE 1 #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # define _DARWIN_C_SOURCE 1 #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # define __EXTENSIONS__ 1 #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # define _HPUX_ALT_XOPEN_SOCKET_API 1 #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX /* # undef _MINIX */ #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # define _NETBSD_SOURCE 1 #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # define _OPENBSD_SOURCE 1 #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE /* # undef _POSIX_SOURCE */ #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE /* # undef _POSIX_1_SOURCE */ #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # define _POSIX_PTHREAD_SEMANTICS 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # define __STDC_WANT_IEC_60559_BFP_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # define __STDC_WANT_IEC_60559_DFP_EXT__ 1 #endif /* Enable extensions specified by C23 Annex F. */ #ifndef __STDC_WANT_IEC_60559_EXT__ # define __STDC_WANT_IEC_60559_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 #endif /* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # define __STDC_WANT_LIB_EXT2__ 1 #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # define __STDC_WANT_MATH_SPEC_FUNCS__ 1 #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # define _TANDEM_SOURCE 1 #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE /* # undef _XOPEN_SOURCE */ #endif /* Version number of package */ #define VERSION 0.119 /* Define to 1 if necessary to make fseeko visible. */ /* #undef _LARGEFILE_SOURCE */ /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT32_T */ /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT64_T */ /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT8_T */ /* Define to '__inline__' or '__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ /* #undef int64_t */ /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ /* Define to 'int' if does not define. */ /* #undef mode_t */ /* Define to 'long int' if does not define. */ /* #undef off_t */ /* Define as a signed integer type capable of holding a process identifier. */ /* #undef pid_t */ /* Define to rpl_realloc if the replacement function should be used. */ /* #undef realloc */ /* Define as 'unsigned int' if doesn't define. */ /* #undef size_t */ /* Define as 'int' if doesn't define. */ /* #undef ssize_t */ /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ /* #undef uint16_t */ /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ /* #undef uint32_t */ /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ /* #undef uint64_t */ /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ /* #undef uint8_t */ /* Define as 'fork' if 'vfork' does not work. */ /* #undef vfork */ #include "got_compat2.h" got-portable-0.119/include/got_sigs.h0000664000175000017500000000216215066535721013233 /* * Copyright (c) 2022 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error * got_sigs_apply_unveil(void); const struct got_error * got_sigs_sign_tag_ssh(pid_t *, int *, int *, const char *, int); const char * got_sigs_get_tagmsg_ssh_signature(const char *); const struct got_error * got_sigs_verify_tag_ssh(char **, struct got_tag_object *, const char *, const char *, const char *, int); got-portable-0.119/include/got_version.h0000664000175000017500000000213215066535721013750 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef GOT_VERSION #error "GOT_VERSION is undefined" #endif #define GOT_STRINGIFY_VERSION(x) #x #define GOT_STRINGVAL_VERSION(x) GOT_STRINGIFY_VERSION(x) #define GOT_VERSION_STR GOT_STRINGVAL_VERSION(GOT_VERSION) static inline void got_version_print_str(void) { printf("%s %s\n", getprogname(), GOT_VERSION_STR); } got-portable-0.119/include/got_worktree_cvg.h0000664000175000017500000000417615066535721014776 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2023 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Create a new commit from changes in the work tree. * Return the ID of the newly created commit. * The worktree's base commit will be set to this new commit. * Files unaffected by this commit operation will retain their * current base commit. * An author and a non-empty log message must be specified. * The name of the committer is optional (may be NULL). * An optional author timestamp can be specified. The current time will * be used if the specified timestamp is 0. * If a path to be committed contains a symlink which points outside * of the path space under version control, raise an error unless * committing of such paths is being forced by the caller. */ const struct got_error *got_worktree_cvg_commit(struct got_object_id **, struct got_worktree *, struct got_pathlist_head *, const char *, time_t, const char *, int, int, int, got_worktree_commit_msg_cb, void *, got_worktree_status_cb, void *, const char *, const char *, const char *, const char *, const char *, const char *, int, const struct got_remote_repo *, got_cancel_cb, struct got_repository *); /* * Get the reference name for a temporary commit to be trivially rebased * over a remote branch. */ const struct got_error *got_worktree_cvg_get_commit_ref_name(char **, struct got_worktree *); got-portable-0.119/include/got_compat.h.in0000664000175000017500000003756415066537206014174 /* include/got_compat.h.in. Generated from configure.ac by autoheader. */ /* GoT version string */ #undef GOT_VERSION /* Got version number */ #undef GOT_VERSION_NUMBER /* Define to 1 if you have the 'asprintf' function. */ #undef HAVE_ASPRINTF /* define if b64_ntop is present */ #undef HAVE_B64_NTOP /* BSD UUID */ #undef HAVE_BSD_UUID /* Define to 1 if you have the 'closefrom' function. */ #undef HAVE_CLOSEFROM /* Curses_h */ #undef HAVE_CURSES_H /* Define to 1 if you have the declaration of 'strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R /* Define to 1 if you have the header file, and it defines 'DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the 'dup2' function. */ #undef HAVE_DUP2 /* libevent2 has event.h */ #undef HAVE_EVENT2_EVENT_H /* libevent */ #undef HAVE_EVENT_H /* Define to 1 if you have the 'explicit_bzero' function. */ #undef HAVE_EXPLICIT_BZERO /* Use F_CLOSEM fcntl for closefrom */ #undef HAVE_FCNTL_CLOSEM /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the 'flock' function. */ #undef HAVE_FLOCK /* Define to 1 if you have the 'fmt_scaled' function. */ #undef HAVE_FMT_SCALED /* Define to 1 if you have the 'fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the 'freezero' function. */ #undef HAVE_FREEZERO /* Define to 1 if fseeko (and ftello) are declared in stdio.h. */ #undef HAVE_FSEEKO /* Define to 1 if you have the 'getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the 'getdtablecount' function. */ #undef HAVE_GETDTABLECOUNT /* Define to 1 if you have the 'getline' function. */ #undef HAVE_GETLINE /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define if your getopt(3) defines and uses optreset */ #undef HAVE_GETOPT_OPTRESET /* Define to 1 if you have the 'getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the 'getprogname' function. */ #undef HAVE_GETPROGNAME /* Define to 1 if imsg is declared in libutil */ #undef HAVE_IMSG /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H /* BSD UUID */ #undef HAVE_LIBBSD /* Define to 1 if you have the 'panelw' library (-lpanelw). */ #undef HAVE_LIBPANELW /* Define to 1 if you have the header file. */ #undef HAVE_LIBUTIL_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_LANDLOCK_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the 'localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if your system has a GNU libc compatible 'malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the 'memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the 'memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the 'memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the 'mergesort' function. */ #undef HAVE_MERGESORT /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the 'mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have a working 'mmap' system call. */ #undef HAVE_MMAP /* Define to 1 if you have the 'munmap' function. */ #undef HAVE_MUNMAP /* NCurses */ #undef HAVE_NCURSES_H /* Define to 1 if you have the header file, and it defines 'DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the 'nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if you have the header file. */ #undef HAVE_PATHS_H /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define if you have /proc/$pid/fd */ #undef HAVE_PROC_PID /* Define if program_invocation_short_name is defined */ #undef HAVE_PROGRAM_INVOCATION_SHORT_NAME /* Define if PR_SET_NAME is defined */ #undef HAVE_PR_SET_NAME /* sys/queue.h */ #undef HAVE_QUEUE_H /* Define to 1 if your system has a GNU libc compatible 'realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 if you have the 'reallocarray' function. */ #undef HAVE_REALLOCARRAY /* Define to 1 if you have the 'realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the 'recallocarray' function. */ #undef HAVE_RECALLOCARRAY /* Define to 1 if you have the 'regcomp' function. */ #undef HAVE_REGCOMP /* Define to 1 if you have the 'rmdir' function. */ #undef HAVE_RMDIR /* Define to 1 if you have the 'setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if you have the 'setproctitle' function. */ #undef HAVE_SETPROCTITLE /* Define to 1 if you have the 'setresgid' function. */ #undef HAVE_SETRESGID /* Define to 1 if you have the 'setresuid' function. */ #undef HAVE_SETRESUID /* Define to 1 if you have the header file. */ #undef HAVE_SHA1_H /* Define to 1 if you have the 'SHA256Update' function. */ #undef HAVE_SHA256UPDATE /* Define to 1 if you have the header file. */ #undef HAVE_SHA256_H /* Define to 1 if you have the header file. */ #undef HAVE_SHA2_H /* Define to 1 if you have the header file. */ #undef HAVE_SHA_H /* Define to 1 if you have the 'SipHash' function. */ #undef HAVE_SIPHASH /* Define to 1 if you have the 'socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the 'strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the 'strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the 'strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the 'strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the 'strerror' function. */ #undef HAVE_STRERROR /* Define if you have 'strerror_r'. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the 'strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the 'strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the 'strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the 'strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the 'strnlen' function. */ #undef HAVE_STRNLEN /* Define to 1 if you have the 'strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the 'strsep' function. */ #undef HAVE_STRSEP /* Define to 1 if you have the 'strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the 'strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the 'strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the 'strtonum' function. */ #undef HAVE_STRTONUM /* Define to 1 if you have the 'strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if the system has the type 'struct ifgroupreq'. */ #undef HAVE_STRUCT_IFGROUPREQ /* Define to 1 if 'fd' is a member of 'struct pollfd'. */ #undef HAVE_STRUCT_POLLFD_FD /* Define to 1 if 'sa_len' is a member of 'struct sockaddr'. */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN /* Define to 1 if the system has the type 'struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE /* Define to 1 if 'ss_len' is a member of 'struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN /* Define to 1 if sysconf() present */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file, and it defines 'DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file, and it defines 'DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_QUEUE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TREE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TLS_H /* HAVE_TREE_H */ #undef HAVE_TREE_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H /* Define to 1 if you have the 'vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Define to 1 if you have the 'wcwidth' function. */ #undef HAVE_WCWIDTH /* Define to 1 if 'fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if 'vfork' works. */ #undef HAVE_WORKING_VFORK /* Define to 1 if the system has the type '_Bool'. */ #undef HAVE__BOOL /* ___progname */ #undef HAVE___PROGNAME /* Define to 1 if 'lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 if strerror_r returns char *. */ #undef STRERROR_R_CHAR_P /* Enable extensions on AIX, Interix, z/OS. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by C23 Annex F. */ #ifndef __STDC_WANT_IEC_60559_EXT__ # undef __STDC_WANT_IEC_60559_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION /* Define to 1 if necessary to make fseeko visible. */ #undef _LARGEFILE_SOURCE /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to '__inline__' or '__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to 'int' if does not define. */ #undef mode_t /* Define to 'long int' if does not define. */ #undef off_t /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define as 'unsigned int' if doesn't define. */ #undef size_t /* Define as 'int' if doesn't define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as 'fork' if 'vfork' does not work. */ #undef vfork #include "got_compat2.h" got-portable-0.119/include/got_date.h0000664000175000017500000000151715066535721013206 /* * Copyright (c) 2022 Josh Rickmar * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ void got_date_format_gmtoff(char *, size_t, time_t); got-portable-0.119/include/got_privsep.h0000664000175000017500000000153715066535721013763 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ const struct got_error *got_privsep_unveil_exec_helpers(void); got-portable-0.119/include/got_blame.h0000664000175000017500000000352415066535721013351 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ typedef const struct got_error *(*got_blame_cb)(void *, int, int, struct got_commit_object *, struct got_object_id *); /* * Blame the blob at the specified path in the specified commit and invoke * a callback whenever an annotation has been computed for a line. * * The callback receives the provided void * argument, the total number * of lines of the annotated file, a line number, and the ID of the commit * which last changed this line. * * The callback is invoked for each commit as history is traversed. * If no changes to the file were made in a commit, line number -1 will * be reported. * * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation * will be aborted and this function returns NULL. * If the callback returns any other error, the blame operation will be * aborted and the callback's error is returned from this function. */ const struct got_error *got_blame(const char *, struct got_object_id *, struct got_repository *, enum got_diff_algorithm, got_blame_cb, void *, got_cancel_cb, void *, int, int, FILE *, FILE *); got-portable-0.119/include/got_repository_dump.h0000664000175000017500000000210615066535721015530 /* * Copyright (c) 2023 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Output a bundle to the given file. */ const struct got_error * got_repo_dump(FILE *out, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.119/include/got_patch.h0000664000175000017500000000303415066535721013364 /* * Copyright (c) 2022 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A callback that gets invoked during the patch application. * * Receives the old and new path, a status code, if an error occurred while * applying the patch, and a hunk applied with offset or its error. */ typedef const struct got_error *(*got_patch_progress_cb)(void *, const char *, const char *, unsigned char, const struct got_error *, int, int, int, int, int, int, const struct got_error *); /* * Apply the (already opened) patch to the repository and register the * status of the added and removed files. * * The patch file descriptor *must* be seekable. */ const struct got_error * got_patch(int, struct got_worktree *, struct got_repository *, int, int, int, struct got_object_id *, got_patch_progress_cb, void *, got_cancel_cb, void *); got-portable-0.119/include/got_fetch.h0000664000175000017500000000510215066535721013354 /* * Copyright (c) 2018, 2019 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_FETCH_DEFAULT_REMOTE_NAME "origin" /* * Attempt to open a connection to a server using the provided protocol * scheme, hostname port number (as a string) and server-side path. * A jumphost can be specified which will be passed to ssh(1) via -J. * An identity file can be specified which will be passed to ssh(1) via -i. * A verbosity level can be specified; it currently controls the amount * of -v options passed to ssh(1). If the level is -1 ssh(1) will be run * with the -q option. * * If successful return an open file descriptor for the connection which can * be passed to other functions below, and must be disposed of with close(2). * * If an ssh(1) process was started return its PID as well, in which case * the caller should eventually send SIGTERM to the procress and wait for * the process to exit with waitpid(2). Otherwise, return PID -1. */ const struct got_error *got_fetch_connect(pid_t *, int *, const char *, const char *, const char *, const char *, const char *, const char *, int); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_fetch_progress_cb)(void *, const char *, off_t, int, int, int, int); /* * Attempt to fetch a packfile from a server. This pack file will contain * objects which that are not yet contained in the provided repository. * Return the hash of the packfile (in form of an object ID) and lists of * references and symbolic references learned from the server. */ const struct got_error *got_fetch_pack(struct got_object_id **, struct got_pathlist_head *, struct got_pathlist_head *, const char *, int, int, struct got_pathlist_head *, struct got_pathlist_head *, int, int, int, struct got_repository *, const char *, const char *, int, got_fetch_progress_cb, void *); got-portable-0.119/include/got_keyword.h0000664000175000017500000000376215066535721013761 /* * Copyright (c) 2023 Mark Jamsek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Commit keywords to specify references in the repository * (cf. svn keywords, fossil special tags, hg revsets). */ #define GOT_KEYWORD_BASE "base" /* work tree base commit */ #define GOT_KEYWORD_HEAD "head" /* worktree/repo HEAD commit */ /* * Parse a commit id string for keywords and/or lineage modifiers "(+|-)[N]". * Valid keywords are "base" or "head" and must be prefixed with a ":". * Lineage modifiers must be prefixed with a ":" and may suffix keywords or * reference names: * :keyword:(+/-)N Nth generation descendant/antecedent of keyword * :keyword:(+/-) 1st generation descendant/antecedent of keyword * :keyword commit pointed to by keyword * ref:(+/-)[N] Nth generation descendant/antecedent of ref * If a match is found, return the corresponding commit id string in the * char ** out parameter, of which the caller takes ownership and must free. * Otherwise it will contain NULL, indicating a match was not found. * If the modifier is greater than the number of ancestors/descendants, the id * string of the oldest/most recent commit (i.e., ROOT/HEAD) will be returned. */ const struct got_error *got_keyword_to_idstr(char **, const char *, struct got_repository *, struct got_worktree *); got-portable-0.119/include/got_commit_graph.h0000664000175000017500000000353515066535721014744 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_commit_graph; const struct got_error *got_commit_graph_open(struct got_commit_graph **, const char *, int); void got_commit_graph_close(struct got_commit_graph *); const struct got_error *got_commit_graph_bfsort( struct got_commit_graph *, struct got_object_id *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_toposort(struct got_commit_graph *, struct got_object_id *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_iter_next(struct got_object_id *, struct got_commit_graph *, struct got_repository *, got_cancel_cb, void *); const struct got_error *got_commit_graph_intersect(struct got_object_id **, struct got_commit_graph *, struct got_commit_graph *, struct got_repository *); /* Find the youngest common ancestor of two commits. */ const struct got_error *got_commit_graph_find_youngest_common_ancestor( struct got_object_id **, struct got_object_id *, struct got_object_id *, int, int, struct got_repository *, got_cancel_cb, void *); got-portable-0.119/include/got_repository_admin.h0000664000175000017500000001212115066535721015651 /* * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_pack_progress_cb)(void *arg, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int obj_deltify, int nobj_written, int pack_done); /* * Attempt to pack objects reachable via 'include_refs' into a new packfile. * If 'excluded_refs' is not an empty list, do not pack any objects * reachable from the listed references. * If loose_obj_only is zero, pack reachable objects even if they are * already packed in another packfile. Otherwise, add only loose * objects to the new pack file. * Return an open file handle for the generated pack file. * Return the hash digest of the resulting pack file in pack_hash which * must freed by the caller when done. */ const struct got_error * got_repo_pack_objects(FILE **packfile, struct got_object_id **pack_hash, struct got_reflist_head *include_refs, struct got_reflist_head *exclude_refs, struct got_repository *repo, int loose_obj_only, int force_refdelta, got_pack_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* * Attempt to open a pack file at the specified path. Return an open * file handle and the expected hash of pack file contents. */ const struct got_error * got_repo_find_pack(FILE **packfile, struct got_object_id **pack_hash, struct got_repository *repo, const char *packfile_path); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_pack_index_progress_cb)(void *arg, off_t packfile_size, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved, int indexing_done); /* (Re-)Index the pack file identified by the given hash. */ const struct got_error * got_repo_index_pack(char **idxpath, FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_index_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); typedef const struct got_error *(*got_pack_list_cb)(void *arg, struct got_object_id *id, int type, off_t offset, off_t size, off_t base_offset, struct got_object_id *base_id); /* List the pack file identified by the given hash. */ const struct got_error * got_repo_list_pack(FILE *packfile, struct got_object_id *pack_hash, struct got_repository *repo, got_pack_list_cb list_cb, void *list_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* A callback function which gets invoked with cleanup information to print. */ typedef const struct got_error *(*got_cleanup_progress_cb)(void *arg, int ncommits, int nloose, int npurged, int nredundant); /* * Walk objects reachable via references and, unless the dry-run parameter * is set, pack all referenced objects into a single pack. * Then determine whether any loose objects can be removed from disk. * Do remove such objects from disk unless the dry_run parameter is set. * Do not remove objects with a modification timestamp above an * implementation-defined timestamp threshold, unless ignore_mtime is set. * Remove packfiles which objects are either unreachable or provided * by biggest pack files. * Return the disk space size occupied by loose objects and pack files * before and after the operation. * Return the number of loose objects which are also stored in a pack file. */ const struct got_error * got_repo_cleanup(struct got_repository *repo, off_t *loose_before, off_t *loose_after, off_t *pack_before, off_t *pack_after, int *ncommits, int *nloose, int *npacked, int dry_run, int ignore_mtime, got_cleanup_progress_cb progress_cb, void *progress_arg, got_pack_progress_cb pack_progress_cb, void *pack_progress_arg, got_pack_index_progress_cb index_progress_cb, void *index_progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* A callback function which gets invoked with cleanup information to print. */ typedef const struct got_error *(*got_lonely_packidx_progress_cb)(void *arg, const char *path); /* Remove pack index files which do not have a corresponding pack file. */ const struct got_error * got_repo_remove_lonely_packidx(struct got_repository *repo, int dry_run, got_lonely_packidx_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.119/include/got_reference.h0000664000175000017500000002013415066535721014223 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A reference which points to an arbitrary object. */ struct got_reference; /* Well-known reference names. */ #define GOT_REF_HEAD "HEAD" #define GOT_REF_ORIG_HEAD "ORIG_HEAD" #define GOT_REF_MERGE_HEAD "MERGE_HEAD" #define GOT_REF_FETCH_HEAD "FETCH_HEAD" struct got_repository; struct got_object_id; /* Determine whether a given reference name is valid. */ int got_ref_name_is_valid(const char *); /* * Attempt to open the reference with the provided name in a repository. * The caller must dispose of the reference with got_ref_close(). * Optionally, the underlying reference file can be locked before it is opened * to prevent concurrent modification of the reference, in which case the file * must be unlocked with got_ref_unlock() before got_ref_close() is called. */ const struct got_error *got_ref_open(struct got_reference **, struct got_repository *, const char *, int); /* * Allocate a new reference for a given object ID. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_ref_alloc(struct got_reference **, const char *, struct got_object_id *); /* * Allocate a new symbolic reference which points at a given reference. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_ref_alloc_symref(struct got_reference **, const char *, struct got_reference *); /* Dispose of a reference. */ void got_ref_close(struct got_reference *); /* Get the name of the reference. */ const char *got_ref_get_name(struct got_reference *); /* Get the name of the reference which a symbolic reference points at. */ const char *got_ref_get_symref_target(struct got_reference *); /* Get the last modification timestamp of the reference. */ time_t got_ref_get_mtime(struct got_reference *); /* * Get the modification timestamp of the commit pointed at by the * given reference. Will return zero if the commit timestamp is * unknown or if the reference does not point at a commit. * * The cached timestamp will be known after got_ref_list() was called * with either got_ref_cmp_by_commit_timestamp_descending() or * with got_ref_cmp_tags(). */ time_t got_ref_get_cached_committer_time(struct got_reference *); /* * Create a duplicate copy of a reference. * The caller must dispose of this copy with got_ref_close(). */ struct got_reference *got_ref_dup(struct got_reference *); /* Attempt to resolve a symbolic reference to a non-symbolic one. */ const struct got_error *got_ref_resolve_symbolic(struct got_reference **, struct got_repository *, struct got_reference *); /* Attempt to resolve a reference (symbolic or not) to an object ID. */ const struct got_error *got_ref_resolve(struct got_object_id **, struct got_repository *, struct got_reference *); /* * Return a string representation of a reference. * The caller must dispose of it with free(3). */ char *got_ref_to_str(struct got_reference *); /* List of references. */ struct got_reflist_entry { TAILQ_ENTRY(got_reflist_entry) entry; struct got_reference *ref; }; TAILQ_HEAD(got_reflist_head, got_reflist_entry); /* Duplicate a reference list entry. Caller must dispose of it with free(3). */ const struct got_error *got_reflist_entry_dup(struct got_reflist_entry **, struct got_reflist_entry *); /* A function which compares two references. Used with got_ref_list(). */ typedef const struct got_error *(*got_ref_cmp_cb)(void *, int *, struct got_reference *, struct got_reference *); /* An implementation of got_ref_cmp_cb which compares two references by name. */ const struct got_error *got_ref_cmp_by_name(void *, int *, struct got_reference *, struct got_reference *); /* An implementation of got_ref_cmp_cb which compares two tags. */ const struct got_error *got_ref_cmp_tags(void *, int *, struct got_reference *, struct got_reference *); /* * An implementation of got_ref_cmp_cb which compares commit timestamps. * Requires a struct got_repository * as the void * argument. */ const struct got_error *got_ref_cmp_by_commit_timestamp_descending(void *, int *, struct got_reference *, struct got_reference *); /* * Append all known references to a caller-provided ref list head. * Optionally limit references returned to those within a given * reference namespace. Sort the list with the provided reference comparison * function, usually got_ref_cmp_by_name(). */ const struct got_error *got_ref_list(struct got_reflist_head *, struct got_repository *, const char *, got_ref_cmp_cb, void *); /* Free all references on a ref list. */ void got_ref_list_free(struct got_reflist_head *); /* * Insert a reference into a reference list. * Return a pointer to the newly allocated list entry in *newp. * If *newp is NULL and no error occurred then the specified reference was * already an element of the list. If *newp is not NULL then the reference * was shallow-copied onto the list and should no longer be closed with * got_ref_close(). Instead it will be closed along with other list * elements by got_ref_list_free(). */ const struct got_error * got_reflist_insert(struct got_reflist_entry **newp, struct got_reflist_head *refs, struct got_reference *ref, got_ref_cmp_cb cmp_cb, void *cmp_arg); /* Sort a list of references with the provided comparison callback. */ const struct got_error * got_reflist_sort(struct got_reflist_head *refs, got_ref_cmp_cb cmp_cb, void *cmp_arg); /* Indicate whether the provided reference is symbolic (points at another * reference) or not (points at an object ID). */ int got_ref_is_symbolic(struct got_reference *); /* Change the object ID a reference points to. */ const struct got_error * got_ref_change_ref(struct got_reference *, struct got_object_id *); /* Change the reference name a symbolic reference points to. */ const struct got_error *got_ref_change_symref(struct got_reference *, const char *); /* * Change a symbolic reference into a regular reference which points to * the provided object ID. */ const struct got_error *got_ref_change_symref_to_ref(struct got_reference *, struct got_object_id *); /* Write a reference to its on-disk path in the repository. */ const struct got_error *got_ref_write(struct got_reference *, struct got_repository *); /* Delete a reference from its on-disk path in the repository. */ const struct got_error *got_ref_delete(struct got_reference *, struct got_repository *); /* Unlock a reference which was opened in locked state. */ const struct got_error *got_ref_unlock(struct got_reference *); /* Map object IDs to references. */ struct got_reflist_object_id_map; /* * Create and populate an object ID map for a given list of references. * Map entries will contain deep-copies of elements of the reflist. * The caller must dispose of the map with got_reflist_object_id_map_free(). */ const struct got_error *got_reflist_object_id_map_create( struct got_reflist_object_id_map **, struct got_reflist_head *, struct got_repository *); /* * Return a list of references which correspond to a given object ID. * The returned list must be considered read-only. * The caller must _not_ call free(3) on the returned pointer! * If no references are associated with the ID, return NULL. */ struct got_reflist_head * got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *, struct got_object_id *); /* Free the specified object ID map. */ void got_reflist_object_id_map_free(struct got_reflist_object_id_map *); got-portable-0.119/include/got_opentemp.h0000664000175000017500000000351615066535721014121 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Utilities for opening temporary files. */ #ifndef GOT_TMPDIR #define GOT_TMPDIR /tmp #endif #define GOT_STRINGIFY_TMP(x) #x #define GOT_STRINGVAL_TMP(x) GOT_STRINGIFY_TMP(x) #define GOT_TMPDIR_STR GOT_STRINGVAL_TMP(GOT_TMPDIR) /* Open a file descriptor to a new temporary file for writing. * The file is not visible in the filesystem. */ int got_opentempfd(void); /* Open a new temporary file for writing. * The file is not visible in the filesystem. */ FILE *got_opentemp(void); /* Open a new temporary file for writing. * The file is visible in the filesystem. */ const struct got_error *got_opentemp_named(char **, FILE **, const char *, const char *); /* Like got_opentemp_named() but returns a file descriptor instead of a FILE. */ const struct got_error *got_opentemp_named_fd(char **, int *, const char *, const char *); /* Truncate a file. This is useful for re-using open temporary files. */ const struct got_error *got_opentemp_truncate(FILE *); /* Truncate a file via a file descriptor. */ const struct got_error *got_opentemp_truncatefd(int); got-portable-0.119/include/got_worktree.h0000664000175000017500000006652115066535721014141 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_worktree; struct got_commitable; struct got_commit_object; struct got_fileindex; /* status codes */ #define GOT_STATUS_NO_CHANGE ' ' #define GOT_STATUS_ADD 'A' #define GOT_STATUS_EXISTS 'E' #define GOT_STATUS_UPDATE 'U' #define GOT_STATUS_DELETE 'D' #define GOT_STATUS_MODIFY 'M' #define GOT_STATUS_MODE_CHANGE 'm' #define GOT_STATUS_CONFLICT 'C' #define GOT_STATUS_MERGE 'G' #define GOT_STATUS_MISSING '!' #define GOT_STATUS_UNVERSIONED '?' #define GOT_STATUS_OBSTRUCTED '~' #define GOT_STATUS_NONEXISTENT 'N' #define GOT_STATUS_REVERT 'R' #define GOT_STATUS_CANNOT_DELETE 'd' #define GOT_STATUS_BUMP_BASE 'b' #define GOT_STATUS_BASE_REF_ERR 'B' #define GOT_STATUS_CANNOT_UPDATE '#' /* Also defined in got_lib_worktree.h in case got_worktree.h is not included. */ #define GOT_WORKTREE_GOT_DIR ".got" #define GOT_WORKTREE_CVG_DIR ".cvg" /* * Attempt to initialize a new work tree on disk. * The first argument is the path to a directory where the work tree * will be created. The path itself must not yet exist, but the dirname(3) * of the path must already exist. * The reference provided will be used to determine the new worktree's * base commit. The third argument specifies the work tree's path prefix. * The fourth argument specifies the meta data directory to use, which * should be either GOT_WORKTREE_GOT_DIR or GOT_WORKTREE_CVG_DIR. */ const struct got_error *got_worktree_init(const char *, struct got_reference *, const char *, const char *, struct got_repository *); /* * Attempt to open a worktree at or above the specified path, using * the specified meta data directory which should be either be NULL * in which case a meta directory is auto-discovered, or be one of * GOT_WORKTREE_GOT_DIR and GOT_WORKTREE_CVG_DIR. * The caller must dispose of it with got_worktree_close(). */ const struct got_error *got_worktree_open(struct got_worktree **, const char *path, const char *meta_dir); /* Dispose of an open work tree. */ const struct got_error *got_worktree_close(struct got_worktree *); /* * Get the path to the root directory of a worktree. */ const char *got_worktree_get_root_path(struct got_worktree *); /* * Get the path to the repository associated with a worktree. */ const char *got_worktree_get_repo_path(struct got_worktree *); /* * Get the path prefix associated with a worktree. */ const char *got_worktree_get_path_prefix(struct got_worktree *); /* * Get the UUID of a work tree as a string. * The caller must dispose of the returned UUID string with free(3). */ const struct got_error *got_worktree_get_uuid(char **, struct got_worktree *); /* * Get the work tree's format version number. */ int got_worktree_get_format_version(struct got_worktree *); /* * Check if a user-provided path prefix matches that of the worktree. */ const struct got_error *got_worktree_match_path_prefix(int *, struct got_worktree *, const char *); /* * Prefix for references pointing at base commit of backout/cherrypick commits. * Reference path takes the form: PREFIX-WORKTREE_UUID-COMMIT_ID */ #define GOT_WORKTREE_CHERRYPICK_REF_PREFIX "refs/got/worktree/cherrypick" #define GOT_WORKTREE_BACKOUT_REF_PREFIX "refs/got/worktree/backout" #define GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN \ sizeof(GOT_WORKTREE_CHERRYPICK_REF_PREFIX) - 1 #define GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN \ sizeof(GOT_WORKTREE_BACKOUT_REF_PREFIX) - 1 #define GOT_WORKTREE_UUID_STRLEN 36 const struct got_error *got_worktree_get_logmsg_ref_name(char **, struct got_worktree *, const char *); /* * Get the name of a work tree's HEAD reference. */ const char *got_worktree_get_head_ref_name(struct got_worktree *); /* * Set the branch head reference of the work tree. */ const struct got_error *got_worktree_set_head_ref(struct got_worktree *, struct got_reference *); /* * Get the current base commit ID of a worktree. */ struct got_object_id *got_worktree_get_base_commit_id(struct got_worktree *); /* * Set the base commit Id of a worktree. */ const struct got_error *got_worktree_set_base_commit_id(struct got_worktree *, struct got_repository *, struct got_object_id *); /* * Get the state of the work tree. If the work tree's global base commit is * the tip of the work tree's current branch, and each file in the index is * based on this same commit, the char out parameter will be * GOT_WORKTREE_STATE_UPTODATE, else it will be GOT_WORKTREE_STATE_OUTOFDATE. */ const struct got_error *got_worktree_get_state(char *, struct got_repository *, struct got_worktree *, got_cancel_cb, void *); #define GOT_WORKTREE_STATE_UNKNOWN ' ' #define GOT_WORKTREE_STATE_UPTODATE '*' #define GOT_WORKTREE_STATE_OUTOFDATE '~' /* * Obtain a parsed representation of this worktree's got.conf file. * Return NULL if this configuration file could not be read. */ const struct got_gotconfig *got_worktree_get_gotconfig(struct got_worktree *); /* A callback function which is invoked when a path is checked out. */ typedef const struct got_error *(*got_worktree_checkout_cb)(void *, unsigned char, const char *); /* A callback function which is invoked when a path is removed. */ typedef const struct got_error *(*got_worktree_delete_cb)(void *, unsigned char, unsigned char, const char *); /* * Attempt to check out files into a work tree from its associated repository * and path prefix, and update the work tree's file index accordingly. * File content is obtained from blobs within the work tree's path prefix * inside the tree corresponding to the work tree's base commit. * The checkout progress callback will be invoked with the provided * void * argument, and the path of each checked out file. * * It is possible to restrict the checkout operation to specific paths in * the work tree, in which case all files outside those paths will remain at * their currently recorded base commit. Inconsistent base commits can be * repaired later by running another update operation across the entire work * tree. Inconsistent base-commits may also occur if this function runs into * an error or if the checkout operation is cancelled by the cancel callback. * Allspecified paths are relative to the work tree's root. Pass a pathlist * with a single empty path "" to check out files across the entire work tree. * * Some operations may refuse to run while the work tree contains files from * multiple base commits. */ const struct got_error *got_worktree_checkout_files(struct got_worktree *, struct got_pathlist_head *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* Merge the differences between two commits into a work tree. */ const struct got_error * got_worktree_merge_files(struct got_worktree *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * A callback function which is invoked to report a file's status. * * If a valid directory file descriptor and a directory entry name are passed, * these should be used to open the file instead of opening the file by path. * This prevents race conditions if the filesystem is modified concurrently. * If the directory descriptor is not available then its value will be -1. */ typedef const struct got_error *(*got_worktree_status_cb)(void *, unsigned char, unsigned char, const char *, struct got_object_id *, struct got_object_id *, struct got_object_id *, int, const char *); /* * Report the status of paths in the work tree. * The status callback will be invoked with the provided void * argument, * a path, and a corresponding status code. */ const struct got_error *got_worktree_status(struct got_worktree *, struct got_pathlist_head *, struct got_repository *, int no_ignores, got_worktree_status_cb, void *, got_cancel_cb cancel_cb, void *); /* * Try to resolve a user-provided path to an on-disk path in the work tree. * The caller must dispose of the resolved path with free(3). */ const struct got_error *got_worktree_resolve_path(char **, struct got_worktree *, const char *); /* Schedule files at on-disk paths for addition in the next commit. */ const struct got_error *got_worktree_schedule_add(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, struct got_repository *, int); /* * Remove files from disk and schedule them to be deleted in the next commit. * Don't allow deleting files with uncommitted modifications, unless the * parameter 'delete_local_mods' is set. */ const struct got_error * got_worktree_schedule_delete(struct got_worktree *, struct got_pathlist_head *, int, const char *, got_worktree_delete_cb, void *, struct got_repository *, int, int); /* A callback function which is used to select or reject a patch. */ typedef const struct got_error *(*got_worktree_patch_cb)(int *, void *, unsigned char, const char *, FILE *, int, int); /* Values for result output parameter of got_wortree_patch_cb. */ #define GOT_PATCH_CHOICE_NONE 0 #define GOT_PATCH_CHOICE_YES 1 #define GOT_PATCH_CHOICE_NO 2 #define GOT_PATCH_CHOICE_QUIT 3 /* * Revert a file at the specified path such that it matches its * original state in the worktree's base commit. * If the patch callback is not NULL, call it to select patch hunks to * revert. Otherwise, revert the whole file found at each path. */ const struct got_error *got_worktree_revert(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, got_worktree_patch_cb patch_cb, void *patch_arg, struct got_repository *); /* * A callback function which is invoked when a commit message is requested. * Passes a pathlist with a struct got_commitable * in the data pointer of * each element, the path to a file which contains a diff of changes to be * committed (may be NULL), and a pointer to the log message that must be * set by the callback and will be freed after committing, and an argument * passed through to the callback. */ typedef const struct got_error *(*got_worktree_commit_msg_cb)( struct got_pathlist_head *, const char *, char **, void *); /* * Create a new commit from changes in the work tree. * Return the ID of the newly created commit. * The worktree's base commit will be set to this new commit. * Files unaffected by this commit operation will retain their * current base commit. * An author and a non-empty log message must be specified. * The name of the committer is optional (may be NULL). * An optional author timestamp can be specified. The current time will * be used if the specified timestamp is 0. * If a path to be committed contains a symlink which points outside * of the path space under version control, raise an error unless * committing of such paths is being forced by the caller. */ const struct got_error *got_worktree_commit(struct got_object_id **, struct got_worktree *, struct got_pathlist_head *, const char *, time_t, const char *, int, int, int, got_worktree_commit_msg_cb, void *, got_worktree_status_cb, void *, struct got_repository *); /* Get the path of a committable worktree item. */ const char *got_commitable_get_path(struct got_commitable *); /* Get the status of a committable worktree item. */ unsigned int got_commitable_get_status(struct got_commitable *); /* * Prepare for rebasing a branch onto the work tree's current branch. * This function creates references to a temporary branch, the branch * being rebased, and the work tree's current branch, under the * "got/worktree/rebase/" namespace. These references are used to * keep track of rebase operation state and are used as input and/or * output arguments with other rebase-related functions. * The function also returns a pointer to a fileindex which must be * passed back to other rebase-related functions. */ const struct got_error *got_worktree_rebase_prepare(struct got_reference **, struct got_reference **, struct got_fileindex **, struct got_worktree *, struct got_reference *, struct got_repository *); /* * Continue an interrupted rebase operation. * This function returns existing references created when rebase was prepared, * and the ID of the commit currently being rebased. This should be called * before either resuming or aborting a rebase operation. * The function also returns a pointer to a fileindex which must be * passed back to other rebase-related functions. */ const struct got_error *got_worktree_rebase_continue(struct got_object_id **, struct got_reference **, struct got_reference **, struct got_reference **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* Check whether a, potentially interrupted, rebase operation is in progress. */ const struct got_error *got_worktree_rebase_in_progress(int *, struct got_worktree *); /* Return information about an in-progress rebase operation. */ const struct got_error *got_worktree_rebase_info(char **new_base_branch_name, char **branch_name, struct got_worktree *, struct got_repository *); /* * Merge changes from the commit currently being rebased into the work tree. * Report affected files, including merge conflicts, via the specified * progress callback. Also populate a list of affected paths which should * be passed to got_worktree_rebase_commit() after a conflict-free merge. * This list must be initialized with TAILQ_INIT() and disposed of with * got_pathlist_free(list, GOT_PATHLIST_FREE_PATH). */ const struct got_error *got_worktree_rebase_merge_files( struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * Commit changes merged by got_worktree_rebase_merge_files() to a temporary * branch and return the ID of the newly created commit. An optional list of * merged paths can be provided; otherwise this function will perform a status * crawl across the entire work tree to find paths to commit. */ const struct got_error *got_worktree_rebase_commit(struct got_object_id **, struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_reference *, const char *, struct got_commit_object *, struct got_object_id *, int, struct got_repository *); /* Postpone the rebase operation. Should be called after a merge conflict. */ const struct got_error *got_worktree_rebase_postpone(struct got_worktree *, struct got_fileindex *); /* * Complete the current rebase operation. This should be called once all * commits have been rebased successfully. * The create_backup parameter controls whether the rebased branch will * be backed up via a reference in refs/got/backup/rebase/. */ const struct got_error *got_worktree_rebase_complete(struct got_worktree *, struct got_fileindex *, struct got_reference *, struct got_reference *, struct got_repository *, int create_backup); /* * Abort the current rebase operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_rebase_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, got_worktree_checkout_cb, void *); /* * Prepare for editing the history of the work tree's current branch. * This function creates references to a temporary branch, and the * work tree's current branch, under the "got/worktree/histedit/" namespace. * These references are used to keep track of histedit operation state and * are used as input and/or output arguments with other histedit-related * functions. */ const struct got_error *got_worktree_histedit_prepare(struct got_reference **, struct got_reference **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * Continue an interrupted histedit operation. * This function returns existing references created when histedit was * prepared and the ID of the commit currently being edited. * It should be called before resuming or aborting a histedit operation. */ const struct got_error *got_worktree_histedit_continue(struct got_object_id **, struct got_reference **, struct got_reference **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* Check whether a histedit operation is in progress. */ const struct got_error *got_worktree_histedit_in_progress(int *, struct got_worktree *); /* Return information about an in-progress histedit operation. */ const struct got_error *got_worktree_histedit_info( char **branch_nane, struct got_worktree *, struct got_repository *); /* * Merge changes from the commit currently being edited into the work tree. * Report affected files, including merge conflicts, via the specified * progress callback. Also populate a list of affected paths which should * be passed to got_worktree_histedit_commit() after a conflict-free merge. * This list must be initialized with TAILQ_INIT() and disposed of with * got_pathlist_free(list, GOT_PATHLIST_FREE_PATH). */ const struct got_error *got_worktree_histedit_merge_files( struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_object_id *, struct got_object_id *, struct got_repository *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* * Commit changes merged by got_worktree_histedit_merge_files() to a temporary * branch and return the ID of the newly created commit. An optional list of * merged paths can be provided; otherwise this function will perform a status * crawl across the entire work tree to find paths to commit. * An optional log message can be provided which will be used instead of the * commit's original message. */ const struct got_error *got_worktree_histedit_commit(struct got_object_id **, struct got_pathlist_head *, struct got_worktree *, struct got_fileindex *, struct got_reference *, const char *, struct got_commit_object *, struct got_object_id *, const char *, int, struct got_repository *); /* * Record the specified commit as skipped during histedit. * This should be called for commits which get dropped or get folded into * a subsequent commit. */ const struct got_error *got_worktree_histedit_skip_commit(struct got_worktree *, struct got_object_id *, struct got_repository *); /* Postpone the histedit operation. */ const struct got_error *got_worktree_histedit_postpone(struct got_worktree *, struct got_fileindex *); /* * Complete the current histedit operation. This should be called once all * commits have been edited successfully. */ const struct got_error *got_worktree_histedit_complete(struct got_worktree *, struct got_fileindex *, struct got_reference *, struct got_reference *, struct got_repository *); /* * Abort the current histedit operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_histedit_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_object_id *, got_worktree_checkout_cb, void *, int); /* Get the path to this work tree's histedit script file. */ const struct got_error *got_worktree_get_histedit_script_path(char **, struct got_worktree *); /* * Prepare a work tree for integrating a branch. * Return pointers to a fileindex and locked references which must be * passed back to other integrate-related functions. */ const struct got_error * got_worktree_integrate_prepare(struct got_fileindex **, struct got_reference **, struct got_reference **, struct got_worktree *, const char *, struct got_repository *); /* * Carry out a prepared branch integration operation. * Report affected files via the specified progress callback. */ const struct got_error *got_worktree_integrate_continue( struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_reference *, got_worktree_checkout_cb, void *, got_cancel_cb, void *); /* Abort a prepared branch integration operation. */ const struct got_error *got_worktree_integrate_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, struct got_reference *, struct got_reference *); /* Postpone the merge operation. Should be called after a merge conflict. */ const struct got_error *got_worktree_merge_postpone(struct got_worktree *, struct got_fileindex *); /* Merge changes from the merge source branch into the worktree. */ const struct got_error * got_worktree_merge_branch(struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_object_id *yca_commit_id, struct got_object_id *branch_tip, struct got_repository *repo, got_worktree_checkout_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); /* Attempt to commit merged changes. */ const struct got_error * got_worktree_merge_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_fileindex *fileindex, const char *author, time_t author_time, const char *committer, int allow_bad_symlinks, struct got_object_id *branch_tip, const char *branch_name, int allow_conflict, struct got_repository *repo, got_worktree_status_cb status_cb, void *status_arg); /* * Complete the merge operation. * This should be called once changes have been successfully committed. */ const struct got_error *got_worktree_merge_complete( struct got_worktree *worktree, struct got_fileindex *fileindex, struct got_repository *repo); /* Check whether a merge operation is in progress. */ const struct got_error *got_worktree_merge_in_progress(int *, struct got_worktree *, struct got_repository *); /* Return information about an in-progress merge operation. */ const struct got_error * got_worktree_merge_info(char **branch_name, struct got_worktree *, struct got_repository *); /* * Prepare for merging a branch into the work tree's current branch: lock the * worktree and check that preconditions are satisfied. The function also * returns a pointer to a fileindex which must be passed back to other * merge-related functions. */ const struct got_error *got_worktree_merge_prepare(struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * This function creates a reference to the branch being merged, and to * this branch's current tip commit, in the "got/worktree/merge/" namespace. * These references are used to keep track of merge operation state and are * used as input and/or output arguments with other merge-related functions. */ const struct got_error *got_worktree_merge_write_refs(struct got_worktree *, struct got_reference *, struct got_repository *); /* * Continue an interrupted merge operation. * This function returns name of the branch being merged, and the ID of the * tip commit being merged. * This function should be called before either resuming or aborting a * merge operation. * The function also returns a pointer to a fileindex which must be * passed back to other merge-related functions. */ const struct got_error *got_worktree_merge_continue(char **, struct got_object_id **, struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * Abort the current rebase operation. * Report reverted files via the specified progress callback. */ const struct got_error *got_worktree_merge_abort(struct got_worktree *, struct got_fileindex *, struct got_repository *, got_worktree_checkout_cb, void *); /* * Stage the specified paths for commit. * If the patch callback is not NULL, call it to select patch hunks for * staging. Otherwise, stage the full file content found at each path. * If a path being staged contains a symlink which points outside * of the path space under version control, raise an error unless * staging of such paths is being forced by the caller. */ const struct got_error *got_worktree_stage(struct got_worktree *, struct got_pathlist_head *, got_worktree_status_cb, void *, got_worktree_patch_cb, void *, int, struct got_repository *); /* * Merge staged changes for the specified paths back into the work tree * and mark the paths as non-staged again. */ const struct got_error *got_worktree_unstage(struct got_worktree *, struct got_pathlist_head *, got_worktree_checkout_cb, void *, got_worktree_patch_cb, void *, struct got_repository *); /* * Prepare for getting meta data for paths in the work tree. This * function also returns a pointer to a fileindex which must be passed * back to other path_info-related functions and *_version() functions. */ const struct got_error * got_worktree_path_info_prepare(struct got_fileindex **, struct got_worktree *, struct got_repository *); /* * Get the file-index version. */ uint32_t got_worktree_get_fileindex_version(struct got_fileindex *); /* A callback function which is invoked with per-path info. */ typedef const struct got_error *(*got_worktree_path_info_cb)(void *, const char *path, mode_t mode, time_t mtime, struct got_object_id *blob_id, struct got_object_id *staged_blob_id, struct got_object_id *commit_id); /* * Report work-tree meta data for paths in the work tree. * The info callback will be invoked with the provided void * argument, * a path, and meta-data arguments (see got_worktree_path_info_cb). */ const struct got_error * got_worktree_path_info(struct got_worktree *, struct got_fileindex *, struct got_pathlist_head *, got_worktree_path_info_cb, void *, got_cancel_cb , void *); /* * Complete the current path_info operation. */ const struct got_error * got_worktree_path_info_complete(struct got_fileindex *, struct got_worktree *); /* References pointing at pre-rebase commit backups. */ #define GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX "refs/got/backup/rebase" /* References pointing at pre-histedit commit backups. */ #define GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX "refs/got/backup/histedit" /* * Prepare for applying a patch. */ const struct got_error * got_worktree_patch_prepare(struct got_fileindex **, char **, struct got_worktree *, struct got_repository *); /* * Lookup paths for the "old" and "new" file before patching and check their * status. */ const struct got_error * got_worktree_patch_check_path(const char *, const char *, char **, char **, struct got_worktree *, struct got_repository *, struct got_fileindex *); const struct got_error * got_worktree_patch_schedule_add(const char *, struct got_repository *, struct got_worktree *, struct got_fileindex *, got_worktree_checkout_cb, void *); const struct got_error * got_worktree_patch_schedule_rm(const char *, struct got_repository *, struct got_worktree *, struct got_fileindex *, got_worktree_delete_cb, void *); /* Complete the patch operation. */ const struct got_error * got_worktree_patch_complete(struct got_worktree *, struct got_fileindex *, const char *); got-portable-0.119/include/got_repository_load.h0000664000175000017500000000221615066535721015504 /* * Copyright (c) 2023 Omar Polo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* A callback function which gets invoked with progress information. */ typedef const struct got_error *(*got_load_progress_cb)(void *, off_t, int, int, int, int); /* * Load a bundle in the repository. */ const struct got_error * got_repo_load(FILE *, struct got_pathlist_head *, struct got_repository *, int, int, got_load_progress_cb, void *, got_cancel_cb, void *); got-portable-0.119/include/got_cancel.h0000664000175000017500000000173215066535721013515 /* * Copyright (c) 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A callback function which is invoked at cancellation points. * May return GOT_ERR_CANCELLED to abort the runing operation. */ typedef const struct got_error *(*got_cancel_cb)(void *); got-portable-0.119/include/got_object.h0000664000175000017500000003250615066536113013535 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum got_hash_algorithm { GOT_HASH_SHA1, GOT_HASH_SHA256, }; struct got_object_id { uint8_t hash[GOT_OBJECT_ID_MAXLEN]; enum got_hash_algorithm algo; }; struct got_blob_object; struct got_tree_object; struct got_tree_entry; struct got_tag_object; struct got_commit_object; struct got_object_qid { STAILQ_ENTRY(got_object_qid) entry; struct got_object_id id; void *data; /* managed by API user */ }; STAILQ_HEAD(got_object_id_queue, got_object_qid); const struct got_error *got_object_qid_alloc(struct got_object_qid **, struct got_object_id *); void got_object_qid_free(struct got_object_qid *); void got_object_id_queue_free(struct got_object_id_queue *); /* * Deep-copy elements from ID queue src to ID queue dest. Do not copy any * qid->data pointers! This is the caller's responsibility if needed. */ const struct got_error *got_object_id_queue_copy( const struct got_object_id_queue *src, struct got_object_id_queue *dest); /* Object types. */ #define GOT_OBJ_TYPE_ANY 0 /* wildcard value at run-time */ #define GOT_OBJ_TYPE_COMMIT 1 #define GOT_OBJ_TYPE_TREE 2 #define GOT_OBJ_TYPE_BLOB 3 #define GOT_OBJ_TYPE_TAG 4 /* 5 is reserved */ #define GOT_OBJ_TYPE_OFFSET_DELTA 6 #define GOT_OBJ_TYPE_REF_DELTA 7 /* * Labels used in object data. */ #define GOT_OBJ_LABEL_COMMIT "commit" #define GOT_OBJ_LABEL_TREE "tree" #define GOT_OBJ_LABEL_BLOB "blob" #define GOT_OBJ_LABEL_TAG "tag" #define GOT_COMMIT_LABEL_TREE "tree " #define GOT_COMMIT_LABEL_PARENT "parent " #define GOT_COMMIT_LABEL_AUTHOR "author " #define GOT_COMMIT_LABEL_COMMITTER "committer " #define GOT_TAG_LABEL_OBJECT "object " #define GOT_TAG_LABEL_TYPE "type " #define GOT_TAG_LABEL_TAG "tag " #define GOT_TAG_LABEL_TAGGER "tagger " struct got_repository; /* * Obtain a string representation of an object ID. The output depends on * the hash function used by the repository format. */ const struct got_error *got_object_id_str(char **, struct got_object_id *); /* * Compare two object IDs. Return value behaves like memcmp(3). */ int got_object_id_cmp(const struct got_object_id *, const struct got_object_id *); /* * Created a newly allocated copy of an object ID. * The caller should dispose of it with free(3). */ struct got_object_id *got_object_id_dup(struct got_object_id *); /* * Get a newly allocated ID of the object which resides at the specified * path in the specified tree. * The caller should dispose of it with free(3). */ const struct got_error *got_object_tree_find_path(struct got_object_id **id, mode_t *mode, struct got_repository *repo, struct got_tree_object *tree, const char *path); /* * Get a newly allocated ID of the object which resides at the specified * path in the tree of the specified commit. * The caller should dispose of it with free(3). */ const struct got_error *got_object_id_by_path(struct got_object_id **, struct got_repository *, struct got_commit_object *, const char *); /* * Obtain the type of an object. * Returns one of the GOT_OBJ_TYPE_x values (see above). */ const struct got_error *got_object_get_type(int *, struct got_repository *, struct got_object_id *); /* * Attempt to resolve the textual representation of an object ID * to the ID of an existing object in the repository. * The caller should dispose of the ID with free(3). */ const struct got_error *got_object_resolve_id_str(struct got_object_id **, struct got_repository *, const char *); /* * Attempt to open a commit object in a repository. * The caller must dispose of the commit with got_object_commit_close(). */ const struct got_error *got_object_open_as_commit(struct got_commit_object **, struct got_repository *, struct got_object_id *); /* Dispose of a commit object. */ void got_object_commit_close(struct got_commit_object *); /* Obtain the ID of the tree created in a commit. */ struct got_object_id *got_object_commit_get_tree_id(struct got_commit_object *); /* Obtain the number of parent commits of a commit. */ int got_object_commit_get_nparents(struct got_commit_object *); /* Obtain the list of parent commits of a commit. */ const struct got_object_id_queue *got_object_commit_get_parent_ids( struct got_commit_object *); /* Get the author's name and email address. */ const char *got_object_commit_get_author(struct got_commit_object *); /* Get an author's commit timestamp in UTC. */ time_t got_object_commit_get_author_time(struct got_commit_object *); /* Get an author's timezone offset. */ time_t got_object_commit_get_author_gmtoff(struct got_commit_object *); /* Get the committer's name and email address. */ const char *got_object_commit_get_committer(struct got_commit_object *); /* Get a committer's commit timestamp in UTC. */ time_t got_object_commit_get_committer_time(struct got_commit_object *); /* Get a committer's timezone offset. */ time_t got_object_commit_get_committer_gmtoff(struct got_commit_object *); /* * Get the commit log message. * PGP-signatures contained in the log message will be stripped. * The caller must dispose of it with free(3). */ const struct got_error *got_object_commit_get_logmsg(char **, struct got_commit_object *); /* Get the raw commit log message.*/ const char *got_object_commit_get_logmsg_raw(struct got_commit_object *); /* * Attempt to open a tree object in a repository. * The caller must dispose of the tree with got_object_tree_close(). */ const struct got_error *got_object_open_as_tree(struct got_tree_object **, struct got_repository *, struct got_object_id *); /* Dispose of a tree object. */ void got_object_tree_close(struct got_tree_object *); /* Get the number of entries in this tree object. */ int got_object_tree_get_nentries(struct got_tree_object *); /* Get the first tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_object_tree_get_first_entry( struct got_tree_object *); /* Get the last tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_object_tree_get_last_entry(struct got_tree_object *); /* Get the entry with the specified index from a tree object. */ struct got_tree_entry *got_object_tree_get_entry( struct got_tree_object *, int); /* Find a particular entry in a tree by name. */ struct got_tree_entry *got_object_tree_find_entry( struct got_tree_object *, const char *); /* Get the file permission mode of a tree entry. */ mode_t got_tree_entry_get_mode(struct got_tree_entry *); /* Get the name of a tree entry. */ const char *got_tree_entry_get_name(struct got_tree_entry *); /* Get the object ID of a tree entry. */ struct got_object_id *got_tree_entry_get_id(struct got_tree_entry *); /* * Get a string containing the target path of a given a symlink tree entry. * The caller should dispose of it with free(3). */ const struct got_error *got_tree_entry_get_symlink_target(char **, struct got_tree_entry *, struct got_repository *); /* Get the index of a tree entry. */ int got_tree_entry_get_index(struct got_tree_entry *); /* Get the next tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_tree_entry_get_next(struct got_tree_object *, struct got_tree_entry *); /* Get the previous tree entry from a tree, or NULL if there is none. */ struct got_tree_entry *got_tree_entry_get_prev(struct got_tree_object *, struct got_tree_entry *); /* Return non-zero if the specified tree entry is a Git submodule. */ int got_object_tree_entry_is_submodule(struct got_tree_entry *); /* Return non-zero if the specified tree entry is a symbolic link. */ int got_object_tree_entry_is_symlink(struct got_tree_entry *); /* * Resolve an in-repository symlink at the specified path in the tree * corresponding to the specified commit. If the specified path is not * a symlink then set *link_target to NULL. * Otherwise, resolve symlinks recursively and return the final link * target path. The caller must dispose of it with free(3). */ const struct got_error *got_object_resolve_symlinks(char **, const char *, struct got_commit_object *, struct got_repository *); /* * Compare two trees and indicate whether the entry at the specified path * differs between them. The path must not be the root path "/"; the function * got_object_id_cmp() should be used instead to compare the tree roots. */ const struct got_error *got_object_tree_path_changed(int *, struct got_tree_object *, struct got_tree_object *, const char *, struct got_repository *); /* * Attempt to open a blob object in a repository. * The size_t argument specifies the block size of an associated read buffer. * The caller must dispose of the blob with got_object_blob_close(). */ const struct got_error *got_object_open_as_blob(struct got_blob_object **, struct got_repository *, struct got_object_id *, size_t, int); /* Dispose of a blob object. */ const struct got_error *got_object_blob_close(struct got_blob_object *); /* * Get the length of header data at the beginning of the blob's read buffer. * Note that header data is only present upon the first invocation of * got_object_blob_read_block() after the blob is opened. */ size_t got_object_blob_get_hdrlen(struct got_blob_object *); /* * Get a pointer to the blob's read buffer. * The read buffer is filled by got_object_blob_read_block(). */ const uint8_t *got_object_blob_get_read_buf(struct got_blob_object *); /* * Read the next chunk of data from a blob, up to the blob's read buffer * block size. The size_t output argument indicates how many bytes have * been read into the blob's read buffer. Zero bytes will be reported if * all data in the blob has been read. */ const struct got_error *got_object_blob_read_block(size_t *, struct got_blob_object *); /* Rewind an open blob's data stream back to the beginning. */ void got_object_blob_rewind(struct got_blob_object *); /* * Heuristic to check whether the blob contains binary data. Rewinds * the blob's data stream back after the header. */ const struct got_error *got_object_blob_is_binary(int *, struct got_blob_object *); /* * getline(3) for blobs. */ const struct got_error *got_object_blob_getline(char **, ssize_t *, size_t *, struct got_blob_object *); /* * Read the entire content of a blob and write it to the specified file. * Flush and rewind the file as well. Indicate the amount of bytes * written in the size_t output argument, and the number of lines in the * file in the int argument, and line offsets in the off_t argument * (NULL can be passed for any output argument). */ const struct got_error *got_object_blob_dump_to_file(off_t *, int *, off_t **, FILE *, struct got_blob_object *); /* * Read the entire content of a blob into a newly allocated string buffer * and terminate it with '\0'. This is intended for blobs which contain a * symlink target path. It should not be used to process arbitrary blobs. * Use got_object_blob_dump_to_file() or got_tree_entry_get_symlink_target() * instead if possible. The caller must dispose of the string with free(3). */ const struct got_error *got_object_blob_read_to_str(char **, struct got_blob_object *); /* * Attempt to open a tag object in a repository. * The caller must dispose of the tree with got_tag_object_close(). */ const struct got_error *got_object_open_as_tag(struct got_tag_object **, struct got_repository *, struct got_object_id *); /* Dispose of a tag object. */ void got_object_tag_close(struct got_tag_object *); /* Get the name of a tag. */ const char *got_object_tag_get_name(struct got_tag_object *); /* Get type of the object a tag points to. */ int got_object_tag_get_object_type(struct got_tag_object *); /* * Get ID of the object a tag points to. * This must not be freed by the caller. Use got_object_id_dup() if needed. */ struct got_object_id *got_object_tag_get_object_id(struct got_tag_object *); /* Get the timestamp of the tag. */ time_t got_object_tag_get_tagger_time(struct got_tag_object *); /* Get the tag's timestamp's GMT offset. */ time_t got_object_tag_get_tagger_gmtoff(struct got_tag_object *); /* Get the author of the tag. */ const char *got_object_tag_get_tagger(struct got_tag_object *); /* Get the tag message associated with the tag. */ const char *got_object_tag_get_message(struct got_tag_object *); const struct got_error *got_object_commit_add_parent(struct got_commit_object *, const char *, enum got_hash_algorithm); /* Create a new tag object in the repository. */ const struct got_error *got_object_tag_create(struct got_object_id **, const char *, struct got_object_id *, const char *, time_t, const char *, const char *, struct got_repository *, int verbosity); /* Increment commit object reference counter. */ void got_object_commit_retain(struct got_commit_object *); got-portable-0.119/include/got_error.h0000664000175000017500000002473615066535721013432 /* * Copyright (c) 2018, 2019, 2020 Stefan Sperling * Copyright (c) 2020 Ori Bernstein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Error codes */ #define GOT_ERR_OK 0 #define GOT_ERR_ERRNO 1 #define GOT_ERR_NOT_GIT_REPO 2 #define GOT_ERR_BAD_FILETYPE 3 #define GOT_ERR_BAD_PATH 4 #define GOT_ERR_NOT_REF 5 #define GOT_ERR_IO 6 #define GOT_ERR_EOF 7 #define GOT_ERR_DECOMPRESSION 8 #define GOT_ERR_NO_SPACE 9 #define GOT_ERR_BAD_OBJ_HDR 10 #define GOT_ERR_OBJ_TYPE 11 #define GOT_ERR_BAD_OBJ_DATA 12 #define GOT_ERR_AMBIGUOUS_ID 13 #define GOT_ERR_BAD_PACKIDX 14 #define GOT_ERR_PACKIDX_CSUM 15 #define GOT_ERR_BAD_PACKFILE 16 #define GOT_ERR_NO_OBJ 17 #define GOT_ERR_NOT_IMPL 18 #define GOT_ERR_OBJ_NOT_PACKED 19 #define GOT_ERR_BAD_DELTA_CHAIN 20 #define GOT_ERR_BAD_DELTA 21 #define GOT_ERR_COMPRESSION 22 #define GOT_ERR_BAD_OBJ_ID_STR 23 #define GOT_ERR_WORKTREE_EXISTS 26 #define GOT_ERR_WORKTREE_META 27 #define GOT_ERR_WORKTREE_VERS 28 #define GOT_ERR_WORKTREE_BUSY 29 #define GOT_ERR_DIR_OBSTRUCTED 30 #define GOT_ERR_FILE_OBSTRUCTED 31 #define GOT_ERR_RECURSION 32 #define GOT_ERR_TIMEOUT 33 #define GOT_ERR_INTERRUPT 34 #define GOT_ERR_PRIVSEP_READ 35 #define GOT_ERR_PRIVSEP_LEN 36 #define GOT_ERR_PRIVSEP_PIPE 37 #define GOT_ERR_PRIVSEP_NO_FD 38 #define GOT_ERR_PRIVSEP_MSG 39 #define GOT_ERR_PRIVSEP_DIED 40 #define GOT_ERR_PRIVSEP_EXIT 41 #define GOT_ERR_PACK_OFFSET 42 #define GOT_ERR_OBJ_EXISTS 43 #define GOT_ERR_BAD_OBJ_ID 44 #define GOT_ERR_OBJECT_FORMAT 45 #define GOT_ERR_ITER_COMPLETED 46 #define GOT_ERR_RANGE 47 #define GOT_ERR_EXPECTED 48 /* for use in regress tests only */ #define GOT_ERR_CANCELLED 49 #define GOT_ERR_NO_TREE_ENTRY 50 #define GOT_ERR_FILEIDX_SIG 51 #define GOT_ERR_FILEIDX_VER 52 #define GOT_ERR_FILEIDX_CSUM 53 #define GOT_ERR_PATH_PREFIX 54 #define GOT_ERR_ANCESTRY 55 #define GOT_ERR_FILEIDX_BAD 56 #define GOT_ERR_BAD_REF_DATA 57 #define GOT_ERR_TREE_DUP_ENTRY 58 #define GOT_ERR_DIR_DUP_ENTRY 59 #define GOT_ERR_NOT_WORKTREE 60 #define GOT_ERR_UUID_VERSION 61 #define GOT_ERR_UUID_INVALID 62 #define GOT_ERR_UUID 63 #define GOT_ERR_LOCKFILE_TIMEOUT 64 #define GOT_ERR_BAD_REF_NAME 65 #define GOT_ERR_WORKTREE_REPO 66 #define GOT_ERR_FILE_MODIFIED 67 #define GOT_ERR_FILE_STATUS 68 #define GOT_ERR_COMMIT_CONFLICT 69 #define GOT_ERR_BAD_REF_TYPE 70 #define GOT_ERR_COMMIT_NO_AUTHOR 71 #define GOT_ERR_COMMIT_HEAD_CHANGED 72 #define GOT_ERR_COMMIT_OUT_OF_DATE 73 #define GOT_ERR_COMMIT_MSG_EMPTY 74 #define GOT_ERR_DIR_NOT_EMPTY 75 #define GOT_ERR_COMMIT_NO_CHANGES 76 #define GOT_ERR_BRANCH_MOVED 77 #define GOT_ERR_OBJ_TOO_LARGE 78 #define GOT_ERR_SAME_BRANCH 79 #define GOT_ERR_ROOT_COMMIT 80 #define GOT_ERR_MIXED_COMMITS 81 #define GOT_ERR_CONFLICTS 82 #define GOT_ERR_BRANCH_EXISTS 83 #define GOT_ERR_MODIFIED 84 #define GOT_ERR_NOT_REBASING 85 #define GOT_ERR_WRONG_BRANCH 86 #define GOT_ERR_REBASE_COMMITID 87 #define GOT_ERR_REBASING 88 #define GOT_ERR_REBASE_PATH 89 #define GOT_ERR_NOT_HISTEDIT 90 #define GOT_ERR_EMPTY_HISTEDIT 91 #define GOT_ERR_NO_HISTEDIT_CMD 92 #define GOT_ERR_HISTEDIT_SYNTAX 93 #define GOT_ERR_HISTEDIT_CANCEL 94 /* 95 is currently unused */ #define GOT_ERR_HISTEDIT_BUSY 96 #define GOT_ERR_HISTEDIT_CMD 97 #define GOT_ERR_HISTEDIT_PATH 98 #define GOT_ERR_PACKFILE_CSUM 99 #define GOT_ERR_COMMIT_BRANCH 100 #define GOT_ERR_FILE_STAGED 101 #define GOT_ERR_STAGE_NO_CHANGE 102 #define GOT_ERR_STAGE_CONFLICT 103 #define GOT_ERR_STAGE_OUT_OF_DATE 104 #define GOT_ERR_FILE_NOT_STAGED 105 #define GOT_ERR_STAGED_PATHS 106 #define GOT_ERR_PATCH_CHOICE 107 #define GOT_ERR_COMMIT_NO_EMAIL 108 #define GOT_ERR_TAG_EXISTS 109 #define GOT_ERR_GIT_REPO_FORMAT 110 #define GOT_ERR_REBASE_REQUIRED 111 #define GOT_ERR_REGEX 112 #define GOT_ERR_REF_NAME_MINUS 113 #define GOT_ERR_GITCONFIG_SYNTAX 114 #define GOT_ERR_REBASE_OUT_OF_DATE 115 #define GOT_ERR_CACHE_DUP_ENTRY 116 /* 117 is currently unused */ #define GOT_ERR_FETCH_FAILED 118 #define GOT_ERR_PARSE_URI 119 #define GOT_ERR_BAD_PROTO 120 #define GOT_ERR_ADDRINFO 121 #define GOT_ERR_BAD_PACKET 122 #define GOT_ERR_NO_REMOTE 123 #define GOT_ERR_FETCH_NO_BRANCH 124 #define GOT_ERR_FETCH_BAD_REF 125 #define GOT_ERR_TREE_ENTRY_TYPE 126 #define GOT_ERR_PARSE_CONFIG 127 #define GOT_ERR_NO_CONFIG_FILE 128 #define GOT_ERR_BAD_SYMLINK 129 #define GOT_ERR_GIT_REPO_EXT 130 #define GOT_ERR_CANNOT_PACK 131 #define GOT_ERR_LONELY_PACKIDX 132 #define GOT_ERR_OBJ_CSUM 133 #define GOT_ERR_SEND_BAD_REF 134 #define GOT_ERR_SEND_FAILED 135 #define GOT_ERR_SEND_EMPTY 136 #define GOT_ERR_SEND_ANCESTRY 137 #define GOT_ERR_CAPA_DELETE_REFS 138 #define GOT_ERR_SEND_DELETE_REF 139 #define GOT_ERR_SEND_TAG_EXISTS 140 #define GOT_ERR_NOT_MERGING 141 #define GOT_ERR_MERGE_OUT_OF_DATE 142 #define GOT_ERR_MERGE_STAGED_PATHS 143 #define GOT_ERR_MERGE_BUSY 144 #define GOT_ERR_MERGE_PATH 145 #define GOT_ERR_FILE_BINARY 146 #define GOT_ERR_PATCH_MALFORMED 147 #define GOT_ERR_PATCH_TRUNCATED 148 #define GOT_ERR_NO_PATCH 149 #define GOT_ERR_HUNK_FAILED 150 #define GOT_ERR_PATCH_FAILED 151 #define GOT_ERR_FILEIDX_DUP_ENTRY 152 #define GOT_ERR_PIN_PACK 153 #define GOT_ERR_BAD_TAG_SIGNATURE 154 #define GOT_ERR_VERIFY_TAG_SIGNATURE 155 #define GOT_ERR_SIGNING_TAG 156 #define GOT_ERR_BAD_OPTION 157 #define GOT_ERR_BAD_QUERYSTRING 158 #define GOT_ERR_INTEGRATE_BRANCH 159 #define GOT_ERR_BAD_REQUEST 160 #define GOT_ERR_CLIENT_ID 161 #define GOT_ERR_REPO_TEMPFILE 162 #define GOT_ERR_REFS_PROTECTED 163 #define GOT_ERR_REF_PROTECTED 164 #define GOT_ERR_REF_BUSY 165 #define GOT_ERR_COMMIT_BAD_AUTHOR 166 #define GOT_ERR_UID 167 #define GOT_ERR_GID 168 #define GOT_ERR_NO_PROG 169 #define GOT_ERR_MERGE_COMMIT_OUT_OF_DATE 170 #define GOT_ERR_BUNDLE_FORMAT 171 #define GOT_ERR_BAD_KEYWORD 172 #define GOT_ERR_UNKNOWN_CAPA 173 #define GOT_ERR_REF_DUP_ENTRY 174 #define GOT_ERR_DIFF_NOCHANGES 175 #define GOT_ERR_USER 176 #define GOT_ERR_USER_EXISTS 177 #define GOT_ERR_GROUP 178 #define GOT_ERR_GROUP_EXISTS 179 #define GOT_ERR_AUTHORIZED_KEY 180 #define GOT_ERR_CONNECTION_LIMIT 190 #define GOT_ERR_ON_SERVER_SIDE 191 #define GOT_ERR_LOGIN_FAILED 192 #define GOT_ERR_UNKNOWN_COMMAND 193 struct got_error { int code; const char *msg; }; #define GOT_ERR_MAX_MSG_SIZE 4080 /* includes '\0' */ /* * Get an error object from the above list, for a given error code. * The error message is fixed. */ const struct got_error *got_error(int); /* * Get an error object from the above list, for a given error code. * Use the specified error message instead of the default one. * Caution: If the message buffer lives in dynamically allocated memory, * then this memory likely won't be freed. */ const struct got_error *got_error_msg(int, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with a * string. */ const struct got_error *got_error_from_errno(const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with two * strings. */ const struct got_error *got_error_from_errno2(const char *, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with three * strings. */ const struct got_error *got_error_from_errno3(const char *, const char *, const char *); /* * Get a statically allocated error object with code GOT_ERR_ERRNO * and an error message obtained from strerror(3), prefixed with a * string built with vsnprintf(3) from the provided format string * and the variable-length list of additional arguments. */ const struct got_error *got_error_from_errno_fmt(const char *, ...); /* * Set errno to the specified error code and return a statically * allocated error object with code GOT_ERR_ERRNO and an error * message obtained from strerror(3), optionally prefixed with a * string. */ const struct got_error *got_error_set_errno(int, const char *); /* * If ferror(3) indicates an error status for the FILE, obtain an error * from got_error_from_errno(). Else, obtain the error via got_error() * with the error code provided in the second argument. */ const struct got_error *got_ferror(FILE *, int); /* * Obtain an error with code GOT_ERR_NO_OBJ and an error message which * contains the specified object ID. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ struct got_object_id; /* forward declaration */ const struct got_error *got_error_no_obj(struct got_object_id *); /* * Obtain an error with code GOT_ERR_OBJ_CSUM and an error message which * contains the specified object ID. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ const struct got_error *got_error_checksum(struct got_object_id *); /* * Obtain an error with code GOT_ERR_NOT_REF and an error message which * contains the specified reference name. The message buffer is statically * allocated; future invocations of this function will overwrite the * message set during earlier invocations. */ const struct got_error *got_error_not_ref(const char *); /* Return an error based on a uuid(3) status code. */ const struct got_error *got_error_uuid(uint32_t, const char *); /* Return an error with a path prefixed to the error message. */ const struct got_error *got_error_path(const char *, int); /* * Return an error with an error message prefix built by vsnprintf(3) * from the provided format string and the variable-length list of * additional arguments. */ const struct got_error *got_error_fmt(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); /* * Check whether open(2) with O_NOFOLLOW failed on a symlink. * This must be called directly after open(2) because it uses errno! */ int got_err_open_nofollow_on_symlink(void); got-portable-0.119/include/got_repository.h0000664000175000017500000002012615066535721014505 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_repository; struct got_pathlist_head; struct got_tag_object; /* Open and close repositories. */ const struct got_error *got_repo_open(struct got_repository**, const char *, const char *, int *); const struct got_error *got_repo_close(struct got_repository*); /* Obtain the on-disk path to the repository. */ const char *got_repo_get_path(struct got_repository *); /* * Obtain the path to a non-bare repository's .git directory. * For bare repositories, this returns the same result as got_repo_get_path(). */ const char *got_repo_get_path_git_dir(struct got_repository *); /* Obtain the file descriptor of the repository's .git directory. */ int got_repo_get_fd(struct got_repository *); /* Obtain the object format */ enum got_hash_algorithm got_repo_get_object_format(struct got_repository *); /* Obtain the commit author name if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_author_name(struct got_repository *); /* Obtain the commit author email if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_author_email(struct got_repository *); /* Obtain global commit author name parsed ~/.gitconfig, else NULL. */ const char *got_repo_get_global_gitconfig_author_name(struct got_repository *); /* Obtain global commit author email parsed ~/.gitconfig, else NULL. */ const char *got_repo_get_global_gitconfig_author_email(struct got_repository *); /* Obtain repository owner name if parsed from gitconfig, else NULL. */ const char *got_repo_get_gitconfig_owner(struct got_repository *); /* Query if a given Git extension is enabled in gitconfig. */ int got_repo_has_extension(struct got_repository *, const char *); /* Information about one remote repository. */ struct got_remote_repo { char *name; char *fetch_url; char *send_url; /* * If set, fetched references are mirrored 1:1 into our repository. * If not set, references are mapped into "refs/remotes/$name/". */ int mirror_references; /* * If set, fetch all branches by default and ignore the list of * branches below. */ int fetch_all_branches; /* Branches to fetch by default. */ int nfetch_branches; char **fetch_branches; /* Branches to send by default. */ int nsend_branches; char **send_branches; /* Other arbitrary references to fetch by default. */ int nfetch_refs; char **fetch_refs; }; /* * Return a deep copy of a given remote_repo. The result should be * freed with got_repo_free_remote_repo_data() and then free(3). * Return NULL on failure. */ const struct got_error *got_repo_remote_repo_dup(struct got_remote_repo **, const struct got_remote_repo *); /* * Free data allocated for the specified remote repository. * Do not free the remote_repo pointer itself. */ void got_repo_free_remote_repo_data(struct got_remote_repo *); /* Obtain the list of remote repositories parsed from gitconfig. */ void got_repo_get_gitconfig_remotes(int *, const struct got_remote_repo **, struct got_repository *); /* * Obtain a parsed representation of this repository's got.conf file. * Return NULL if this configuration file could not be read. */ const struct got_gotconfig *got_repo_get_gotconfig(struct got_repository *); /* * Obtain paths to various directories within a repository. * The caller must dispose of a path with free(3). */ char *got_repo_get_path_objects(struct got_repository *); char *got_repo_get_path_objects_pack(struct got_repository *); char *got_repo_get_path_refs(struct got_repository *); char *got_repo_get_path_packed_refs(struct got_repository *); char *got_repo_get_path_gitconfig(struct got_repository *); char *got_repo_get_path_gotconfig(struct got_repository *); struct got_reference; struct got_reflist_head; /* * Obtain a reference, by name, from a repository. * The caller must dispose of it with got_ref_close(). */ const struct got_error *got_repo_get_reference(struct got_reference **, struct got_repository *, const char *); /* Indicate whether this is a bare repositiry (contains no git working tree). */ int got_repo_is_bare(struct got_repository *); /* * Attempt to map an input path to a path within the repository. * * This is useful in cases where the input path might be an on-disk path * found in a non-bare Git repository, e.g. when a tab-completed path to * a versioned file in a non-bare Git repository is passed to commands * such as 'got log' in absolute or relative form. * In such cases, the corresponding repository-relative path is returned. * * If the input path is not located in a non-bare Git repository, the * input path is made absolute but is otherwise returned as-is. */ const struct got_error *got_repo_map_path(char **, struct got_repository *, const char *); /* * Create a new repository with optional specified * HEAD ref in an empty directory at a specified path. */ const struct got_error *got_repo_init(const char *, const char *, enum got_hash_algorithm); /* Attempt to find a unique object ID for a given ID string prefix. */ const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **, const char *, int, struct got_repository *); /* * Given an object ID string or reference name, attempt to find a corresponding * object. * The object type may be restricted to commit, tree, blob, or tag. * Tags will only be matched if a list of references is provided. * GOT_OBJ_TYPE_ANY will match any type of object. * A human-readable label can optionally be returned, which the caller should * dispose of with free(3). * Return GOT_ERR_NO_OBJ if no matching commit can be found. */ const struct got_error *got_repo_match_object_id(struct got_object_id **, char **, const char *, int, struct got_reflist_head *, struct got_repository *); /* * Search the provided list of references for a tag with a given name * and target object type. * Return GOT_ERR_NO_OBJ if no matching tag can be found. */ const struct got_error *got_repo_object_match_tag(struct got_tag_object **, const char *, int, struct got_reflist_head *, struct got_repository *); /* A callback function which is invoked when a path is imported. */ typedef const struct got_error *(*got_repo_import_cb)(void *, const char *); /* * Import an unversioned directory tree into the repository. * Creates a root commit, i.e. a commit with zero parents. */ const struct got_error *got_repo_import(struct got_object_id **, const char *, const char *, const char *, struct got_pathlist_head *, struct got_repository *, got_repo_import_cb, void *); /* Obtain the number and size of loose objects in the repository. */ const struct got_error *got_repo_get_loose_object_info(int *nobjects, off_t *ondisk_size, struct got_repository *); /* Obtain the number and size of packed objects in the repository. */ const struct got_error *got_repo_get_packfile_info(int *npackfiles, int *nobjects, off_t *total_packsize, struct got_repository *); /* Create an array of file descriptors to hand over to got_repo_open for pack */ const struct got_error *got_repo_pack_fds_open(int **); /* Close the array of file descriptors handed over to got_repo_open for pack */ const struct got_error *got_repo_pack_fds_close(int *); /* Open/set/close temporary files for internal use. Needed by gotd(8). */ const struct got_error *got_repo_temp_fds_open(int **); void got_repo_temp_fds_set(struct got_repository *, int *); const struct got_error *got_repo_temp_fds_close(int *); got-portable-0.119/include/got_gotconfig.h0000664000175000017500000000367215066535721014254 /* * Copyright (c) 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct got_gotconfig; /* * Obtain the commit author parsed from got.conf. * Return NULL if no configuration file or author could be found. */ const char *got_gotconfig_get_author(const struct got_gotconfig *); /* * Obtain the list of remote repositories parsed from got.conf. * Return 0 and NULL if no configuration file or remote repository * could be found. */ void got_gotconfig_get_remotes(int *, const struct got_remote_repo **, const struct got_gotconfig *); /* * Obtain the filename of the allowed signers file. * Returns NULL if no configuration file is found or no allowed signers file * is configured. */ const char * got_gotconfig_get_allowed_signers_file(const struct got_gotconfig *); /* * Obtain the filename of the revoked signers file. * Returns NULL if no configuration file is found or no revoked signers file * is configured. */ const char * got_gotconfig_get_revoked_signers_file(const struct got_gotconfig *); /* * Obtain the signer identity used to sign tag objects * Returns NULL if no configuration file is found or no revoked signers file * is configured. */ const char * got_gotconfig_get_signer_id(const struct got_gotconfig *); got-portable-0.119/include/got_utf8.h0000664000175000017500000000200115066535721013144 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Return a sanitized UTF-8 string which is safe to write to a terminal. */ const struct got_error *got_mbsavis(char**, int *, const char *); /* Indicate whether the current locale supports UTF-8. */ int got_locale_is_utf8(void); got-portable-0.119/include/got_send.h0000664000175000017500000000623015066535721013217 /* * Copyright (c) 2018, 2019 Ori Bernstein * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define GOT_SEND_DEFAULT_REMOTE_NAME "origin" /* * Attempt to open a connection to a server using the provided protocol * scheme, hostname port number (as a string) and server-side path. * A verbosity level can be specified; it currently controls the amount * of -v options passed to ssh(1). If the level is -1 ssh(1) will be run * with the -q option. * * If successful return an open file descriptor for the connection which can * be passed to other functions below, and must be disposed of with close(2). * A jumphost can be specified which will be passed to ssh(1) via -J. * An identity file can be specified which will be passed to ssh(1) via -i. * * If an ssh(1) process was started return its PID as well, in which case * the caller should eventually send SIGTERM to the procress and wait for * the process to exit with waitpid(2). Otherwise, return PID -1. */ const struct got_error *got_send_connect(pid_t *, int *, const char *, const char *, const char *, const char *, const char *, const char *, int); /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_send_progress_cb)(void *, int ncolored, int nfound, int ntrees, off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify, int nobj_written, off_t bytes_sent, const char *refname, const char *, int success); /* * Attempt to generate a pack file and sent it to a server. * This pack file will contain objects which are reachable in the local * repository via the specified branches and tags. Any objects which are * already present in the remote repository will be omitted from the * pack file. * * If the server supports deletion of references, attempt to delete * branches on the specified delete_branches list from the server. * Such branches are not required to exist in the local repository. * Requesting deletion of branches results in an error if the server * does not support this feature. */ const struct got_error *got_send_pack(const char *remote_name, struct got_pathlist_head *branch_names, struct got_pathlist_head *tag_names, struct got_pathlist_head *delete_branches, int verbosity, int overwrite_refs, int sendfd, struct got_repository *repo, got_send_progress_cb progress_cb, void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg); got-portable-0.119/include/got_path.h0000664000175000017500000001270615066535721013227 /* * Copyright (c) 2018, 2019 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Utilities for dealing with filesystem paths. */ #define GOT_DEFAULT_PACK_MODE (S_IFREG | \ S_IRUSR | S_IRGRP | S_IROTH) #define GOT_DEFAULT_FILE_MODE (S_IFREG | \ S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH) #define GOT_DEFAULT_DIR_MODE (S_IFDIR | \ S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH) struct dirent; /* Determine whether a path is an absolute path. */ int got_path_is_absolute(const char *); /* * Canonicalize absolute paths by removing redundant path separators * and resolving references to parent directories ("/../"). * Relative paths are copied from input to buf as-is. */ const struct got_error *got_canonpath(const char *, char *, size_t); /* * Get child part of two absolute paths. The second path must equal the first * path up to some path component, and must be longer than the first path. * The result is allocated with malloc(3). */ const struct got_error *got_path_skip_common_ancestor(char **, const char *, const char *); /* * Remove leading components from path. It's an error to strip more * component than present. The result is allocated dynamically. */ const struct got_error *got_path_strip(char **, const char *, int); /* Determine whether a path points to the root directory "/" . */ int got_path_is_root_dir(const char *); /* Determine whether a path is a path-wise child of another path. */ int got_path_is_child(const char *, const char *, size_t); /* * Like strcmp() but orders children in subdirectories directly after * their parents. String lengths must also be passed in. */ int got_path_cmp(const char *, const char *, size_t, size_t); struct got_pathlist_entry { RB_ENTRY(got_pathlist_entry) entry; const char *path; size_t path_len; void *data; /* data pointer provided to got_pathlist_insert() */ }; int got_pathlist_cmp(const struct got_pathlist_entry * , const struct got_pathlist_entry *); RB_HEAD(got_pathlist_head, got_pathlist_entry); RB_PROTOTYPE(got_pathlist_head, got_pathlist_entry, entry, got_pathlist_cmp); /* * Insert a path into the list of paths in a predictable order. * The caller should already have initialized the list head. This list stores * the pointer to the path as-is, i.e. the path is not copied internally and * must remain available until the list is freed with got_pathlist_free(). * If the first argument is not NULL, set it to a pointer to the newly inserted * element, or to a NULL pointer in case the path was already on the list. */ const struct got_error *got_pathlist_insert(struct got_pathlist_entry **, struct got_pathlist_head *, const char *, void *); /* Flags passed to got_pathlist_free() to control which pointers are freed. */ #define GOT_PATHLIST_FREE_NONE 0 /* pathlist entry only */ #define GOT_PATHLIST_FREE_PATH (1 << 0) /* entry and path pointer */ #define GOT_PATHLIST_FREE_DATA (1 << 1) /* entry and data pointer */ #define GOT_PATHLIST_FREE_ALL (GOT_PATHLIST_FREE_PATH|GOT_PATHLIST_FREE_DATA) /* Free resources allocated for a path list. */ void got_pathlist_free(struct got_pathlist_head *, int); /* Attempt to create a directory at a given path. */ const struct got_error *got_path_mkdir(const char *); /* Determine whether a directory has no files or directories in it. */ int got_path_dir_is_empty(const char *); /* * dirname(3) with error handling, dynamically allocated result, and * unmodified input. */ const struct got_error *got_path_dirname(char **, const char *); /* * Obtain the file type of a given directory entry. * * If the entry has some type other than DT_UNKNOWN, resolve to this type. * * Otherwise, attempt to resolve the type of a DT_UNKNOWN directory * entry with lstat(2), though the result may still be DT_UNKNOWN. * This is a fallback to accommodate filesystems which do not provide * directory entry type information. * DT_UNKNOWN directory entries occur on NFS mounts without "readdir plus" RPC. */ const struct got_error *got_path_dirent_type(int *, const char *, struct dirent *); /* basename(3) with dynamically allocated result and unmodified input. */ const struct got_error *got_path_basename(char **, const char *); /* Strip trailing slashes from a path; path will be modified in-place. */ void got_path_strip_trailing_slashes(char *); /* Look up the absolute path of a program in $PATH */ const struct got_error *got_path_find_prog(char **, const char *); /* Create a new file at a specified path, with optional content. */ const struct got_error *got_path_create_file(const char *, const char *); /* * Attempt to move an existing file to a new path, creating missing parent * directories at the destination path if necessary. * (Cross-mount-point moves are not yet implemented.) */ const struct got_error *got_path_move_file(const char *, const char *); got-portable-0.119/include/got_diff.h0000664000175000017500000002776315066535721013214 /* * Copyright (c) 2018 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ enum got_diff_algorithm { GOT_DIFF_ALGORITHM_MYERS, GOT_DIFF_ALGORITHM_PATIENCE, }; /* * List of all line types in a diff (including '{got,tog} log' lines). * XXX GOT_DIFF_LINE_HUNK to GOT_DIFF_LINE_NONE inclusive must map to the * DIFF_LINE_* macro counterparts defined in lib/diff_output.h (i.e., 60-64). */ enum got_diff_line_type { GOT_DIFF_LINE_LOGMSG, GOT_DIFF_LINE_AUTHOR, GOT_DIFF_LINE_DATE, GOT_DIFF_LINE_CHANGES, GOT_DIFF_LINE_META, GOT_DIFF_LINE_BLOB_MIN, GOT_DIFF_LINE_BLOB_PLUS, GOT_DIFF_LINE_HUNK = 60, GOT_DIFF_LINE_MINUS, GOT_DIFF_LINE_PLUS, GOT_DIFF_LINE_CONTEXT, GOT_DIFF_LINE_NONE }; struct got_diff_line { off_t offset; uint8_t type; }; struct got_diffstat_cb_arg; /* * Compute the differences between two blobs and write unified diff text * to the provided output file. Two open temporary files must be provided * for internal use; these files can be obtained from got_opentemp() and * must be closed by the caller. * If one of the blobs being diffed does not exist, all corresponding * blob object arguments should be set to NULL. * Two const char * diff header labels may be provided which will be used * to identify each blob in the diff output. * If a label is NULL, use the blob's hash instead. * The number of context lines to show in the diff must be specified as well. * Whitespace differences may optionally be ignored. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_blob(struct got_diff_line **, size_t *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, FILE *); /* * Compute the differences between a blob and a file and write unified diff * text to the provided output file. The blob object, its content, and its * size must be provided. The file's size must be provided, as well as a * const char * diff header label which identifies the file. * An optional const char * diff header label for the blob may be provided, too. * The number of context lines to show in the diff must be specified as well. * Whitespace differences may optionally be ignored. * If not NULL, the two initial output arguments will be populated with an * array of line metadata for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_blob_file(struct got_diff_line **, size_t *, struct got_blob_object *, FILE *, off_t, const char *, FILE *, int, struct stat *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, FILE *); /* * A callback function invoked to handle the differences between two blobs * when diffing trees with got_diff_tree(). This callback receives two blobs, * their respective IDs, and two corresponding paths within the diffed trees. * The first blob contains content from the old side of the diff, and * the second blob contains content on the new side of the diff. * Two open temporary files must be provided for internal use; these files * can be obtained from got_opentemp() and must be closed by the caller. * The blob object argument for either blob may be NULL to indicate * that no content is present on its respective side of the diff. * File modes from relevant tree objects which contain the blobs may * also be passed. These will be zero if not available. */ typedef const struct got_error *(*got_diff_blob_cb)(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * A pre-defined implementation of got_diff_blob_cb() which appends unidiff * output to a file. The caller must allocate and fill in the argument * structure. */ struct got_diff_blob_output_unidiff_arg { FILE *outfile; /* Unidiff text will be written here. */ int diff_context; /* Sets the number of context lines. */ int ignore_whitespace; /* Ignore whitespace differences. */ int force_text_diff; /* Assume text even if binary data detected. */ struct got_diffstat_cb_arg *diffstat; /* Compute diffstat of changes */ enum got_diff_algorithm diff_algo; /* Diffing algorithm to use. */ /* * The number of lines contained in produced unidiff text output, * and an array of got_diff_lines with byte offset and line type to * each line. May be initialized to zero and NULL to ignore line * metadata. If not NULL, then the array of line offsets and types will * be populated. Optionally, the array can be pre-populated with line * offsets and types, with nlines > 0 indicating the length of the * pre-populated array. This is useful if the output file already * contains some lines of text. The array will be grown as needed to * accommodate additional offsets and types, and the last offset found * in a pre-populated array will be added to all subsequent offsets. */ size_t nlines; struct got_diff_line *lines; /* Dispose of with free(3) when done. */ }; const struct got_error *got_diff_blob_output_unidiff(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * Compute the differences between two trees and invoke the provided * got_diff_blob_cb() callback when content differs. * Diffing of blob content can be suppressed by passing zero for the * 'diff_content' parameter. The callback will then only receive blob * object IDs and diff labels, but NULL pointers instead of blob objects. * If 'diff_content' is set, two open temporary FILEs and two open * temporary file descriptors must be provided for internal use; these * files can be obtained from got_opentemp() and got_opentempfd(), * and must be closed by the caller. Otherwise the files can be NULL. * The set of arguments relating to either tree may be NULL to indicate * that no content is present on its respective side of the diff. */ const struct got_error *got_diff_tree(struct got_tree_object *, struct got_tree_object *, FILE *, FILE *, int, int, const char *, const char *, struct got_repository *, got_diff_blob_cb cb, void *cb_arg, int); /* * Pre-defined implementations of got_diff_blob_cb(): the first of which * collects a list of file paths that differ between two trees; the second * also computes a diffstat of added/removed lines for each collected path * and requires passing an initialized got_diffstat_cb_arg argument. * The caller must allocate and initialize a got_pathlist_head * argument. * Data pointers of entries added to the path list will point to a struct * got_diff_changed_path object. * The caller is expected to free both the path and data pointers of all * entries on the path list. */ struct got_diff_changed_path { uint32_t add; /* number of lines added */ uint32_t rm; /* number of lines removed */ /* * The modification status of this path. It can be GOT_STATUS_ADD, * GOT_STATUS_DELETE, GOT_STATUS_MODIFY, or GOT_STATUS_MODE_CHANGE. */ int status; }; const struct got_error *got_diff_tree_collect_changed_paths(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); struct got_diffstat_cb_arg { size_t max_path_len; uint32_t ins; uint32_t del; int add_cols; int rm_cols; int nfiles; struct got_pathlist_head *paths; int ignore_ws; int force_text; enum got_diff_algorithm diff_algo; }; const struct got_error *got_diff_tree_compute_diffstat(void *, struct got_blob_object *, struct got_blob_object *, FILE *, FILE *, struct got_object_id *, struct got_object_id *, const char *, const char *, mode_t, mode_t, struct got_repository *); /* * Diff two objects, assuming both objects are blobs. Two const char * diff * header labels may be provided which will be used to identify each blob in * the diff output. If a label is NULL, use the blob's hash instead. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * The set of arguments relating to either blob may be NULL/-1 to indicate * that no content is present on its respective side of the diff. * The number of context lines to show in the diff must be specified as well. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_blobs(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); struct got_pathlist_head; /* * Diff two objects, assuming both objects are trees. Two const char * diff * header labels may be provided which will be used to identify each blob in * the trees. If a label is NULL, use the blob's hash instead. * The number of context lines to show in diffs must be specified. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * If 'diff_content' is not set, the files may be NULL / -1. * The set of arguments relating to either tree may be NULL to indicate * that no content is present on its respective side of the diff. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_trees(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, struct got_pathlist_head *, const char *, const char *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); /* * Diff two objects, assuming both objects are commits. * The number of context lines to show in diffs must be specified. * Two open temporary files and two temporary file descriptors must be * provided for internal use; these files can be obtained from * got_opentemp() and got_opentempfd(), and must be closed by the caller. * The set of arguments relating to either commit may be NULL to indicate * that no content is present on its respective side of the diff. * Write unified diff text to the provided output FILE. * If not NULL, the two initial output arguments will be populated with an * array of line offsets for, and the number of lines in, the unidiff text. */ const struct got_error *got_diff_objects_as_commits(struct got_diff_line **, size_t *, FILE *, FILE *, int, int, struct got_object_id *, struct got_object_id *, struct got_pathlist_head *, enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *, FILE *); #define GOT_DIFF_MAX_CONTEXT 64 got-portable-0.119/regress/0000775000175000017500000000000015066535722011353 5got-portable-0.119/regress/gotsysd/0000775000175000017500000000000015066536114013043 5got-portable-0.119/regress/gotsysd/common.sh0000664000175000017500000000321715066535722014616 #!/bin/sh # # Copyright (c) 2025 Stefan Sperling # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. test_init() { local testname="$1" local no_tree="$2" if [ -z "$testname" ]; then echo "No test name provided" >&2 return 1 fi local testroot=`mktemp -d \ "$GOTSYSD_TEST_ROOT/gotsysd-test-$testname-XXXXXXXXXX"` got clone -q -i "${GOTSYSD_SSH_KEY}" \ "ssh://${GOTSYSD_TEST_USER}@${VMIP}/${GOTSYS_REPO}" \ $testroot/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got clone failed unexpectedly" >&2 return 1 fi echo "$testroot" } test_cleanup() { return 0 } test_done() { local testroot="$1" local result="$2" if [ "$result" = "0" ]; then test_cleanup "$testroot" || return 1 if [ -z "$GOT_TEST_QUIET" ]; then echo "ok" fi elif echo "$result" | grep -q "^xfail"; then # expected test failure; test reproduces an unfixed bug echo "$result" test_cleanup "$testroot" || return 1 else echo "test failed; leaving test data in $testroot" fi } got-portable-0.119/regress/gotsysd/Makefile0000664000175000017500000003265615066535722014443 .include "../../got-version.mk" REGRESS_TARGETS=test_gotsysd test_gotwebd REGRESS_SETUP_ONCE=setup_test_vm REGRESS_CLEANUP=stop_test_vm NOOBJ=Yes CLEANFILES= SHA256.sig bsd.rd bsd.rd.fs bsd.rd.decomp ${AUTOINSTALL_CONF} \ ${GOTSYSD_BSD_RD} ${GOTSYSD_SSH_KEY} ${GOTSYSD_SSH_PUBKEY} \ ${GOTSYSD_TEST_VM_BASE_IMAGE} ${GOTSYSD_VM_PASSWD_FILE} ${GOTD_CONF} \ ${GOTSYSD_CONF} ${GOTSYS_CONF} ${GOT_CONF} ${INSTALL_SITE} \ ${HTTPD_CONF} ${GOTWEBD_CONF} .PHONY: ensure_root vm start_test_vm build_got GOTSYSD_TEST_ROOT=/tmp GOTSYSD_TEST_DIR!!=mktemp -d "$(GOTSYSD_TEST_ROOT)/gotsysd-test-XXXXXXXXXX" GOTSYSD_TEST_VM_BASE_IMAGE=gotsysd_test_vm_base.qcow2 GOTSYSD_BSD_RD=gotsysd_bsd.rd GOTSYSD_VND?=vnd0 GOTSYSD_MIRROR?=ftp.bit.nl GOTSYSD_MIRROR_URL?=https://${GOTSYSD_MIRROR}/pub/OpenBSD GOTSYSD_OPENBSD_VERSION?=snapshots GOTSYSD_VM_NAME=gotsysd-test GOTSYSD_VM_PASSWORD?=gameoftrees GOTSYSD_VM_PASSWD_FILE=gotsysd_vm_passwd GOTD_CONF=gotd.conf GOTD_UID=501 # /usr/ports/infrastructure/db/user.list GOTD_USER=_gotd GOTSYSD_CONF=gotsysd.conf GOTSYSD_UNIX_SOCKET=/var/run/gotsysd.sock GOTSYSD_UID=600 # /usr/ports/infrastructure/db/user.list GOTSYS_CONF=gotsys.conf GOT_CONF=got.conf GOTSYS_REPO=gotsys.git GOTWEBD_UID=593 # /usr/ports/infrastructure/db/user.list GOTSYSD_TEST_SMTP_PORT=2525 GOTSYSD_TEST_HTTP_PORT=8000 GOTSYSD_TEST_HMAC_SECRET!=openssl rand -base64 32 HTTPD_CONF=httpd.conf GOTWEBD_CONF=gotwebd.conf GOTSYSD_TEST_USER?=${DOAS_USER} .if empty(GOTSYSD_TEST_USER) GOTSYSD_TEST_USER=${SUDO_USER} .endif .if empty(GOTSYSD_TEST_USER) GOTSYSD_TEST_USER=${USER} .endif GOTSYSD_TEST_USER_HOME!=getent passwd $(GOTSYSD_TEST_USER) | cut -d: -f6 GOTSYSD_DEV_USER=flan_hacker GOTSYSD_DEV_PASSWORD=hack1234 GOTSYSD_TEST_ENV=GOTSYSD_TEST_ROOT=${GOTSYSD_TEST_ROOT} \ GOTSYSD_TEST_DIR=$(GOTSYSD_TEST_DIR) \ GOTSYSD_TEST_USER=$(GOTSYSD_TEST_USER) \ GOTSYSD_VM_PASSWORD=$(GOTSYSD_VM_PASSWORD) \ GOTSYSD_DEV_USER=$(GOTSYSD_DEV_USER) \ GOTSYSD_DEV_PASSWORD=$(GOTSYSD_DEV_PASSWORD) \ GOTSYSD_SSH_KEY=${GOTSYSD_SSH_KEY} \ GOTSYSD_SSH_PUBKEY=${GOTSYSD_SSH_PUBKEY} \ GOTSYS_REPO=${GOTSYS_REPO} \ HOME=$(GOTSYSD_TEST_USER_HOME) \ PATH=$(GOTSYSD_TEST_USER_HOME)/bin:$(PATH) \ GOTD_USER=${GOTD_USER} \ GOTSYSD_TEST_SMTP_PORT=${GOTSYSD_TEST_SMTP_PORT} \ GOTSYSD_TEST_HTTP_PORT=${GOTSYSD_TEST_HTTP_PORT} \ GOTSYSD_TEST_HMAC_SECRET=${GOTSYSD_TEST_HMAC_SECRET} UNPRIV=su -m ${GOTSYSD_TEST_USER} -c AUTOINSTALL_CONF=auto_install.conf INSTALL_SITE=install.site GOTSYSD_SSH_KEY=gotsysd_sshkey GOTSYSD_SSH_PUBKEY=gotsysd_sshkey.pub GOTSYSD_SSH_OPTIONS= -i ${GOTSYSD_SSH_KEY} -o StrictHostKeyChecking=accept-new GOTSYSD_SSH_CMD= ssh ${GOTSYSD_SSH_OPTIONS} GOTSYSD_SCP_CMD= scp ${GOTSYSD_SSH_OPTIONS} -B -C -q .if "${GOT_RELEASE}" == "Yes" PREFIX ?= /usr/local BINDIR ?= ${PREFIX}/sbin .else PREFIX ?= ${GOTSYSD_TEST_USER_HOME} BINDIR ?= ${PREFIX}/bin .endif ensure_root: @if [[ `id -u` -ne 0 ]]; then \ echo gotsysd test suite must be started by root >&2; \ false; \ fi ; \ if [[ "$(GOTSYSD_TEST_USER)" = "root" ]]; then \ echo GOTSYSD_TEST_USER must be a non-root user >&2; \ false; \ fi ensure_ipforwarding: @if [[ `sysctl -n net.inet.ip.forwarding` -ne 1 ]]; then \ echo IPv4 forwarding should be enabled first: sysctl net.inet.ip.forwarding=1 >&2; \ false; \ fi ; \ bsd.rd: ${UNPRIV} "ftp -o SHA256.sig \ ${GOTSYSD_MIRROR_URL}/${GOTSYSD_OPENBSD_VERSION}/`uname -m`/SHA256.sig" ${UNPRIV} "ftp -o bsd.rd \ ${GOTSYSD_MIRROR_URL}/${GOTSYSD_OPENBSD_VERSION}/`uname -m`/bsd.rd" \ ${UNPRIV} "set -e; \ KEY=$$(head -1 < SHA256.sig | cut -d' ' -f5 | \ egrep '^openbsd-[[:digit:]]{2,3}-base.pub$$' || true); \ signify -C -p /etc/signify/$${KEY} -x SHA256.sig bsd.rd" ${GOTSYSD_SSH_PUBKEY}: ${UNPRIV} "ssh-keygen -q -f ${GOTSYSD_SSH_KEY} -P '' \ -C 'temporary-gotsysd-regress-ssh-key'" ${GOTSYSD_VM_PASSWD_FILE}: ${UNPRIV} "touch ${GOTSYSD_VM_PASSWD_FILE}" ${UNPRIV} "chmod 700 ${GOTSYSD_VM_PASSWD_FILE}" @${UNPRIV} "echo ${GOTSYSD_VM_PASSWORD} | encrypt > $@" ${AUTOINSTALL_CONF}: ${GOTSYSD_VM_PASSWD_FILE} ${GOTSYSD_SSH_PUBKEY} ${UNPRIV} "echo System hostname = $(GOTSYSD_VM_NAME) > $@" ${UNPRIV} "echo -n 'Password for root = ' >> $@" ${UNPRIV} "cat ${GOTSYSD_VM_PASSWD_FILE} >> $@" ${UNPRIV} "echo -n 'Public ssh key for root account = ' >> $@" ${UNPRIV} "cat ${GOTSYSD_SSH_PUBKEY} >> $@" ${UNPRIV} "echo Allow root ssh login? = prohibit-password >> $@" ${UNPRIV} "echo Setup a user = ${GOTSYSD_TEST_USER} >> $@" ${UNPRIV} "echo -n 'Password for user ${GOTSYSD_TEST_USER}? = ' >> $@" ${UNPRIV} "cat ${GOTSYSD_VM_PASSWD_FILE} >> $@" ${UNPRIV} "echo -n 'Public ssh key for user = ' >> $@" ${UNPRIV} "cat ${GOTSYSD_SSH_PUBKEY} >> $@" ${UNPRIV} "echo Location of sets = http >> $@" ${UNPRIV} "echo Server directory = pub/OpenBSD/${GOTSYSD_OPENBSD_VERSION}/`uname -m` >> $@" ${UNPRIV} "echo HTTP Server = ${GOTSYSD_MIRROR} >> $@" ${INSTALL_SITE}: ${UNPRIV} "echo 'echo library_aslr=NO >> /etc/rc.conf.local' >> $@" ${UNPRIV} "echo sed -i \'/\\\/usr\\\/libexec\\\/reorder_kernel/d\' /etc/rc >> $@" ${GOTSYSD_BSD_RD}: bsd.rd ${AUTOINSTALL_CONF} ${INSTALL_SITE} ${UNPRIV} "gzcat bsd.rd > bsd.rd.decomp" rdsetroot -x bsd.rd.decomp bsd.rd.fs vnconfig ${GOTSYSD_VND} bsd.rd.fs mount /dev/${GOTSYSD_VND}a /mnt cp ${AUTOINSTALL_CONF} /mnt/auto_install.conf install -o root -m 755 ${INSTALL_SITE} /mnt/install.site sed -i 's/if \[\[ -x \/mnt\/$$MODE.site \]\]; then/if cp \/install.site \/mnt\/install.site; then/' /mnt/install.sub umount /mnt vnconfig -u ${GOTSYSD_VND} rdsetroot bsd.rd.decomp bsd.rd.fs mv bsd.rd.decomp $@ ${GOTSYSD_TEST_VM_BASE_IMAGE}: vmctl create -s 4G $@ # Install the base VM image. This target should be run interactively. vm: ensure_root ensure_ipforwarding ${GOTSYSD_TEST_VM_BASE_IMAGE} ${GOTSYSD_BSD_RD} vmctl start -d ${GOTSYSD_TEST_VM_BASE_IMAGE} \ -b $(GOTSYSD_BSD_RD) -c -L ${GOTSYSD_VM_NAME} start_test_vm: ensure_root ensure_ipforwarding @set -e; \ vmctl create -b ${.CURDIR}/${GOTSYSD_TEST_VM_BASE_IMAGE} \ ${GOTSYSD_TEST_DIR}/vm.qcow2; \ vmctl start -d ${GOTSYSD_TEST_DIR}/vm.qcow2 -B disk -L \ ${GOTSYSD_VM_NAME}; \ while sleep 1; do \ if vmctl status ${GOTSYSD_VM_NAME} | \ grep -q ${GOTSYSD_VM_NAME}; then \ break; \ fi; \ done; \ VMID=`vmctl status ${GOTSYSD_VM_NAME} | tail -n1 | \ awk '{print $$1}'`; \ VMIP="100.64.$$VMID.3"; \ echo "Waiting for VM to finish booting..."; \ while sleep 1; do \ if nc -z $${VMIP} ssh; then \ break; \ else \ sleep 5; \ fi; \ done; \ ${GOTD_CONF}: @${UNPRIV} "echo repository gotsys { > $@" @${UNPRIV} "echo path \'/git/gotsys.git\' >> $@" @${UNPRIV} "echo permit rw ${GOTSYSD_TEST_USER} >> $@" @${UNPRIV} "echo } >> $@" ${GOTSYSD_CONF}: @${UNPRIV} "echo permit root > $@" @${UNPRIV} "echo permit _gotd >> $@" @${UNPRIV} "echo listen on \\'${GOTSYSD_UNIX_SOCKET}\\' >> $@" ${GOTSYS_CONF}: ${GOTSYSD_SSH_PUBKEY} @${UNPRIV} "echo user ${GOTSYSD_TEST_USER} { >> $@" @${UNPRIV} "echo -n \ \ \ \ password \\\" >> $@" @${UNPRIV} "echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n' >> $@" @${UNPRIV} "echo \\\" >> $@" @${UNPRIV} "echo } >> $@" @${UNPRIV} "echo repository gotsys { >> $@" @${UNPRIV} "echo \ \ \ \ permit rw ${GOTSYSD_TEST_USER} >> $@" @${UNPRIV} "echo } >> $@" ${GOT_CONF}: @${UNPRIV} "echo author \\'${GOTSYSD_TEST_USER} \\<${GOTSYSD_TEST_USER}@localhost\\>\\' > $@" $(HTTPD_CONF): @${UNPRIV} 'echo server "VMIP" { > $@' @${UNPRIV} 'echo \ \ listen on VMIP port http >> $@' @${UNPRIV} 'echo \ \ root \"/htdocs/gotwebd\" >> $@' @${UNPRIV} 'echo \ \ location \"/\" { >> $@' @${UNPRIV} 'echo \ \ \ \ fastcgi socket \"/run/gotweb.sock\" >> $@' @${UNPRIV} 'echo \ \ } >> $@' @${UNPRIV} 'echo } >> $@' $(GOTWEBD_CONF): @${UNPRIV} 'echo prefork 1 > $@' @${UNPRIV} 'echo enable authentication insecure >> $@' @${UNPRIV} 'echo permit ${GOTSYSD_TEST_USER} >> $@' @${UNPRIV} 'echo deny ${GOTSYSD_DEV_USER} >> $@' @${UNPRIV} 'echo server \"VMIP\" { >> $@' @${UNPRIV} 'echo \ \ repos_path \"/git\" >> $@' @${UNPRIV} 'echo \ \ show_repo_age off >> $@' @${UNPRIV} 'echo \ \ show_repo_description off >> $@' @${UNPRIV} 'echo \ \ show_repo_owner off >> $@' @${UNPRIV} 'echo \ \ show_site_owner off >> $@' @${UNPRIV} 'echo \ \ repository \"public\" { >> $@' @${UNPRIV} 'echo \ \ \ \ disable authentication >> $@' @${UNPRIV} 'echo \ \ } >> $@' @${UNPRIV} 'echo \ \ repository \"gotdev\" { >> $@' @${UNPRIV} 'echo \ \ \ \ permit ${GOTSYSD_DEV_USER} >> $@' @${UNPRIV} 'echo \ \ \ \ deny ${GOTSYSD_TEST_USER} >> $@' @${UNPRIV} 'echo \ \ } >> $@' @${UNPRIV} 'echo \ \ repository \"gottest\" { >> $@' @${UNPRIV} 'echo \ \ \ \ permit ${GOTSYSD_TEST_USER} >> $@' @${UNPRIV} 'echo \ \ \ \ deny ${GOTSYSD_DEV_USER} >> $@' @${UNPRIV} 'echo \ \ } >> $@' @${UNPRIV} 'echo } >> $@' build_got: @set -e; \ VMID=`vmctl status ${GOTSYSD_VM_NAME} | tail -n1 | \ awk '{print $$1}'`; \ VMIP="100.64.$$VMID.3"; \ ${UNPRIV} "ssh-keygen -R $${VMIP}"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} ${GOTSYSD_TEST_USER}@$${VMIP} \ mkdir -p src/got bin"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} -r \ ${.CURDIR}/../../{Makefile*,cvg,got*,git*,lib*,include,tog,template} \ ${GOTSYSD_TEST_USER}@$${VMIP}:src/got/"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} build-got.sh \ ${GOTSYSD_TEST_USER}@$${VMIP}:bin/"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} ${GOTSYSD_TEST_USER}@$${VMIP} \ ./bin/build-got.sh"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ make -C /home/${GOTSYSD_TEST_USER}/src/got -- GOT_RELEASE=Yes \ DEBUG=\\'-Oo -g\\' sysd-install server-install webd-install install"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} -- root@$${VMIP} \ ln -f -s gitwrapper /usr/local/bin/git-upload-pack"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} -- root@$${VMIP} \ ln -f -s gitwrapper /usr/local/bin/git-receive-pack" setup_test_vm: start_test_vm build_got ${GOTD_CONF} ${GOTSYSD_CONF} ${GOTSYS_CONF} ${GOT_CONF} ${HTTPD_CONF} ${GOTWEBD_CONF} @set -e; \ VMID=`vmctl status ${GOTSYSD_VM_NAME} | tail -n1 | \ awk '{print $$1}'`; \ VMIP="100.64.$$VMID.3"; \ ${UNPRIV} "ssh-keygen -R $${VMIP}"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} sysctl kern.nosuidcoredump=3"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} mkdir -p -m 700 \ /var/crash/gotd /var/crash/gotsysd /var/crash/gotwebd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} sed -i 's/daemon.info/daemon.*/' /etc/syslog.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} rcctl restart syslogd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} mkdir -m 750 /git "; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ got init /git/${GOTSYS_REPO}"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOT_CONF} root@$${VMIP}:/git/${GOTSYS_REPO}/got.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} mkdir /tmp/gotsys "; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOTSYS_CONF} root@$${VMIP}:/tmp/gotsys/"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ got import -m init -r /git/${GOTSYS_REPO} \ /tmp/gotsys >/dev/null"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ groupadd -g ${GOTD_UID} _gotd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ useradd -d /nonexistent -s /sbin/nologin \ -u ${GOTD_UID} -g ${GOTD_UID} _gotd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ chown -R _gotd:_gotd /git "; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOTD_CONF} root@$${VMIP}:/etc/gotd.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ /usr/local/sbin/gotd -vvv"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ groupadd -g ${GOTSYSD_UID} _gotsysd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ useradd -d /nonexistent -s /sbin/nologin \ -u ${GOTSYSD_UID} -g ${GOTSYSD_UID} _gotsysd"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOTSYSD_CONF} root@$${VMIP}:/etc/gotsysd.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ /usr/local/sbin/gotsysd -vvv"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ groupadd -g ${GOTWEBD_UID} _gotwebd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ useradd -d /nonexistent -s /sbin/nologin \ -u ${GOTWEBD_UID} -g ${GOTWEBD_UID} -G _gotd _gotwebd"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} ${GOTWEBD_CONF} root@$${VMIP}:/etc/"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} ${HTTPD_CONF} root@$${VMIP}:/etc/"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ sed -i s/VMIP/$${VMIP}/ /etc/httpd.conf /etc/gotwebd.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} rcctl -f start httpd"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ /usr/local/sbin/gotwebd -v"; \ stop_test_vm: ensure_root @vmctl stop ${GOTSYSD_VM_NAME} test_gotsysd: @set -e; \ VMID=`vmctl status ${GOTSYSD_VM_NAME} | tail -n1 | \ awk '{print $$1}'`; \ VMIP="100.64.$$VMID.3"; \ GWIP="100.64.$$VMID.2"; \ ${UNPRIV} "env ${GOTSYSD_TEST_ENV} VMIP=$${VMIP} GWIP=$${GWIP} \ sh ./test_gotsysd.sh" test_gotwebd: @set -e; \ VMID=`vmctl status ${GOTSYSD_VM_NAME} | tail -n1 | \ awk '{print $$1}'`; \ VMIP="100.64.$$VMID.3"; \ GWIP="100.64.$$VMID.2"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ 'rm -rf /git/gotsys.git /git/foo.git /tmp/gotsys'"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ got init /git/${GOTSYS_REPO}"; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOT_CONF} root@$${VMIP}:/git/${GOTSYS_REPO}/got.conf"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} mkdir /tmp/gotsys "; \ ${UNPRIV} "${GOTSYSD_SCP_CMD} \ ${GOTSYS_CONF} root@$${VMIP}:/tmp/gotsys/"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ got import -m init -r /git/${GOTSYS_REPO} \ /tmp/gotsys >/dev/null"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ chown -R _gotd:_gotd /git"; \ ${UNPRIV} "${GOTSYSD_SSH_CMD} root@$${VMIP} \ gotsys apply -w > /dev/null"; \ ${UNPRIV} "env ${GOTSYSD_TEST_ENV} VMIP=$${VMIP} GWIP=$${GWIP} \ sh ./test_gotwebd.sh" .include got-portable-0.119/regress/gotsysd/README0000664000175000017500000000317715066535722013657 Running gotsysd regression tests requires some manual system preparation. vmd(8) must be running: # rcctl enable vmd # rcctl start vmd pf(4) must be configured to pass traffic from the default guest IP range to the internet. Assuming the default route interface is em0, this line in /etc/pf.conf should work: match out on em0 from "100.64.0.0/10" nat-to (em0) pf(4) must be configured to pass DNS requests from the guest IP range to a working DNS resolver: match in on tap inet proto udp from "100.64.0.0/10" to any \ port domain rdr-to 127.0.0.1 Replace 127.0.0.1 with your preferred resolver. The pf(4) ruleset must be reloaded: # pfctl -f /etc/pf.conf IP forwarding must be enabled for IPv4 traffic: # sysctl net.inet.ip.forwarding=1 The test suite defaults to the virtual machine name: gotsysd-test This name can be passed to vmctl(8) to control the VM. The tests require a base disk image which is used to avoid running a full VM installation for each run of the tests. The base image must be created manually by performing a scripted autoinstall(8) installation: # make vm The base disk image will be removed by 'make clean'. Once the installation has completed, wait until the guest has booted into the installed system. Once the installed system has booted successfully, the VM can be shut down from the host: # vmctl stop gotsysd-test The gotsysd test suite also tests gotwebd user authentication. These tests require the w3m browser to be installed: # pkg_add w3m Now the actual test suite can be run with: # make A test VM will be started automatically and stopped again once the tests have finished running. got-portable-0.119/regress/gotsysd/build-got.sh0000775000175000017500000000100315066535722015206 #!/bin/sh set -e cd ~/src/got # Because we copied this got src tree from the host the modified-timestamps # on already compiled files might be off. Clean out any build artifacts. # We cannot run the top-level clean target because some subdirs are missing, # most notably the regress directory. for d in got* git* lib* template; do if [ -d "${d}" ]; then make -s -C "${d}" clean > /dev/null fi done echo "Building gotsysd, gotd, gotwebd, and got:" make -s GOT_RELEASE=Yes DEBUG="-O0 -g" sysd server webd all got-portable-0.119/regress/gotsysd/http-server0000775000175000017500000000567115066535722015211 #!/usr/bin/env perl # # Copyright (c) 2024 Omar Polo # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use v5.36; use IPC::Open2; use Getopt::Long qw(:config bundling no_getopt_compat); use Digest; use Digest::HMAC; my $auth; my $address; my $port = 8000; my $hmac_secret; my $hmac_signature; my $hmac; GetOptions("a:s" => \$auth, "l:s" => \$address, "p:i" => \$port, "s:s" => \$hmac_secret) or die("usage: $0 [-a auth] [-l address] [-p port] [-s hmac_secret]\n"); my $pid = open2(my $out, my $in, 'nc', '-l', $address, $port); my $clen; while (<$out>) { local $/ = "\r\n"; chomp; last if /^$/; if (m/^POST/) { die "bad http request" unless m,^POST / HTTP/1.1$,; next; } if (m/^Host:/) { die "bad Host header" unless /^Host: $address:$port$/; next; } if (m/^Content-Type/) { die "bad content-type header" unless m,Content-Type: application/json$,; next; } if (m/^Content-Length/) { die "double content-length" if defined $clen; die "bad content-length header" unless m/Content-Length: (\d+)$/; $clen = $1; next; } if (m/Connection/) { die "bad connection header" unless m/Connection: close$/; next; } if (m/Authorization/) { die "bad authorization header" unless m/Authorization: basic (.*)$/; my $t = $1; die "wrong authorization; got $t want $auth" if not defined($auth) or $auth ne $t; next; } if (m/X-Gotd-Signature/) { die "bad hmac signature header" unless m/X-Gotd-Signature: sha256=(.*)$/; $hmac_signature = $1; next; } } die "no Content-Length header" unless defined $clen; if (defined $hmac_signature) { die "no Hmac secret provided" unless defined $hmac_secret; my $sha256 = Digest->new("SHA-256"); $hmac = Digest::HMAC->new($hmac_secret, $sha256); } while ($clen != 0) { my $len = $clen; $len = 512 if $clen > 512; my $r = read($out, my $buf, $len); $clen -= $r; if (defined $hmac) { $hmac->add($buf); } print $buf; } say ""; if (defined $hmac) { my $digest = $hmac->hexdigest; if ($digest ne $hmac_signature) { print "bad hmac signature: expected: $hmac_signature, actual: $digest"; die } } print $in "HTTP/1.1 200 OK\r\n"; print $in "Content-Length: 0\r\n"; print $in "Connection: close\r\n"; print $in "\r\n"; close $in; close $out; waitpid($pid, 0); exit $? >> 8; got-portable-0.119/regress/gotsysd/.gitignore0000664000175000017500000000036115066535722014757 SHA256.sig auto_install.conf bsd.rd bsd.rd.fs got.conf gotd.conf gotwebd.conf gotsys.conf gotsysd.conf gotsysd_bsd.rd gotsysd_sshkey gotsysd_sshkey.pub gotsysd_test_vm_base.qcow2 gotsysd_vm_passwd httpd.conf install.site stamp-setup_test_vm got-portable-0.119/regress/gotsysd/test_gotsysd.sh0000664000175000017500000017166615066536114016073 #!/bin/sh # # Copyright (c) 2025 Stefan Sperling # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. . ../cmdline/common.sh . ./common.sh test_user_add() { local testroot=`test_init user_add 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` # Ensure that the GOTSYSD_DEV_USER account does not exist yet. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} userinfo ${GOTSYSD_DEV_USER} \ 2> $testroot/stderr ret=$? if [ $ret -ne 1 ]; then echo "user ${GOTSYSD_DEV_USER} already exists" >&2 test_done "$testroot" 1 return 1 fi echo "userinfo: can't find user \`${GOTSYSD_DEV_USER}'" \ > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi # Ensure that the GOTSYSD_DEV_USER login group does not exist yet. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} groupinfo ${GOTSYSD_DEV_USER} \ 2> $testroot/stderr ret=$? if [ $ret -ne 1 ]; then echo "group ${GOTSYSD_DEV_USER} already exists" >&2 test_done "$testroot" 1 return 1 fi echo "groupinfo: can't find group \`${GOTSYSD_DEV_USER}'" \ > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # The GOTSYSD_DEV_USER account should now exist. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} userinfo ${GOTSYSD_DEV_USER} \ > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "userinfo ${GOTSYSD_DEV_USER} failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo ${GOTSYSD_DEV_USER} failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "ls /home/${GOTSYSD_DEV_USER} failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout 2>$testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "ssh ${GOTSYSD_DEV_USER}@${VMIP}succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stderr.expected < $testroot/stdout cat > $testroot/stdout.expected < $testroot/stdout 2>$testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "ssh deleteme@${VMIP}succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stderr.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD}1234 | encrypt | tr -d '\n'` # strip the optional ssh key comment for better test coverage sshkey=`cat ${GOTSYSD_SSH_PUBKEY} | cut -d' ' -f 1,2` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} grep ${GOTSYSD_DEV_USER} /etc/master.passwd \ > $testroot/master.passwd.before ret=$? if [ $ret -ne 0 ]; then echo "could not find ${GOTSYSD_DEV_USER} in master.passwd" >&2 test_done "$testroot" 1 return 1 fi got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} grep ${GOTSYSD_DEV_USER} /etc/master.passwd \ > $testroot/master.passwd.after ret=$? if [ $ret -ne 0 ]; then echo "could not find ${GOTSYSD_DEV_USER} in master.passwd" >&2 test_done "$testroot" 1 return 1 fi cmp -s $testroot/master.passwd.before $testroot/master.passwd.after ret=$? if [ $ret -eq 0 ]; then echo "${GOTSYSD_DEV_USER}'s line in master.passwd is unchanged" test_done "$testroot" "1" return 1 fi test_done "$testroot" "0" } test_user_del() { local testroot=`test_init user_del 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD}1234 | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} grep ${GOTSYSD_DEV_USER} /etc/master.passwd \ > $testroot/master.passwd.before ret=$? if [ $ret -ne 0 ]; then echo "could not find ${GOTSYSD_DEV_USER} in master.passwd" >&2 test_done "$testroot" 1 return 1 fi got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} grep deleteme /etc/master.passwd \ > $testroot/master.passwd.after ret=$? if [ $ret -ne 0 ]; then echo "could not find deleteme in master.passwd" >&2 test_done "$testroot" 1 return 1 fi cmp -s $testroot/master.passwd.before $testroot/master.passwd.after ret=$? if [ $ret -eq 0 ]; then echo "${GOTSYSD_DEV_USER}'s line in master.passwd is unchanged" test_done "$testroot" "1" return 1 fi # The deleteme account should still exist because we oo not # allow UIDs to be recycled. ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} userinfo deleteme \ > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "userinfo deleteme failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout cat > $testroot/stdout.expected < $testroot/stdout 2> $testroot/stderr echo -n > $testroot/stdout.expected cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi cat > $testroot/stderr.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` # Ensure that the developers group does not exist yet. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} groupinfo developers \ 2> $testroot/stderr ret=$? if [ $ret -ne 1 ]; then echo "user already exists" >&2 test_done "$testroot" 1 return 1 fi echo "groupinfo: can't find group \`developers'" \ > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # The developers group should now exist. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} groupinfo developers > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo developers failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "userinfo ${GOTSYSD_DEV_USER} failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo slackers failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` # Ensure that the developers group exists. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} groupinfo developers > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo developers failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected <&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # The developers group should still exist because we do not # recycle GIDs. But the group should have no members. ssh -q -i ${GOTSYSD_SSH_KEY} \ root@${VMIP} groupinfo developers > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo developers failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "userinfo ${GOTSYSD_DEV_USER} failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "groupinfo slackers failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # The new repository should now exist. ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} ls /git \ > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "ls /git failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "ls /git failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stdout.expected < $testroot/foo/alpha got import -m init -r $testroot/foo.git $testroot/foo >/dev/null cat > $testroot/foo.git/got.conf <&2 test_done "$testroot" 1 return 1 fi test_done "$testroot" "$ret" } test_user_anonymous() { local testroot=`test_init user_anonymous 1` # An attempt to grant write permissions to anonymus is an error. cat > ${testroot}/bad-gotsys.conf < $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "gotsys check suceeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo -n "gotsys: ${testroot}/bad-gotsys.conf: line 2: " \ > $testroot/stderr.expected echo "the \"anonymous\" user must not have write permission" \ >> $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # The new repository should be readable anonymously. got clone -q anonymous@${VMIP}:foo.git $testroot/foo-anonclone.git ret=$? if [ $ret -ne 0 ]; then echo "got clone failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi test_done "$testroot" "$ret" } test_user_anonymous_remove() { local testroot=`test_init user_anonymous_remove 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # Repository foo should no longer be readable anonymously. env SSH_ASKPASS="/usr/bin/true" SSH_ASKPASS_REQUIRE=force \ got clone anonymous@${VMIP}:foo.git \ $testroot/foo-anonclone.git > /dev/null 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got clone succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi printf "Permission denied, please try again.\r\n" \ > $testroot/stderr.expected printf "Permission denied, please try again.\r\n" \ >> $testroot/stderr.expected printf "anonymous@${VMIP}: Permission denied (publickey,password,keyboard-interactive).\r\n" \ >> $testroot/stderr.expected echo "got-fetch-pack: unexpected end of file" \ >> $testroot/stderr.expected echo "got: unexpected end of file" >> $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_bad_gotsysconf() { local testroot=`test_init bad_gotsysconf 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # An attempt to send an invalid gotsys.conf file cat > ${testroot}/wt/gotsys.conf < $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "gotsys check suceeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "gotsys: ${testroot}/wt/gotsys.conf: line 3: syntax error" \ > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi (cd ${testroot}/wt && got commit -m "commit a bad gotsys.conf" \ >/dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got send succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > ${testroot}/stderr.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` # An attempt to send an invalid gotsys.conf file cat > ${testroot}/wt/gotsys.conf < $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "gotsys check succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "gotsys: ${testroot}/wt/gotsys.conf: line 18: invalid reference name: refs/heads/mai\"n" \ > $testroot/stderr.expected cmp -s $testroot/stderr.expected $testroot/stderr ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "$ret" return 1 fi (cd ${testroot}/wt && got commit -m "commit a bad gotsys.conf" \ >/dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got send succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > ${testroot}/stderr.expected < ${testroot}/bad-gotsys.conf < $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "gotsys check succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi cat > $testroot/stderr.expected </dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # Create branch "foo" in foo.git. got clone -q -i ${GOTSYSD_SSH_KEY} -b main \ ${GOTSYSD_DEV_USER}@${VMIP}:foo.git $testroot/foo.git got branch -r $testroot/foo.git -c main foo got send -q -i ${GOTSYSD_SSH_KEY} -r $testroot/foo.git -b foo ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 return 1 fi # The foo repository should now advertise refs/heads/foo as HEAD. got clone -q -l anonymous@${VMIP}:foo.git | egrep '^HEAD:' \ > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "got clone -l failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "HEAD: refs/heads/foo" > $testroot/stdout.expected cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_protect_refs() { local testroot=`test_init protect_refs 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # Create a new commit on branch "foo" and send it. got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \ ${GOTSYSD_DEV_USER}@${VMIP}:foo.git $testroot/foo.git got checkout -q $testroot/foo.git $testroot/wt-foo > /dev/null echo "tweak alpha" > $testroot/wt-foo/alpha (cd $testroot/wt-foo && got commit -m 'change alpha' > /dev/null) got send -q -i ${GOTSYSD_SSH_KEY} -r $testroot/foo.git -b foo ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 return 1 fi # Attempt to rewrite the history of branch "foo". (cd $testroot/wt-foo && got update -q -c :head:-1 > /dev/null) (cd $testroot/wt-foo && got histedit -d > /dev/null) got send -q -i ${GOTSYSD_SSH_KEY} -r $testroot/foo.git -b foo -f \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got send succeeded unexpectedly" >&2 return 1 fi echo -n "" > $testroot/stdout.expected cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi echo "gotsh: refs/heads/foo: reference is protected" \ > $testroot/stderr.expected grep '^gotsh:' $testroot/stderr > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr.filtered test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_deny_access() { local testroot=`test_init deny_access 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi # Try to clone repository foo. Should fail. got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \ ${GOTSYSD_DEV_USER}@${VMIP}:foo.git $testroot/foo.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got clone succeeded unexpectedly" >&2 return 1 fi echo -n "" > $testroot/stdout.expected cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi echo "gotsh: foo: Permission denied" > $testroot/stderr.expected grep '^gotsh:' $testroot/stderr > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr.filtered test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_override_access_rules() { local testroot=`test_init override_access_rules 1` # Override gotsys.conf access rules which deny access to foo.git. echo "repository permit ro ${GOTSYSD_DEV_USER}" | \ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ 'cat >> /etc/gotsysd.conf' # Restart gotsysd (XXX need a better way to do this...) ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'pkill -xf /usr/local/sbin/gotsysd' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} '/usr/local/sbin/gotsysd -vvv' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'gotsys apply -w' > /dev/null # Cloning repository foo should now succeed. got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \ ${GOTSYSD_DEV_USER}@${VMIP}:foo.git $testroot/foo.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -ne 0 ]; then echo "got clone failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # gotsys.git access should now be read-only. got clone -q -i ${GOTSYSD_SSH_KEY} \ ${GOTSYSD_DEV_USER}@${VMIP}:gotsys.git $testroot/gotsys2.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -ne 0 ]; then echo "got clone failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi got checkout -q $testroot/gotsys2.git $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/gotsys2.git` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/gotsys2.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got send succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "gotsh: gotsys.git: Permission denied" > $testroot/stderr.expected grep '^gotsh:' $testroot/stderr > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected $testroot/stderr.filtered test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_override_all_user_access() { local testroot=`test_init override_all_user_access 1` # Override gotsys.conf access rules which deny access to foo.git. echo 'repository deny "*"' | \ ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ 'cat >> /etc/gotsysd.conf' # Restart gotsysd (XXX need a better way to do this...) ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'pkill -xf /usr/local/sbin/gotsysd' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} '/usr/local/sbin/gotsysd -vvv' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'gotsys apply -w' > /dev/null # Cloning any repository as any user should now fail. for user in ${GOTSYSD_TEST_USER} ${GOTSYSD_DEV_USER} anonymous; do got clone -q -i ${GOTSYSD_SSH_KEY} -b foo \ ${user}@${VMIP}:foo.git $testroot/foo-${user}.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got clone succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "got-fetch-pack: foo: Permission denied" \ > $testroot/stderr.expected grep '^got-fetch-pack:' $testroot/stderr \ > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected \ $testroot/stderr.filtered test_done "$testroot" "$ret" return 1 fi got clone -q -i ${GOTSYSD_SSH_KEY} \ ${user}@${VMIP}:gotsys.git \ $testroot/gotsys-${user}.git \ > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then echo "got clone succeeded unexpectedly" >&2 test_done "$testroot" 1 return 1 fi echo "got-fetch-pack: gotsys.git: Permission denied" \ > $testroot/stderr.expected grep '^got-fetch-pack:' $testroot/stderr \ > $testroot/stderr.filtered cmp -s $testroot/stderr.expected $testroot/stderr.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stderr.expected \ $testroot/stderr.filtered test_done "$testroot" "$ret" return 1 fi done # Undo gotsys.conf override ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'rm -f /etc/gotsysd.conf' # Restart gotsysd (XXX need a better way to do this...) ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'pkill -xf /usr/local/sbin/gotsysd' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} '/usr/local/sbin/gotsysd -vvv' sleep 1 ssh -q -i ${GOTSYSD_SSH_KEY} root@${VMIP} 'gotsys apply -w' > /dev/null test_done "$testroot" "$ret" } # flan:password encoded in base64 AUTH="ZmxhbjpwYXNzd29yZA==" test_http_notification() { local testroot=`test_init http_notification 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` local author_time=`git_show_author_time $testroot/${GOTSYS_REPO}` timeout 5 ./http-server -a $AUTH -l "$GWIP" \ -p "$GOTSYSD_TEST_HTTP_PORT" > $testroot/stdout & sleep 1 # server starts up got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi wait %1 # wait for the http "server" echo -n > "$testroot/stdout.expected" ed -s "$testroot/stdout.expected" <<-EOF a {"notifications":[{ "type":"commit", "short":false, "repo":"gotsys.git", "authenticated_user":"${GOTSYSD_TEST_USER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", "name":"$GIT_AUTHOR_NAME", "mail":"$GIT_AUTHOR_EMAIL", "user":"$GOT_AUTHOR_11" }, "committer":{ "full":"$GOT_AUTHOR", "name":"$GIT_AUTHOR_NAME", "mail":"$GIT_AUTHOR_EMAIL", "user":"$GOT_AUTHOR_11" }, "date":$author_time, "short_message":"whitespace changes", "message":"whitespace changes\n", "diffstat":{ "files":[{ "action":"modified", "file":"gotsys.conf", "added":2, "removed":0 }], "total":{ "added":1, "removed":2 } } }]} . ,j w EOF cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_http_notification_hmac() { local testroot=`test_init http_notification_hmac 1` got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` local author_time=`git_show_author_time $testroot/${GOTSYS_REPO}` timeout 5 ./http-server -a $AUTH -l "$GWIP" \ -p "$GOTSYSD_TEST_HTTP_PORT" -s "$GOTSYSD_TEST_HMAC_SECRET" \ > $testroot/stdout & sleep 1 # server starts up got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi wait %1 # wait for the http "server" echo -n > "$testroot/stdout.expected" ed -s "$testroot/stdout.expected" <<-EOF a {"notifications":[{ "type":"commit", "short":false, "repo":"gotsys.git", "authenticated_user":"${GOTSYSD_TEST_USER}", "id":"$commit_id", "author":{ "full":"$GOT_AUTHOR", "name":"$GIT_AUTHOR_NAME", "mail":"$GIT_AUTHOR_EMAIL", "user":"$GOT_AUTHOR_11" }, "committer":{ "full":"$GOT_AUTHOR", "name":"$GIT_AUTHOR_NAME", "mail":"$GIT_AUTHOR_EMAIL", "user":"$GOT_AUTHOR_11" }, "date":$author_time, "short_message":"whitespace changes", "message":"whitespace changes\n", "diffstat":{ "files":[{ "action":"modified", "file":"gotsys.conf", "added":0, "removed":3 }], "total":{ "added":1, "removed":0 } } }]} . ,j w EOF cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi test_done "$testroot" "$ret" } test_email_notification() { local testroot=`test_init email_notification 1` # Need to smtpd in the test VM since we will be using port 25 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ '/etc/rc.d/smtpd stop' > /dev/null got checkout -q $testroot/${GOTSYS_REPO} $testroot/wt >/dev/null ret=$? if [ $ret -ne 0 ]; then echo "got checkout failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Wait for gotsysd to apply the new configuration. echo "$commit_id" > $testroot/stdout.expected for i in 1 2 3 4 5; do sleep 1 ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ cat /var/db/gotsysd/commit > $testroot/stdout if cmp -s $testroot/stdout.expected $testroot/stdout; then break; fi done cmp -s $testroot/stdout.expected $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "gotsysd failed to apply configuration" >&2 diff -u $testroot/stdout.expected $testroot/stdout test_done "$testroot" "$ret" return 1 fi cat > ${testroot}/wt/gotsys.conf </dev/null) local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` local author_time=`git_show_author_time $testroot/${GOTSYS_REPO}` ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ 'printf "220\r\n250\r\n250\r\n250\r\n354\r\n250\r\n221\r\n" \ | timeout 5 nc -l 25' > $testroot/stdout & sleep 1 # server starts up got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} ret=$? if [ $ret -ne 0 ]; then echo "got send failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi wait %1 # wait for ssh / nc -l short_commit_id=`trim_obj_id 12 $commit_id` HOSTNAME=`ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} hostname` printf "HELO localhost\r\n" > $testroot/stdout.expected printf "MAIL FROM:<${GOTD_USER}@${HOSTNAME}>\r\n" \ >> $testroot/stdout.expected printf "RCPT TO:<${GOTSYSD_TEST_USER}@example.com>\r\n" \ >> $testroot/stdout.expected printf "DATA\r\n" >> $testroot/stdout.expected printf "From: ${GOTD_USER}@${HOSTNAME}\r\n" >> $testroot/stdout.expected printf "To: ${GOTSYSD_TEST_USER}@example.com\r\n" \ >> $testroot/stdout.expected printf "Subject: $GOTSYS_REPO: " >> $testroot/stdout.expected printf "${GOTSYSD_TEST_USER} changed refs/heads/main: $short_commit_id\r\n" \ >> $testroot/stdout.expected printf "\r\n" >> $testroot/stdout.expected printf "commit $commit_id\n" >> $testroot/stdout.expected printf "from: $GOT_AUTHOR\n" >> $testroot/stdout.expected d=`date -u -r $author_time +"%a %b %e %X %Y UTC"` printf "date: $d\n" >> $testroot/stdout.expected printf "messagelen: 20\n" >> $testroot/stdout.expected printf " \n" >> $testroot/stdout.expected printf " whitespace changes\n \n" >> $testroot/stdout.expected printf " M gotsys.conf | 3+ 0-\n\n" >> $testroot/stdout.expected printf "1 file changed, 3 insertions(+), 0 deletions(-)\n\n" \ >> $testroot/stdout.expected printf "\r\n" >> $testroot/stdout.expected printf ".\r\n" >> $testroot/stdout.expected printf "QUIT\r\n" >> $testroot/stdout.expected grep -v ^Date $testroot/stdout > $testroot/stdout.filtered cmp -s $testroot/stdout.expected $testroot/stdout.filtered ret=$? if [ $ret -ne 0 ]; then diff -u $testroot/stdout.expected $testroot/stdout.filtered test_done "$testroot" "$ret" return 1 fi # Restart smtpd ssh -i ${GOTSYSD_SSH_KEY} root@${VMIP} \ '/etc/rc.d/smtpd start' > /dev/null test_done "$testroot" "$ret" } test_parseargs "$@" run_test test_user_add run_test test_user_mod run_test test_user_del run_test test_group_add run_test test_group_del run_test test_repo_create run_test test_user_anonymous run_test test_user_anonymous_remove run_test test_bad_gotsysconf run_test test_bad_ref_in_gotsysconf run_test test_set_head run_test test_protect_refs run_test test_deny_access run_test test_override_access_rules run_test test_override_all_user_access run_test test_http_notification run_test test_http_notification_hmac run_test test_email_notification got-portable-0.119/regress/gotsysd/test_gotwebd.sh0000775000175000017500000002610015066535722016017 #!/bin/sh # # Copyright (c) 2025 Stefan Sperling # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. . ../cmdline/common.sh . ./common.sh test_login() { local testroot=`test_init login 1` # Attempt unauthorized access. w3m "http://${VMIP}/" -dump > $testroot/stdout cat > $testroot/stdout.expected < $testroot/stdout ret=$? if [ $ret -ne 0 ]; then echo "ssh login failed failed unexpectedly" >&2 test_done "$testroot" 1 return 1 fi # Request the index page again using the login token and # storing the cookie sent by gotwebd. url=$(cut -d: -f 2,3 < $testroot/stdout | sed -e 's/ https:/http:/') w3m -cookie-jar "$testroot/cookies" "$url" -dump > $testroot/stdout cat > $testroot/stdout.expected < $testroot/stdout local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` local commit_time=`git_show_author_time $testroot/${GOTSYS_REPO} $commit_id` local d=$(env LC_ALL=C date -u -r "$commit_time" \ +"%a %b %e %H:%M:%S %Y UTC") local tree_id=$(got cat -r $testroot/${GOTSYS_REPO} $commit_id | \ grep 'tree ' | cut -d ' ' -f2) cat > $testroot/stdout.expected < $testroot/stdout local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` local tree_id=$(got cat -r $testroot/${GOTSYS_REPO} $commit_id | \ grep 'tree ' | cut -d ' ' -f2) cat > $testroot/stdout.expected <