contrib/chg/chg.c
author Yuya Nishihara <yuya@tcha.org>
Tue, 03 Nov 2020 11:12:25 +0900
branchstable
changeset 45849 731ea8fa1f11
parent 45848 41aaf960dc00
child 45850 9534de20358f
permissions -rw-r--r--
chg: show debug message for each fd to be closed It helps debugging. The number of file descriptors should be small in most cases, so the console output wouldn't get bloated even with CHG_DEBUG=1.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     1
/*
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     2
 * A fast client for Mercurial command server
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     3
 *
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     4
 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     5
 *
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     6
 * This software may be used and distributed according to the terms of the
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     7
 * GNU General Public License version 2 or any later version.
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     8
 */
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     9
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    10
#include <assert.h>
45802
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
    11
#include <dirent.h>
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    12
#include <errno.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    13
#include <fcntl.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    14
#include <signal.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    15
#include <stdio.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    16
#include <stdlib.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    17
#include <string.h>
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
    18
#include <sys/file.h>
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    19
#include <sys/stat.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    20
#include <sys/types.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    21
#include <sys/un.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    22
#include <sys/wait.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    23
#include <time.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    24
#include <unistd.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    25
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    26
#include "hgclient.h"
30693
baee0f47b533 chg: add procutil.h
Jun Wu <quark@fb.com>
parents: 30692
diff changeset
    27
#include "procutil.h"
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    28
#include "util.h"
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    29
30677
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
    30
#ifndef PATH_MAX
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
    31
