aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2025-02-27 15:22:59 -0800
committerJunio C Hamano <gitster@pobox.com>2025-02-27 15:23:00 -0800
commit9d8cce051add2eb82cb0be97a58201c1d3fe0c1b (patch)
tree656c7d9a67e9233f2b3ecdae15a3461b49af783e
parentGit 2.49-rc0 (diff)
parentagent: advertise OS name via agent capability (diff)
downloadgit-9d8cce051add2eb82cb0be97a58201c1d3fe0c1b.tar.gz
git-9d8cce051add2eb82cb0be97a58201c1d3fe0c1b.zip
Merge branch 'ua/os-version-capability'
The value of "uname -s" is by default sent over the wire as a part of the "version" capability. * ua/os-version-capability: agent: advertise OS name via agent capability t5701: add setup test to remove side-effect dependency version: extend get_uname_info() to hide system details version: refactor get_uname_info() version: refactor redact_non_printables() version: replace manual ASCII checks with isprint() for clarity
-rw-r--r--Documentation/gitprotocol-v2.adoc10
-rw-r--r--builtin/bugreport.c13
-rw-r--r--connect.c2
-rwxr-xr-xt/t5701-git-serve.sh26
-rw-r--r--t/test-lib-functions.sh8
-rw-r--r--version.c69
-rw-r--r--version.h10
7 files changed, 115 insertions, 23 deletions
diff --git a/Documentation/gitprotocol-v2.adoc b/Documentation/gitprotocol-v2.adoc
index 1652fef3ae..9f6350bbf2 100644
--- a/Documentation/gitprotocol-v2.adoc
+++ b/Documentation/gitprotocol-v2.adoc
@@ -184,9 +184,13 @@ form `agent=X`) to notify the client that the server is running version
the `agent` capability with a value `Y` (in the form `agent=Y`) in its
request to the server (but it MUST NOT do so if the server did not
advertise the agent capability). The `X` and `Y` strings may contain any
-printable ASCII characters except space (i.e., the byte range 32 < x <
-127), and are typically of the form "package/version" (e.g.,
-"git/1.8.3.1"). The agent strings are purely informative for statistics
+printable ASCII characters except space (i.e., the byte range 33 <= x <=
+126), and are typically of the form "package/version-os" (e.g.,
+"git/1.8.3.1-Linux") where `os` is the operating system name (e.g.,
+"Linux"). `X` and `Y` can be configured using the GIT_USER_AGENT
+environment variable and it takes priority. The `os` is
+retrieved using the 'sysname' field of the `uname(2)` system call
+or its equivalent. The agent strings are purely informative for statistics
and debugging purposes, and MUST NOT be used to programmatically assume
the presence or absence of particular features.
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 0ac59cc8dc..66d64bfd5a 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -12,10 +12,10 @@
#include "diagnose.h"
#include "object-file.h"
#include "setup.h"
+#include "version.h"
static void get_system_info(struct strbuf *sys_info)
{
- struct utsname uname_info;
char *shell = NULL;
/* get git version from native cmd */
@@ -24,16 +24,7 @@ static void get_system_info(struct strbuf *sys_info)
/* system call for other version info */
strbuf_addstr(sys_info, "uname: ");
- if (uname(&uname_info))
- strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
- strerror(errno),
- errno);
- else
- strbuf_addf(sys_info, "%s %s %s %s\n",
- uname_info.sysname,
- uname_info.release,
- uname_info.version,
- uname_info.machine);
+ get_uname_info(sys_info, 1);
strbuf_addstr(sys_info, _("compiler info: "));
get_compiler_info(sys_info);
diff --git a/connect.c b/connect.c
index 91f3990014..e6e25a0479 100644
--- a/connect.c
+++ b/connect.c
@@ -624,7 +624,7 @@ const char *parse_feature_value(const char *feature_list, const char *feature, s
*offset = found + len - orig_start;
return value;
}
- /* feature with a value (e.g., "agent=git/1.2.3") */
+ /* feature with a value (e.g., "agent=git/1.2.3-Linux") */
else if (*value == '=') {
size_t end;
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index de904c1655..678a346ed0 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -7,24 +7,40 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
-test_expect_success 'test capability advertisement' '
+test_expect_success 'setup to generate files with expected content' '
+ printf "agent=git/%s" "$(git version | cut -d" " -f3)" >agent_capability &&
+
test_oid_cache <<-EOF &&
wrong_algo sha1:sha256
wrong_algo sha256:sha1
EOF
+
+ if test_have_prereq WINDOWS
+ then
+ printf "agent=FAKE\n" >agent_capability
+ else
+ printf -- "-%s\n" $(uname -s | test_redact_non_printables) >>agent_capability
+ fi &&
cat >expect.base <<-EOF &&
version 2
- agent=git/$(git version | cut -d" " -f3)
+ $(cat agent_capability)
ls-refs=unborn
fetch=shallow wait-for-done
server-option
object-format=$(test_oid algo)
EOF
- cat >expect.trailer <<-EOF &&
+ cat >expect.trailer <<-EOF
0000
EOF
+'
+
+test_expect_success 'test capability advertisement' '
cat expect.base expect.trailer >expect &&
+ if test_have_prereq WINDOWS
+ then
+ GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
+ fi &&
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
--advertise-capabilities >out &&
test-tool pkt-line unpack <out >actual &&
@@ -355,6 +371,10 @@ test_expect_success 'test capability advertisement with uploadpack.advertiseBund
expect.extra \
expect.trailer >expect &&
+ if test_have_prereq WINDOWS
+ then
+ GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
+ fi &&
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
--advertise-capabilities >out &&
test-tool pkt-line unpack <out >actual &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index b93736e0d5..79377bc0fc 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -2043,3 +2043,11 @@ test_trailing_hash () {
test-tool hexdump |
sed "s/ //g"
}
+
+# Trim and replace each character with ascii code below 32 or above
+# 127 (included) using a dot '.' character.
+# Octal intervals \001-\040 and \177-\377
+# correspond to decimal intervals 1-32 and 127-255
+test_redact_non_printables () {
+ tr -d "\n\r" | tr "[\001-\040][\177-\377]" "."
+}
diff --git a/version.c b/version.c
index 4786c4e0a5..279269cc50 100644
--- a/version.c
+++ b/version.c
@@ -1,6 +1,9 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "version.h"
#include "strbuf.h"
+#include "gettext.h"
#ifndef GIT_VERSION_H
# include "version-def.h"
@@ -11,6 +14,19 @@
const char git_version_string[] = GIT_VERSION;
const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
+/*
+ * Trim and replace each character with ascii code below 32 or above
+ * 127 (included) using a dot '.' character.
+ */
+static void redact_non_printables(struct strbuf *buf)
+{
+ strbuf_trim(buf);
+ for (size_t i = 0; i < buf->len; i++) {
+ if (!isprint(buf->buf[i]) || buf->buf[i] == ' ')
+ buf->buf[i] = '.';
+ }
+}
+
const char *git_user_agent(void)
{
static const char *agent = NULL;
@@ -24,6 +40,27 @@ const char *git_user_agent(void)
return agent;
}
+/*
+ Retrieve, sanitize and cache operating system info for subsequent
+ calls. Return a pointer to the sanitized operating system info
+ string.
+*/
+static const char *os_info(void)
+{
+ static const char *os = NULL;
+
+ if (!os) {
+ struct strbuf buf = STRBUF_INIT;
+
+ get_uname_info(&buf, 0);
+ /* Sanitize the os information immediately */
+ redact_non_printables(&buf);
+ os = strbuf_detach(&buf, NULL);
+ }
+
+ return os;
+}
+
const char *git_user_agent_sanitized(void)
{
static const char *agent = NULL;
@@ -32,13 +69,35 @@ const char *git_user_agent_sanitized(void)
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, git_user_agent());
- strbuf_trim(&buf);
- for (size_t i = 0; i < buf.len; i++) {
- if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
- buf.buf[i] = '.';
+
+ if (!getenv("GIT_USER_AGENT")) {
+ strbuf_addch(&buf, '-');
+ strbuf_addstr(&buf, os_info());
}
- agent = buf.buf;
+ redact_non_printables(&buf);
+ agent = strbuf_detach(&buf, NULL);
}
return agent;
}
+
+int get_uname_info(struct strbuf *buf, unsigned int full)
+{
+ struct utsname uname_info;
+
+ if (uname(&uname_info)) {
+ strbuf_addf(buf, _("uname() failed with error '%s' (%d)\n"),
+ strerror(errno),
+ errno);
+ return -1;
+ }
+ if (full)
+ strbuf_addf(buf, "%s %s %s %s\n",
+ uname_info.sysname,
+ uname_info.release,
+ uname_info.version,
+ uname_info.machine);
+ else
+ strbuf_addf(buf, "%s\n", uname_info.sysname);
+ return 0;
+}
diff --git a/version.h b/version.h
index 7c62e80577..bbde6d371a 100644
--- a/version.h
+++ b/version.h
@@ -1,10 +1,20 @@
#ifndef VERSION_H
#define VERSION_H
+struct repository;
+
extern const char git_version_string[];
extern const char git_built_from_commit_string[];
const char *git_user_agent(void);
const char *git_user_agent_sanitized(void);
+/*
+ Try to get information about the system using uname(2).
+ Return -1 and put an error message into 'buf' in case of uname()
+ error. Return 0 and put uname info into 'buf' otherwise.
+*/
+int get_uname_info(struct strbuf *buf, unsigned int full);
+
+
#endif /* VERSION_H */