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 claritymaint
commit
9d8cce051a
|
@ -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
|
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
|
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
|
advertise the agent capability). The `X` and `Y` strings may contain any
|
||||||
printable ASCII characters except space (i.e., the byte range 32 < x <
|
printable ASCII characters except space (i.e., the byte range 33 <= x <=
|
||||||
127), and are typically of the form "package/version" (e.g.,
|
126), and are typically of the form "package/version-os" (e.g.,
|
||||||
"git/1.8.3.1"). The agent strings are purely informative for statistics
|
"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
|
and debugging purposes, and MUST NOT be used to programmatically assume
|
||||||
the presence or absence of particular features.
|
the presence or absence of particular features.
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
#include "diagnose.h"
|
#include "diagnose.h"
|
||||||
#include "object-file.h"
|
#include "object-file.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
static void get_system_info(struct strbuf *sys_info)
|
static void get_system_info(struct strbuf *sys_info)
|
||||||
{
|
{
|
||||||
struct utsname uname_info;
|
|
||||||
char *shell = NULL;
|
char *shell = NULL;
|
||||||
|
|
||||||
/* get git version from native cmd */
|
/* 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 */
|
/* system call for other version info */
|
||||||
strbuf_addstr(sys_info, "uname: ");
|
strbuf_addstr(sys_info, "uname: ");
|
||||||
if (uname(&uname_info))
|
get_uname_info(sys_info, 1);
|
||||||
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);
|
|
||||||
|
|
||||||
strbuf_addstr(sys_info, _("compiler info: "));
|
strbuf_addstr(sys_info, _("compiler info: "));
|
||||||
get_compiler_info(sys_info);
|
get_compiler_info(sys_info);
|
||||||
|
|
|
@ -624,7 +624,7 @@ const char *parse_feature_value(const char *feature_list, const char *feature, s
|
||||||
*offset = found + len - orig_start;
|
*offset = found + len - orig_start;
|
||||||
return value;
|
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 == '=') {
|
else if (*value == '=') {
|
||||||
size_t end;
|
size_t end;
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,40 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||||
|
|
||||||
. ./test-lib.sh
|
. ./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 &&
|
test_oid_cache <<-EOF &&
|
||||||
wrong_algo sha1:sha256
|
wrong_algo sha1:sha256
|
||||||
wrong_algo sha256:sha1
|
wrong_algo sha256:sha1
|
||||||
EOF
|
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 &&
|
cat >expect.base <<-EOF &&
|
||||||
version 2
|
version 2
|
||||||
agent=git/$(git version | cut -d" " -f3)
|
$(cat agent_capability)
|
||||||
ls-refs=unborn
|
ls-refs=unborn
|
||||||
fetch=shallow wait-for-done
|
fetch=shallow wait-for-done
|
||||||
server-option
|
server-option
|
||||||
object-format=$(test_oid algo)
|
object-format=$(test_oid algo)
|
||||||
EOF
|
EOF
|
||||||
cat >expect.trailer <<-EOF &&
|
cat >expect.trailer <<-EOF
|
||||||
0000
|
0000
|
||||||
EOF
|
EOF
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'test capability advertisement' '
|
||||||
cat expect.base expect.trailer >expect &&
|
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 \
|
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
|
||||||
--advertise-capabilities >out &&
|
--advertise-capabilities >out &&
|
||||||
test-tool pkt-line unpack <out >actual &&
|
test-tool pkt-line unpack <out >actual &&
|
||||||
|
@ -355,6 +371,10 @@ test_expect_success 'test capability advertisement with uploadpack.advertiseBund
|
||||||
expect.extra \
|
expect.extra \
|
||||||
expect.trailer >expect &&
|
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 \
|
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
|
||||||
--advertise-capabilities >out &&
|
--advertise-capabilities >out &&
|
||||||
test-tool pkt-line unpack <out >actual &&
|
test-tool pkt-line unpack <out >actual &&
|
||||||
|
|
|
@ -2043,3 +2043,11 @@ test_trailing_hash () {
|
||||||
test-tool hexdump |
|
test-tool hexdump |
|
||||||
sed "s/ //g"
|
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]" "."
|
||||||
|
}
|
||||||
|
|
69
version.c
69
version.c
|
@ -1,6 +1,9 @@
|
||||||
|
#define USE_THE_REPOSITORY_VARIABLE
|
||||||
|
|
||||||
#include "git-compat-util.h"
|
#include "git-compat-util.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
#include "gettext.h"
|
||||||
|
|
||||||
#ifndef GIT_VERSION_H
|
#ifndef GIT_VERSION_H
|
||||||
# include "version-def.h"
|
# include "version-def.h"
|
||||||
|
@ -11,6 +14,19 @@
|
||||||
const char git_version_string[] = GIT_VERSION;
|
const char git_version_string[] = GIT_VERSION;
|
||||||
const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
|
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)
|
const char *git_user_agent(void)
|
||||||
{
|
{
|
||||||
static const char *agent = NULL;
|
static const char *agent = NULL;
|
||||||
|
@ -24,6 +40,27 @@ const char *git_user_agent(void)
|
||||||
return agent;
|
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)
|
const char *git_user_agent_sanitized(void)
|
||||||
{
|
{
|
||||||
static const char *agent = NULL;
|
static const char *agent = NULL;
|
||||||
|
@ -32,13 +69,35 @@ const char *git_user_agent_sanitized(void)
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_addstr(&buf, git_user_agent());
|
strbuf_addstr(&buf, git_user_agent());
|
||||||
strbuf_trim(&buf);
|
|
||||||
for (size_t i = 0; i < buf.len; i++) {
|
if (!getenv("GIT_USER_AGENT")) {
|
||||||
if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
|
strbuf_addch(&buf, '-');
|
||||||
buf.buf[i] = '.';
|
strbuf_addstr(&buf, os_info());
|
||||||
}
|
}
|
||||||
agent = buf.buf;
|
redact_non_printables(&buf);
|
||||||
|
agent = strbuf_detach(&buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return agent;
|
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;
|
||||||
|
}
|
||||||
|
|
10
version.h
10
version.h
|
@ -1,10 +1,20 @@
|
||||||
#ifndef VERSION_H
|
#ifndef VERSION_H
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
|
struct repository;
|
||||||
|
|
||||||
extern const char git_version_string[];
|
extern const char git_version_string[];
|
||||||
extern const char git_built_from_commit_string[];
|
extern const char git_built_from_commit_string[];
|
||||||
|
|
||||||
const char *git_user_agent(void);
|
const char *git_user_agent(void);
|
||||||
const char *git_user_agent_sanitized(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 */
|
#endif /* VERSION_H */
|
||||||
|
|
Loading…
Reference in New Issue