ident: loosen getpwuid error in non-strict mode
authorJeff King <peff@peff.net>
Thu, 10 Dec 2015 21:41:29 +0000 (16:41 -0500)
committerJunio C Hamano <gitster@pobox.com>
Mon, 14 Dec 2015 19:44:38 +0000 (11:44 -0800)
If the user has not specified an identity and we have to
turn to getpwuid() to find the username or gecos field, we
die immediately when getpwuid fails (e.g., because the user
does not exist). This is OK for making a commit, where we
have set IDENT_STRICT and would want to bail on bogus input.

But for something like a reflog, where the ident is "best
effort", it can be pain. For instance, even running "git
clone" with a UID that is not in /etc/passwd will result in
git barfing, just because we can't find an ident to put in
the reflog.

Instead of dying in xgetpwuid_self, we can instead return a
fallback value, and set a "bogus" flag. For the username in
an email, we already have a "default_email_is_bogus" flag.
For the name field, we introduce (and check) a matching
"default_name_is_bogus" flag. As a bonus, this means you now
get the usual "tell me who you are" advice instead of just a
"no such user" error.

No tests, as this is dependent on configuration outside of
git's control. However, I did confirm that it behaves
sensibly when I delete myself from the local /etc/passwd
(reflogs get written, and commits complain).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
ident.c

diff --git a/ident.c b/ident.c
index 085cfbe..bb1b174 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -11,6 +11,7 @@ static struct strbuf git_default_name = STRBUF_INIT;
 static struct strbuf git_default_email = STRBUF_INIT;
 static struct strbuf git_default_date = STRBUF_INIT;
 static int default_email_is_bogus;
 static struct strbuf git_default_email = STRBUF_INIT;
 static struct strbuf git_default_date = STRBUF_INIT;
 static int default_email_is_bogus;
+static int default_name_is_bogus;
 
 #define IDENT_NAME_GIVEN 01
 #define IDENT_MAIL_GIVEN 02
 
 #define IDENT_NAME_GIVEN 01
 #define IDENT_MAIL_GIVEN 02
@@ -24,15 +25,22 @@ static int author_ident_explicitly_given;
 #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
 #endif
 
 #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
 #endif
 
-static struct passwd *xgetpwuid_self(void)
+static struct passwd *xgetpwuid_self(int *is_bogus)
 {
        struct passwd *pw;
 
        errno = 0;
        pw = getpwuid(getuid());
 {
        struct passwd *pw;
 
        errno = 0;
        pw = getpwuid(getuid());
-       if (!pw)
-               die(_("unable to look up current user in the passwd file: %s"),
-                   errno ? strerror(errno) : _("no such user"));
+       if (!pw) {
+               static struct passwd fallback;
+               fallback.pw_name = "unknown";
+#ifndef NO_GECOS_IN_PWENT
+               fallback.pw_gecos = "Unknown";
+#endif
+               pw = &fallback;
+               if (is_bogus)
+                       *is_bogus = 1;
+       }
        return pw;
 }
 
        return pw;
 }
 
@@ -122,7 +130,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email,
 const char *ident_default_name(void)
 {
        if (!git_default_name.len) {
 const char *ident_default_name(void)
 {
        if (!git_default_name.len) {
-               copy_gecos(xgetpwuid_self(), &git_default_name);
+               copy_gecos(xgetpwuid_self(&default_name_is_bogus), &git_default_name);
                strbuf_trim(&git_default_name);
        }
        return git_default_name.buf;
                strbuf_trim(&git_default_name);
        }
        return git_default_name.buf;
@@ -138,8 +146,8 @@ const char *ident_default_email(void)
                        committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                        author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                } else
                        committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                        author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                } else
-                       copy_email(xgetpwuid_self(), &git_default_email,
-                                  &default_email_is_bogus);
+                       copy_email(xgetpwuid_self(&default_email_is_bogus),
+                                  &git_default_email, &default_email_is_bogus);
                strbuf_trim(&git_default_email);
        }
        return git_default_email.buf;
                strbuf_trim(&git_default_email);
        }
        return git_default_email.buf;
@@ -327,10 +335,16 @@ const char *fmt_ident(const char *name, const char *email,
                                fputs(env_hint, stderr);
                        die("empty ident name (for <%s>) not allowed", email);
                }
                                fputs(env_hint, stderr);
                        die("empty ident name (for <%s>) not allowed", email);
                }
-               pw = xgetpwuid_self();
+               pw = xgetpwuid_self(NULL);
                name = pw->pw_name;
        }
 
                name = pw->pw_name;
        }
 
+       if (want_name && strict &&
+           name == git_default_name.buf && default_name_is_bogus) {
+               fputs(env_hint, stderr);
+               die("unable to auto-detect name (got '%s')", name);
+       }
+
        if (strict && email == git_default_email.buf && default_email_is_bogus) {
                fputs(env_hint, stderr);
                die("unable to auto-detect email address (got '%s')", email);
        if (strict && email == git_default_email.buf && default_email_is_bogus) {
                fputs(env_hint, stderr);
                die("unable to auto-detect email address (got '%s')", email);