drop length limitations on gecos-derived names and emails

When we pull the user's name from the GECOS field of the passwd file (or generate an email address based on their username and hostname), we put the result into a static buffer. While it's extremely unlikely that anybody ever hit these limits (after all, in such a case their parents must have hated them), we still had to deal with the error cases in our code. Converting these static buffers to strbufs lets us simplify the code and drop some error messages from the documentation that have confused some users. The conversion is mostly mechanical: replace string copies with strbuf equivalents, and access the strbuf.buf directly. There are a few exceptions: - copy_gecos and copy_email are the big winners in code reduction (since they no longer have to manage the string length manually) - git_ident_config wants to replace old versions of the default name (e.g., if we read the config multiple times), so it must reset+add to the strbuf instead of just adding Note that there is still one length limitation: the gethostname interface requires us to provide a static buffer, so we arbitrarily choose 1024 bytes for the hostname. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 21, 2012 at 19:10 UTC 8587ead78ad3d2af760270b21035ffe48fde3e7b
3 files changed +39 -73
Documentation/git-commit-tree.txt
-4
@@ -92,10 +92,6 @@ Diagnostics
92 -----------
93 You don't exist. Go away!::
94 The passwd(5) gecos field couldn't be read
95 -Your parents must have hated you!::
96 - The passwd(5) gecos field is longer than a giant static buffer.
97 -Your sysadmin must hate you!::
98 - The passwd(5) name field is longer than a giant static buffer.
95
96 Discussion
97 ----------
Documentation/git-var.txt
-4
@@ -63,10 +63,6 @@ Diagnostics
63 -----------
64 You don't exist. Go away!::
65 The passwd(5) gecos field couldn't be read
66 -Your parents must have hated you!::
67 - The passwd(5) gecos field is longer than a giant static buffer.
68 -Your sysadmin must hate you!::
69 - The passwd(5) name field is longer than a giant static buffer.
66
67 SEE ALSO
68 --------
ident.c
+39 -65
@@ -7,9 +7,8 @@
7 */
8 #include "cache.h"
9
10 -#define MAX_GITNAME (1000)
11 -static char git_default_name[MAX_GITNAME];
12 -static char git_default_email[MAX_GITNAME];
10 +static struct strbuf git_default_name = STRBUF_INIT;
11 +static struct strbuf git_default_email = STRBUF_INIT;
12 static char git_default_date[50];
13 int user_ident_explicitly_given;
14
@@ -19,42 +18,27 @@ int user_ident_explicitly_given;
18 #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
19 #endif
20
22 -static void copy_gecos(const struct passwd *w, char *name, size_t sz)
21 +static void copy_gecos(const struct passwd *w, struct strbuf *name)
22 {
24 - char *src, *dst;
25 - size_t len, nlen;
26 -
27 - nlen = strlen(w->pw_name);
23 + char *src;
24
25 /* Traditionally GECOS field had office phone numbers etc, separated
26 * with commas. Also & stands for capitalized form of the login name.
27 */
28
33 - for (len = 0, dst = name, src = get_gecos(w); len < sz; src++) {
29 + for (src = get_gecos(w); *src && *src != ','; src++) {
30 int ch = *src;
35 - if (ch != '&') {
36 - *dst++ = ch;
37 - if (ch == 0 || ch == ',')
38 - break;
39 - len++;
40 - continue;
41 - }
42 - if (len + nlen < sz) {
31 + if (ch != '&')
32 + strbuf_addch(name, ch);
33 + else {
34 /* Sorry, Mr. McDonald... */
44 - *dst++ = toupper(*w->pw_name);
45 - memcpy(dst, w->pw_name + 1, nlen - 1);
46 - dst += nlen - 1;
47 - len += nlen;
35 + strbuf_addch(name, toupper(*w->pw_name));
36 + strbuf_addstr(name, w->pw_name + 1);
37 }
38 }
50 - if (len < sz)
51 - name[len] = 0;
52 - else
53 - die("Your parents must have hated you!");
54 -
39 }
40
57 -static int add_mailname_host(char *buf, size_t len)
41 +static int add_mailname_host(struct strbuf *buf)
42 {
43 FILE *mailname;
44
@@ -65,7 +49,7 @@ static int add_mailname_host(char *buf, size_t len)
49 strerror(errno));
50 return -1;
51 }
68 - if (!fgets(buf, len, mailname)) {
52 + if (strbuf_getline(buf, mailname, '\n') == EOF) {
53 if (ferror(mailname))
54 warning("cannot read /etc/mailname: %s",
55 strerror(errno));
@@ -74,85 +58,73 @@ static int add_mailname_host(char *buf, size_t len)
58 }
59 /* success! */
60 fclose(mailname);
77 -
78 - len = strlen(buf);
79 - if (len && buf[len-1] == '\n')
80 - buf[len-1] = '\0';
61 return 0;
62 }
63
84 -static void add_domainname(char *buf, size_t len)
64 +static void add_domainname(struct strbuf *out)
65 {
66 + char buf[1024];
67 struct hostent *he;
87 - size_t namelen;
68 const char *domainname;
69
90 - if (gethostname(buf, len)) {
70 + if (gethostname(buf, sizeof(buf))) {
71 warning("cannot get host name: %s", strerror(errno));
92 - strlcpy(buf, "(none)", len);
72 + strbuf_addstr(out, "(none)");
73 return;
74 }
95 - namelen = strlen(buf);
96 - if (memchr(buf, '.', namelen))
75 + strbuf_addstr(out, buf);
76 + if (strchr(buf, '.'))
77 return;
78
79 he = gethostbyname(buf);
100 - buf[namelen++] = '.';
101 - buf += namelen;
102 - len -= namelen;
80 + strbuf_addch(out, '.');
81 if (he && (domainname = strchr(he->h_name, '.')))
104 - strlcpy(buf, domainname + 1, len);
82 + strbuf_addstr(out, domainname + 1);
83 else
106 - strlcpy(buf, "(none)", len);
84 + strbuf_addstr(out, "(none)");
85 }
86
109 -static void copy_email(const struct passwd *pw)
87 +static void copy_email(const struct passwd *pw, struct strbuf *email)
88 {
89 /*
90 * Make up a fake email address
91 * (name + '@' + hostname [+ '.' + domainname])
92 */
115 - size_t len = strlen(pw->pw_name);
116 - if (len > sizeof(git_default_email)/2)
117 - die("Your sysadmin must hate you!");
118 - memcpy(git_default_email, pw->pw_name, len);
119 - git_default_email[len++] = '@';
120 -
121 - if (!add_mailname_host(git_default_email + len,
122 - sizeof(git_default_email) - len))
93 + strbuf_addstr(email, pw->pw_name);
94 + strbuf_addch(email, '@');
95 +
96 + if (!add_mailname_host(email))
97 return; /* read from "/etc/mailname" (Debian) */
124 - add_domainname(git_default_email + len,
125 - sizeof(git_default_email) - len);
98 + add_domainname(email);
99 }
100
101 const char *ident_default_name(void)
102 {
130 - if (!git_default_name[0]) {
103 + if (!git_default_name.len) {
104 struct passwd *pw = getpwuid(getuid());
105 if (!pw)
106 die("You don't exist. Go away!");
134 - copy_gecos(pw, git_default_name, sizeof(git_default_name));
107 + copy_gecos(pw, &git_default_name);
108 }
136 - return git_default_name;
109 + return git_default_name.buf;
110 }
111
112 const char *ident_default_email(void)
113 {
141 - if (!git_default_email[0]) {
114 + if (!git_default_email.len) {
115 const char *email = getenv("EMAIL");
116
117 if (email && email[0]) {
145 - strlcpy(git_default_email, email,
146 - sizeof(git_default_email));
118 + strbuf_addstr(&git_default_email, email);
119 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
120 } else {
121 struct passwd *pw = getpwuid(getuid());
122 if (!pw)
123 die("You don't exist. Go away!");
152 - copy_email(pw);
124 + copy_email(pw, &git_default_email);
125 }
126 }
155 - return git_default_email;
127 + return git_default_email.buf;
128 }
129
130 const char *ident_default_date(void)
@@ -327,7 +299,7 @@ const char *fmt_ident(const char *name, const char *email,
299 struct passwd *pw;
300
301 if (error_on_no_name) {
330 - if (name == git_default_name)
302 + if (name == git_default_name.buf)
303 fputs(env_hint, stderr);
304 die("empty ident %s <%s> not allowed", name, email);
305 }
@@ -397,7 +369,8 @@ int git_ident_config(const char *var, const char *value, void *data)
369 if (!strcmp(var, "user.name")) {
370 if (!value)
371 return config_error_nonbool(var);
400 - strlcpy(git_default_name, value, sizeof(git_default_name));
372 + strbuf_reset(&git_default_name);
373 + strbuf_addstr(&git_default_name, value);
374 user_ident_explicitly_given |= IDENT_NAME_GIVEN;
375 return 0;
376 }
@@ -405,7 +378,8 @@ int git_ident_config(const char *var, const char *value, void *data)
378 if (!strcmp(var, "user.email")) {
379 if (!value)
380 return config_error_nonbool(var);
408 - strlcpy(git_default_email, value, sizeof(git_default_email));
381 + strbuf_reset(&git_default_email);
382 + strbuf_addstr(&git_default_email, value);
383 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
384 return 0;
385 }