[PATCH 10 of 14] chg: calculate sockdirfd

Jun Wu quark at fb.com
Sun Apr 10 19:57:27 EDT 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1460330280 -3600
#      Mon Apr 11 00:18:00 2016 +0100
# Node ID 1b8ee8aabe42b44cd865d41bf095c2cf7892e4dc
# Parent  68977496c0f5b4026c19cd8ec4ea22113401c030
chg: calculate sockdirfd

This is a part of the series to support long socket path. Before this patch,
sockdirfd is AT_FDCWD, making it effectively unused. This patch calculates
sockdirfd and makes sockname and lockfile basenames instead of full paths.

diff --git a/contrib/chg/chg.c b/contrib/chg/chg.c
--- a/contrib/chg/chg.c
+++ b/contrib/chg/chg.c
@@ -29,6 +29,10 @@
 #define UNIX_PATH_MAX (sizeof(((struct sockaddr_un *)NULL)->sun_path))
 #endif
 
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
 struct cmdserveropts {
 	char sockname[UNIX_PATH_MAX];
 	char redirectsockname[UNIX_PATH_MAX];
@@ -140,8 +144,9 @@
 static void setcmdserveropts(struct cmdserveropts *opts)
 {
 	int r;
-	char sockdir[UNIX_PATH_MAX];
+	char sockdir[PATH_MAX];
 	const char *envsockname = getenv("CHGSOCKNAME");
+	const char *basename = NULL;
 	if (!envsockname) {
 		/* by default, put socket file in secure directory
 		 * (permission of socket file may be ignored on some Unices) */
@@ -153,14 +158,38 @@
 		if (r < 0 || (size_t)r >= sizeof(sockdir))
 			abortmsg("too long TMPDIR (r = %d)", r);
 		preparesockdir(sockdir);
+		basename = "server";
+	} else {
+		/* otherwise, split the path the user provides */
+		const char *lastsep = strrchr(envsockname, '/');
+		if (lastsep) {
+			size_t len = lastsep - envsockname + 1;
+			if (len >= sizeof(sockdir))
+				abortmsg("CHGSOCKNAME is too long");
+			memcpy(sockdir, envsockname, len);
+			sockdir[len] = '\0';
+			basename = lastsep + 1;
+		} else {
+			r = snprintf(sockdir, sizeof(sockdir), ".");
+			assert(r == 2);
+			basename = envsockname;
+		}
 	}
 
-	const char *basename = (envsockname) ? envsockname : sockdir;
-	const char *sockfmt = (envsockname) ? "%s" : "%s/server";
-	const char *lockfmt = (envsockname) ? "%s.lock" : "%s/lock";
-	r = snprintf(opts->sockname, sizeof(opts->sockname), sockfmt, basename);
-	if (r < 0 || (size_t)r >= sizeof(opts->sockname))
-		abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);
+	if (basename[0] == '\0')
+		abortmsg("basename cannot be empty");
+
+	opts->sockdirfd = open(sockdir, O_DIRECTORY);
+	if (opts->sockdirfd == -1)
+		abortmsgerrno("failed to open dir %s", sockdir);
+	fsetcloexec(opts->sockdirfd);
+
+	opts->sockname[sizeof(opts->sockname) - 1] = '\0';
+	strncpy(opts->sockname, basename, sizeof(opts->sockname));
+	if (opts->sockname[sizeof(opts->sockname) - 1] != '\0')
+		abortmsg("basename %s is too long", basename);
+
+	static const char lockfmt[] = "%s.lock";
 	r = snprintf(opts->lockfile, sizeof(opts->lockfile), lockfmt, basename);
 	if (r < 0 || (size_t)r >= sizeof(opts->lockfile))
 		abortmsg("too long TMPDIR or CHGSOCKNAME (r = %d)", r);


More information about the Mercurial-devel mailing list