#define PATH_MAX 4096
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    32
#endif
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    33
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    34
struct cmdserveropts {
30677
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
    35
	char sockname[PATH_MAX];
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
    36
	char initsockname[PATH_MAX];
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
    37
	char redirectsockname[PATH_MAX];
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    38
	size_t argsize;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    39
	const char **args;
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    40
};
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    41
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    42
static void initcmdserveropts(struct cmdserveropts *opts)
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    43
{
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    44
	memset(opts, 0, sizeof(struct cmdserveropts));
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    45
}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    46
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    47
static void freecmdserveropts(struct cmdserveropts *opts)
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    48
{
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    49
	free(opts->args);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    50
	opts->args = NULL;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    51
	opts->argsize = 0;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    52
}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    53
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    54
/*
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    55
 * Test if an argument is a sensitive flag that should be passed to the server.
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    56
 * Return 0 if not, otherwise the number of arguments starting from the current
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    57
 * one that should be passed to the server.
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    58
 */
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    59
static size_t testsensitiveflag(const char *arg)
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    60
{
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    61
	static const struct {
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    62
		const char *name;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    63
		size_t narg;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    64
	} flags[] = {
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    65
	    {"--config", 1},     {"--cwd", 1},       {"--repo", 1},
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    66
	    {"--repository", 1}, {"--traceback", 0}, {"-R", 1},
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    67
	};
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    68
	size_t i;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    69
	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) {
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    70
		size_t len = strlen(flags[i].name);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    71
		size_t narg = flags[i].narg;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    72
		if (memcmp(arg, flags[i].name, len) == 0) {
28790
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    73
			if (arg[len] == '\0') {
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    74
				/* --flag (value) */
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    75
				return narg + 1;
28790
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    76
			} else if (arg[len] == '=' && narg > 0) {
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    77
				/* --flag=value */
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    78
				return 1;
28790
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    79
			} else if (flags[i].name[1] != '-') {
b0cc9652e8dc chg: wrap line at 80 chars
Jun Wu <quark@fb.com>
parents: 28789
diff changeset
    80
				/* short flag */
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    81
				return 1;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    82
			}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    83
		}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    84
	}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    85
	return 0;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    86
}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    87
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    88
/*
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    89
 * Parse argv[] and put sensitive flags to opts->args
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    90
 */
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    91
static void setcmdserverargs(struct cmdserveropts *opts, int argc,
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    92
                             const char *argv[])
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    93
{
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    94
	size_t i, step;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    95
	opts->argsize = 0;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    96
	for (i = 0, step = 1; i < (size_t)argc; i += step, step = 1) {
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    97
		if (!argv[i])
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
    98
			continue; /* pass clang-analyse */
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
    99
		if (strcmp(argv[i], "--") == 0)
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   100
			break;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   101
		size_t n = testsensitiveflag(argv[i]);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   102
		if (n == 0 || i + n > (size_t)argc)
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   103
			continue;
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   104
		opts->args =
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   105
		    reallocx(opts->args, (n + opts->argsize) * sizeof(char *));
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   106
		memcpy(opts->args + opts->argsize, argv + i,
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   107
		       sizeof(char *) * n);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   108
		opts->argsize += n;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   109
		step = n;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   110
	}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   111
}
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   112
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   113
static void preparesockdir(const char *sockdir)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   114
{
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   115
	int r;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   116
	r = mkdir(sockdir, 0700);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   117
	if (r < 0 && errno != EEXIST)
28789
7f6e0a15189b chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
   118
		abortmsgerrno("cannot create sockdir %s", sockdir);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   119
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   120
	struct stat st;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   121
	r = lstat(sockdir, &st);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   122
	if (r < 0)
28789
7f6e0a15189b chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
   123
		abortmsgerrno("cannot stat %s", sockdir);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   124
	if (!S_ISDIR(st.st_mode))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   125
		abortmsg("cannot create sockdir %s (file exists)", sockdir);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   126
	if (st.st_uid != geteuid() || st.st_mode & 0077)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   127
		abortmsg("insecure sockdir %s", sockdir);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   128
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   129
30884
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   130
/*
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   131
 * Check if a socket directory exists and is only owned by the current user.
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   132
 * Return 1 if so, 0 if not. This is used to check if XDG_RUNTIME_DIR can be
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   133
 * used or not. According to the specification [1], XDG_RUNTIME_DIR should be
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   134
 * ignored if the directory is not owned by the user with mode 0700.
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   135
 * [1]: https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   136
 */
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   137
static int checkruntimedir(const char *sockdir)
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   138
{
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   139
	struct stat st;
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   140
	int r = lstat(sockdir, &st);
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   141
	if (r < 0) /* ex. does not exist */
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   142
		return 0;
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   143
	if (!S_ISDIR(st.st_mode)) /* ex. is a file, not a directory */
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   144
		return 0;
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   145
	return st.st_uid == geteuid() && (st.st_mode & 0777) == 0700;
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   146
}
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   147
30680
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   148
static void getdefaultsockdir(char sockdir[], size_t size)
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   149
{
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   150
	/* by default, put socket file in secure directory
30681
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   151
	 * (${XDG_RUNTIME_DIR}/chg, or /${TMPDIR:-tmp}/chg$UID)
30680
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   152
	 * (permission of socket file may be ignored on some Unices) */
30681
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   153
	const char *runtimedir = getenv("XDG_RUNTIME_DIR");
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   154
	int r;
30884
a68510b69f41 chg: verify XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30741
diff changeset
   155
	if (runtimedir && checkruntimedir(runtimedir)) {
30681
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   156
		r = snprintf(sockdir, size, "%s/chg", runtimedir);
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   157
	} else {
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   158
		const char *tmpdir = getenv("TMPDIR");
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   159
		if (!tmpdir)
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   160
			tmpdir = "/tmp";
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   161
		r = snprintf(sockdir, size, "%s/chg%d", tmpdir, geteuid());
0064a1eb28e2 chg: respect XDG_RUNTIME_DIR
Jun Wu <quark@fb.com>
parents: 30680
diff changeset
   162
	}
30680
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   163
	if (r < 0 || (size_t)r >= size)
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   164
		abortmsg("too long TMPDIR (r = %d)", r);
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   165
}
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   166
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   167
static void setcmdserveropts(struct cmdserveropts *opts)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   168
{
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   169
	int r;
30677
c80c16a8a0b0 chg: support long socket path
Jun Wu <quark@fb.com>
parents: 30676
diff changeset
   170
	char sockdir[PATH_MAX];
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   171
	const char *envsockname = getenv("CHGSOCKNAME");
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   172
	if (!envsockname) {
30680
4677df6b449a chg: make "get default sockdir" a separate method
Jun Wu <quark@fb.com>
parents: 30677
diff changeset
   173
		getdefaultsockdir(sockdir, sizeof(sockdir));
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   174
		preparesockdir(sockdir);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   175
	}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   176
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   177
	const char *basename = (envsockname) ? envsockname : sockdir;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   178
	const char *sockfmt = (envsockname) ? "%s" : "%s/server";
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   179
	r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   180
	if (r < 0 || (size_t)r >= sizeof(opts->sockname))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   181
		abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   182
	r = snprintf(opts->initsockname, sizeof(opts->initsockname), "%s.%u",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   183
	             opts->sockname, (unsigned)getpid());
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   184
	if (r < 0 || (size_t)r >= sizeof(opts->initsockname))
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   185
		abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   186
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   187
45551
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   188
/* If the current program is, say, /a/b/c/chg, returns /a/b/c/hg. */
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   189
static char *getrelhgcmd(void)
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   190
{
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   191
	ssize_t n;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   192
	char *res, *slash;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   193
	int maxsize = 4096;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   194
	res = malloc(maxsize);
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   195
	if (res == NULL)
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   196
		goto cleanup;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   197
	n = readlink("/proc/self/exe", res, maxsize);
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   198
	if (n < 0 || n >= maxsize)
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   199
		goto cleanup;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   200
	res[n] = '\0';
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   201
	slash = strrchr(res, '/');
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   202
	if (slash == NULL)
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   203
		goto cleanup;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   204
	/* 4 is strlen("/hg") + nul byte */
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   205
	if (slash + 4 >= res + maxsize)
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   206
		goto cleanup;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   207
	memcpy(slash, "/hg", 4);
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   208
	return res;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   209
cleanup:
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   210
	free(res);
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   211
	return NULL;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   212
}
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   213
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   214
static const char *gethgcmd(void)
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   215
{
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   216
	static const char *hgcmd = NULL;
45551
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   217
#ifdef HGPATHREL
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   218
	int tryrelhgcmd = 1;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   219
#else
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   220
	int tryrelhgcmd = 0;
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   221
#endif
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   222
	if (!hgcmd) {
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   223
		hgcmd = getenv("CHGHG");
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   224
		if (!hgcmd || hgcmd[0] == '\0')
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   225
			hgcmd = getenv("HG");
45551
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   226
		if (tryrelhgcmd && (!hgcmd || hgcmd[0] == '\0'))
4c8d9b53b1c7 chg: make is possible to call by default an hg binary located next to chg
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 45520
diff changeset
   227
			hgcmd = getrelhgcmd();
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   228
		if (!hgcmd || hgcmd[0] == '\0')
28605
baa073200ba2 chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents: 28555
diff changeset
   229
#ifdef HGPATH
baa073200ba2 chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents: 28555
diff changeset
   230
			hgcmd = (HGPATH);
baa073200ba2 chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents: 28555
diff changeset
   231
#else
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   232
			hgcmd = "hg";
28605
baa073200ba2 chg: allows default hg path to be overridden
Jun Wu <quark@fb.com>
parents: 28555
diff changeset
   233
#endif
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   234
	}
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   235
	return hgcmd;
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   236
}
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   237
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   238
static void execcmdserver(const struct cmdserveropts *opts)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   239
{
28237
a3d73e069f8d chg: extract gethgcmd logic to a function
Jun Wu <quark@fb.com>
parents: 28196
diff changeset
   240
	const char *hgcmd = gethgcmd();
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   241
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   242
	const char *baseargv[] = {
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   243
	    hgcmd,
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   244
	    "serve",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   245
	    "--cmdserver",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   246
	    "chgunix",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   247
	    "--address",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   248
	    opts->initsockname,
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   249
	    "--daemon-postexec",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   250
	    "chdir:/",
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   251
	};
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   252
	size_t baseargvsize = sizeof(baseargv) / sizeof(baseargv[0]);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   253
	size_t argsize = baseargvsize + opts->argsize + 1;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   254
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   255
	const char **argv = mallocx(sizeof(char *) * argsize);
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   256
	memcpy(argv, baseargv, sizeof(baseargv));
38198
3c84493556db chg: fix an undefined behavior about memcpy
Jun Wu <quark@fb.com>
parents: 35959
diff changeset
   257
	if (opts->args) {
3c84493556db chg: fix an undefined behavior about memcpy
Jun Wu <quark@fb.com>
parents: 35959
diff changeset
   258
		size_t size = sizeof(char *) * opts->argsize;
3c84493556db chg: fix an undefined behavior about memcpy
Jun Wu <quark@fb.com>
parents: 35959
diff changeset
   259
		memcpy(argv + baseargvsize, opts->args, size);
3c84493556db chg: fix an undefined behavior about memcpy
Jun Wu <quark@fb.com>
parents: 35959
diff changeset
   260
	}
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   261
	argv[argsize - 1] = NULL;
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   262
44261
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   263
	const char *lc_ctype_env = getenv("LC_CTYPE");
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   264
	if (lc_ctype_env == NULL) {
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   265
		if (putenv("CHG_CLEAR_LC_CTYPE=") != 0)
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   266
			abortmsgerrno("failed to putenv CHG_CLEAR_LC_CTYPE");
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   267
	} else {
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   268
		if (setenv("CHGORIG_LC_CTYPE", lc_ctype_env, 1) != 0) {
44995
2c920c4dbb31 chg: fix typo
Manuel Jacob <me@manueljacob.de>
parents: 44617
diff changeset
   269
			abortmsgerrno("failed to setenv CHGORIG_LC_CTYPE");
44261
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   270
		}
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   271
	}
04a3ae7aba14 chg: force-set LC_CTYPE on server start to actual value from the environment
Kyle Lippincott <spectral@google.com>
parents: 38198
diff changeset
   272
45802
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   273
	/* close any open files to avoid hanging locks */
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   274
	DIR *dp = opendir("/proc/self/fd");
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   275
	if (dp != NULL) {
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   276
		debugmsg("closing files based on /proc contents");
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   277
		struct dirent *de;
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   278
		while ((de = readdir(dp))) {
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   279
			char *end;
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   280
			long fd_value = strtol(de->d_name, &end, 10);
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   281
			if (end == de->d_name) {
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   282
				/* unable to convert to int (. or ..) */
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   283
				continue;
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   284
			}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   285
			if (errno == ERANGE) {
45848
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   286
				debugmsg("tried to parse %s, but range error "
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   287
				         "occurred",
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   288
				         de->d_name);
45802
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   289
				continue;
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   290
			}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   291
			if (fd_value > STDERR_FILENO) {
45849
731ea8fa1f11 chg: show debug message for each fd to be closed
Yuya Nishihara <yuya@tcha.org>
parents: 45848
diff changeset
   292
				debugmsg("closing fd %ld", fd_value);
45802
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   293
				int res = close(fd_value);
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   294
				if (res) {
45848
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   295
					debugmsg("tried to close fd %ld: %d "
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   296
					         "(errno: %d)",
41aaf960dc00 chg: apply clang-format
Yuya Nishihara <yuya@tcha.org>
parents: 45802
diff changeset
   297
					         fd_value, res, errno);
45802
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   298
				}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   299
			}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   300
		}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   301
	}
8711dc13474c chg: close file descriptors when starting the daemon
Mathias De Mare <mathias.de_mare@nokia.com>
parents: 45551
diff changeset
   302
28261
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28260
diff changeset
   303
	if (putenv("CHGINTERNALMARK=") != 0)
28789
7f6e0a15189b chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
   304
		abortmsgerrno("failed to putenv");
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   305
	if (execvp(hgcmd, (char **)argv) < 0)
28789
7f6e0a15189b chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
   306
		abortmsgerrno("failed to exec cmdserver");
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   307
	free(argv);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   308
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   309
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   310
/* Retry until we can connect to the server. Give up after some time. */
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   311
static hgclient_t *retryconnectcmdserver(struct cmdserveropts *opts, pid_t pid)
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   312
{
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   313
	static const struct timespec sleepreq = {0, 10 * 1000000};
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   314
	int pst = 0;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   315
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   316
	debugmsg("try connect to %s repeatedly", opts->initsockname);
29345
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   317
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   318
	unsigned int timeoutsec = 60; /* default: 60 seconds */
29345
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   319
	const char *timeoutenv = getenv("CHGTIMEOUT");
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   320
	if (timeoutenv)
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   321
		sscanf(timeoutenv, "%u", &timeoutsec);
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   322
62b890496de5 chg: make timeout adjustable
Jun Wu <quark@fb.com>
parents: 29344
diff changeset
   323
	for (unsigned int i = 0; !timeoutsec || i < timeoutsec * 100; i++) {
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   324
		hgclient_t *hgc = hgc_open(opts->initsockname);
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   325
		if (hgc) {
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   326
			debugmsg("rename %s to %s", opts->initsockname,
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   327
			         opts->sockname);
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   328
			int r = rename(opts->initsockname, opts->sockname);
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   329
			if (r != 0)
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   330
				abortmsgerrno("cannot rename");
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   331
			return hgc;
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   332
		}
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   333
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   334
		if (pid > 0) {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   335
			/* collect zombie if child process fails to start */
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   336
			int r = waitpid(pid, &pst, WNOHANG);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   337
			if (r != 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   338
				goto cleanup;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   339
		}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   340
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   341
		nanosleep(&sleepreq, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   342
	}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   343
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   344
	abortmsg("timed out waiting for cmdserver %s", opts->initsockname);
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   345
	return NULL;
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   346
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   347
cleanup:
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   348
	if (WIFEXITED(pst)) {
28863
6e06fbee9244 chg: server exited with code 0 without being connectable is an error
Jun Wu <quark@fb.com>
parents: 28856
diff changeset
   349
		if (WEXITSTATUS(pst) == 0)
6e06fbee9244 chg: server exited with code 0 without being connectable is an error
Jun Wu <quark@fb.com>
parents: 28856
diff changeset
   350
			abortmsg("could not connect to cmdserver "
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   351
			         "(exited with status 0)");
28477
194a6cd873cd chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents: 28455
diff changeset
   352
		debugmsg("cmdserver exited with status %d", WEXITSTATUS(pst));
194a6cd873cd chg: silently inherit server exit code
Jun Wu <quark@fb.com>
parents: 28455
diff changeset
   353
		exit(WEXITSTATUS(pst));
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   354
	} else if (WIFSIGNALED(pst)) {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   355
		abortmsg("cmdserver killed by signal %d", WTERMSIG(pst));
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   356
	} else {
28851
584e0716c7af chg: fix spelling in the error message about error waiting for cmdserver
Jun Wu <quark@fb.com>
parents: 28790
diff changeset
   357
		abortmsg("error while waiting for cmdserver");
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   358
	}
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   359
	return NULL;
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   360
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   361
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   362
/* Connect to a cmdserver. Will start a new server on demand. */
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   363
static hgclient_t *connectcmdserver(struct cmdserveropts *opts)
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   364
{
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   365
	const char *sockname =
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   366
	    opts->redirectsockname[0] ? opts->redirectsockname : opts->sockname;
28769
222f482930c8 chg: make connect debug message less repetitive
Jun Wu <quark@fb.com>
parents: 28605
diff changeset
   367
	debugmsg("try connect to %s", sockname);
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   368
	hgclient_t *hgc = hgc_open(sockname);
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   369
	if (hgc)
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   370
		return hgc;
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   371
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   372
	/* prevent us from being connected to an outdated server: we were
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   373
	 * told by a server to redirect to opts->redirectsockname and that
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   374
	 * address does not work. we do not want to connect to the server
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   375
	 * again because it will probably tell us the same thing. */
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   376
	if (sockname == opts->redirectsockname)
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   377
		unlink(opts->sockname);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   378
30620
937c52f06709 chg: start server at a unique address
Jun Wu <quark@fb.com>
parents: 30513
diff changeset
   379
	debugmsg("start cmdserver at %s", opts->initsockname);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   380
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   381
	pid_t pid = fork();
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   382
	if (pid < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   383
		abortmsg("failed to fork cmdserver process");
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   384
	if (pid == 0) {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   385
		execcmdserver(opts);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   386
	} else {
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   387
		hgc = retryconnectcmdserver(opts, pid);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   388
	}
28196
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   389
87de4a22e8c2 chg: hold a lock file before connected to server
Jun Wu <quark@fb.com>
parents: 28194
diff changeset
   390
	return hgc;
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   391
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   392
28455
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   393
static void killcmdserver(const struct cmdserveropts *opts)
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   394
{
28455
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   395
	/* resolve config hash */
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   396
	char *resolvedpath = realpath(opts->sockname, NULL);
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   397
	if (resolvedpath) {
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   398
		unlink(resolvedpath);
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   399
		free(resolvedpath);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   400
	}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   401
}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   402
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   403
/* Run instructions sent from the server like unlink and set redirect path
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   404
 * Return 1 if reconnect is needed, otherwise 0 */
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   405
static int runinstructions(struct cmdserveropts *opts, const char **insts)
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   406
{
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   407
	int needreconnect = 0;
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   408
	if (!insts)
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   409
		return needreconnect;
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   410
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   411
	assert(insts);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   412
	opts->redirectsockname[0] = '\0';
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   413
	const char **pinst;
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   414
	for (pinst = insts; *pinst; pinst++) {
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   415
		debugmsg("instruction: %s", *pinst);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   416
		if (strncmp(*pinst, "unlink ", 7) == 0) {
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   417
			unlink(*pinst + 7);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   418
		} else if (strncmp(*pinst, "redirect ", 9) == 0) {
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   419
			int r = snprintf(opts->redirectsockname,
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   420
			                 sizeof(opts->redirectsockname), "%s",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   421
			                 *pinst + 9);
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   422
			if (r < 0 || r >= (int)sizeof(opts->redirectsockname))
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   423
				abortmsg("redirect path is too long (%d)", r);
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   424
			needreconnect = 1;
28516
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28477
diff changeset
   425
		} else if (strncmp(*pinst, "exit ", 5) == 0) {
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28477
diff changeset
   426
			int n = 0;
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28477
diff changeset
   427
			if (sscanf(*pinst + 5, "%d", &n) != 1)
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28477
diff changeset
   428
				abortmsg("cannot read the exit code");
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28477
diff changeset
   429
			exit(n);
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   430
		} else if (strcmp(*pinst, "reconnect") == 0) {
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   431
			needreconnect = 1;
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   432
		} else {
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   433
			abortmsg("unknown instruction: %s", *pinst);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   434
		}
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   435
	}
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   436
	return needreconnect;
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   437
}
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   438
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   439
/*
45520
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   440
 * Test whether the command and the environment is unsupported or not.
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   441
 *
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   442
 * If any of the stdio file descriptors are not present (rare, but some tools
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   443
 * might spawn new processes without stdio instead of redirecting them to the
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   444
 * null device), then mark it as not supported because attachio won't work
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   445
 * correctly.
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   446
 *
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   447
 * The command list is not designed to cover all cases. But it's fast, and does
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   448
 * not depend on the server.
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   449
 */
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   450
static int isunsupported(int argc, const char *argv[])
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   451
{
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   452
	enum { SERVE = 1,
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   453
	       DAEMON = 2,
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   454
	       SERVEDAEMON = SERVE | DAEMON,
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   455
	};
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   456
	unsigned int state = 0;
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   457
	int i;
45520
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   458
	/* use fcntl to test missing stdio fds */
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   459
	if (fcntl(STDIN_FILENO, F_GETFD) == -1 ||
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   460
	    fcntl(STDOUT_FILENO, F_GETFD) == -1 ||
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   461
	    fcntl(STDERR_FILENO, F_GETFD) == -1) {
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   462
		debugmsg("stdio fds are missing");
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   463
		return 1;
5eee6f4f3d0d chg: fallback to original hg if stdio fds are missing
Jun Wu <quark@fb.com>
parents: 44995
diff changeset
   464
	}
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   465
	for (i = 0; i < argc; ++i) {
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   466
		if (strcmp(argv[i], "--") == 0)
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   467
			break;
44617
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   468
		/*
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   469
		 * there can be false positives but no false negative
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   470
		 * we cannot assume `serve` will always be first argument
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   471
		 * because global options can be passed before the command name
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   472
		 */
1e459ac4cb48 chg: be stricter about checking invocation of `serve` command
Pulkit Goyal <7895pulkit@gmail.com>
parents: 44261
diff changeset
   473
		if (strcmp("serve", argv[i]) == 0)
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   474
			state |= SERVE;
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   475
		else if (strcmp("-d", argv[i]) == 0 ||
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   476
		         strcmp("--daemon", argv[i]) == 0)
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   477
			state |= DAEMON;
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   478
	}
34531
50788d1ae6cc chg: just forward --time to command server
Yuya Nishihara <yuya@tcha.org>
parents: 31890
diff changeset
   479
	return (state & SERVEDAEMON) == SERVEDAEMON;
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   480
}
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   481
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   482
static void execoriginalhg(const char *argv[])
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   483
{
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   484
	debugmsg("execute original hg");
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   485
	if (execvp(gethgcmd(), (char **)argv) < 0)
28789
7f6e0a15189b chg: replace abortmsg showing errno with abortmsgerrno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
   486
		abortmsgerrno("failed to exec original hg");
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   487
}
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   488
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   489
int main(int argc, const char *argv[], const char *envp[])
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   490
{
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   491
	if (getenv("CHGDEBUG"))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   492
		enabledebugmsg();
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   493
28787
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28769
diff changeset
   494
	if (!getenv("HGPLAIN") && isatty(fileno(stderr)))
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28769
diff changeset
   495
		enablecolor();
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28769
diff changeset
   496
28261
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28260
diff changeset
   497
	if (getenv("CHGINTERNALMARK"))
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28260
diff changeset
   498
		abortmsg("chg started by chg detected.\n"
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   499
		         "Please make sure ${HG:-hg} is not a symlink or "
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   500
		         "wrapper to chg. Alternatively, set $CHGHG to the "
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   501
		         "path of real hg.");
28261
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28260
diff changeset
   502
28260
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   503
	if (isunsupported(argc - 1, argv + 1))
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   504
		execoriginalhg(argv);
0a17cfbe5429 chg: fallback to original hg for some unsupported commands or flags
Jun Wu <quark@fb.com>
parents: 28237
diff changeset
   505
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   506
	struct cmdserveropts opts;
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   507
	initcmdserveropts(&opts);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   508
	setcmdserveropts(&opts);
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   509
	setcmdserverargs(&opts, argc, argv);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   510
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   511
	if (argc == 2) {
28455
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   512
		if (strcmp(argv[1], "--kill-chg-daemon") == 0) {
412ee35a8005 chg: do not write pidfile
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
   513
			killcmdserver(&opts);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   514
			return 0;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   515
		}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   516
	}
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   517
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   518
	hgclient_t *hgc;
28358
ffd3ac07b1d7 chg: limit reconnect attempts
Jun Wu <quark@fb.com>
parents: 28357
diff changeset
   519
	size_t retry = 0;
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   520
	while (1) {
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   521
		hgc = connectcmdserver(&opts);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   522
		if (!hgc)
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   523
			abortmsg("cannot open hg client");
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   524
		hgc_setenv(hgc, envp);
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   525
		const char **insts = hgc_validate(hgc, argv + 1, argc - 1);
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   526
		int needreconnect = runinstructions(&opts, insts);
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   527
		free(insts);
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   528
		if (!needreconnect)
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   529
			break;
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   530
		hgc_close(hgc);
28358
ffd3ac07b1d7 chg: limit reconnect attempts
Jun Wu <quark@fb.com>
parents: 28357
diff changeset
   531
		if (++retry > 10)
ffd3ac07b1d7 chg: limit reconnect attempts
Jun Wu <quark@fb.com>
parents: 28357
diff changeset
   532
			abortmsg("too many redirections.\n"
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   533
			         "Please make sure %s is not a wrapper which "
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   534
			         "changes sensitive environment variables "
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   535
			         "before executing hg. If you have to use a "
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   536
			         "wrapper, wrap chg instead of hg.",
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34531
diff changeset
   537
			         gethgcmd());
28357
2f0f352d4196 chg: use validate to make sure the server is up to date
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   538
	}
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   539
30690
e9ec42634ec8 chg: decouple hgclient from setupsignalhandler
Jun Wu <quark@fb.com>
parents: 30689
diff changeset
   540
	setupsignalhandler(hgc_peerpid(hgc), hgc_peerpgid(hgc));
31890
ca7af5d15b21 chg: always wait for pager
Jun Wu <quark@fb.com>
parents: 30884
diff changeset
   541
	atexit(waitpager);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   542
	int exitcode = hgc_runcommand(hgc, argv + 1, argc - 1);
29369
85a18f3c0bdd chg: reset signal handlers to default before waiting pager
Yuya Nishihara <yuya@tcha.org>
parents: 29357
diff changeset
   543
	restoresignalhandler();
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   544
	hgc_close(hgc);
28167
66f6dad20c19 chg: pass sensitive command line flags to server
Jun Wu <quark@fb.com>
parents: 28086
diff changeset
   545
	freecmdserveropts(&opts);
29344
bb3d5c20eaf6 chg: exec pager in child process
Jun Wu <quark@fb.com>
parents: 29016
diff changeset
   546
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   547
	return exitcode;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   548
}