4 * create git identifier lines of the form "name <email> date"
6 * Copyright (C) 2005 Linus Torvalds
10 #define MAX_GITNAME (1000)
11 static char git_default_name[MAX_GITNAME];
12 static char git_default_email[MAX_GITNAME];
13 static char git_default_date[50];
14 int user_ident_explicitly_given;
16 #ifdef NO_GECOS_IN_PWENT
17 #define get_gecos(ignored) "&"
19 #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
22 static void copy_gecos(const struct passwd *w, char *name, size_t sz)
27 nlen = strlen(w->pw_name);
29 /* Traditionally GECOS field had office phone numbers etc, separated
30 * with commas. Also & stands for capitalized form of the login name.
33 for (len = 0, dst = name, src = get_gecos(w); len < sz; src++) {
37 if (ch == 0 || ch == ',')
42 if (len + nlen < sz) {
43 /* Sorry, Mr. McDonald... */
44 *dst++ = toupper(*w->pw_name);
45 memcpy(dst, w->pw_name + 1, nlen - 1);
53 die("Your parents must have hated you!");
57 static int add_mailname_host(char *buf, size_t len)
61 mailname = fopen("/etc/mailname", "r");
64 warning("cannot open /etc/mailname: %s",
68 if (!fgets(buf, len, mailname)) {
70 warning("cannot read /etc/mailname: %s",
80 static void add_domainname(char *buf, size_t len)
84 const char *domainname;
86 if (gethostname(buf, len)) {
87 warning("cannot get host name: %s", strerror(errno));
88 strlcpy(buf, "(none)", len);
91 namelen = strlen(buf);
92 if (memchr(buf, '.', namelen))
95 he = gethostbyname(buf);
99 if (he && (domainname = strchr(he->h_name, '.')))
100 strlcpy(buf, domainname + 1, len);
102 strlcpy(buf, "(none)", len);
105 static void copy_email(const struct passwd *pw)
108 * Make up a fake email address
109 * (name + '@' + hostname [+ '.' + domainname])
111 size_t len = strlen(pw->pw_name);
112 if (len > sizeof(git_default_email)/2)
113 die("Your sysadmin must hate you!");
114 memcpy(git_default_email, pw->pw_name, len);
115 git_default_email[len++] = '@';
117 if (!add_mailname_host(git_default_email + len,
118 sizeof(git_default_email) - len))
119 return; /* read from "/etc/mailname" (Debian) */
120 add_domainname(git_default_email + len,
121 sizeof(git_default_email) - len);
124 const char *ident_default_name(void)
126 if (!git_default_name[0]) {
127 struct passwd *pw = getpwuid(getuid());
129 die("You don't exist. Go away!");
130 copy_gecos(pw, git_default_name, sizeof(git_default_name));
132 return git_default_name;
135 const char *ident_default_email(void)
137 if (!git_default_email[0]) {
138 const char *email = getenv("EMAIL");
140 if (email && email[0]) {
141 strlcpy(git_default_email, email,
142 sizeof(git_default_email));
143 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
145 struct passwd *pw = getpwuid(getuid());
147 die("You don't exist. Go away!");
151 return git_default_email;
154 const char *ident_default_date(void)
156 if (!git_default_date[0])
157 datestamp(git_default_date, sizeof(git_default_date));
158 return git_default_date;
161 static int add_raw(char *buf, size_t size, int offset, const char *str)
163 size_t len = strlen(str);
164 if (offset + len > size)
166 memcpy(buf + offset, str, len);
170 static int crud(unsigned char c)
185 * Copy over a string to the destination, but avoid special
186 * characters ('\n', '<' and '>') and remove crud at the end
188 static int copy(char *buf, size_t size, int offset, const char *src)
193 /* Remove crud from the beginning.. */
194 while ((c = *src) != 0) {
200 /* Remove crud from the end.. */
210 * Copy the rest to the buffer, but avoid the special
211 * characters '\n' '<' and '>' that act as delimiters on
212 * an identification line
214 for (i = 0; i < len; i++) {
217 case '\n': case '<': case '>':
228 * Reverse of fmt_ident(); given an ident line, split the fields
229 * to allow the caller to parse it.
230 * Signal a success by returning 0, but date/tz fields of the result
231 * can still be NULL if the input line only has the name/email part
232 * (e.g. reading from a reflog entry).
234 int split_ident_line(struct ident_split *split, const char *line, int len)
240 memset(split, 0, sizeof(*split));
242 split->name_begin = line;
243 for (cp = line; *cp && cp < line + len; cp++)
245 split->mail_begin = cp + 1;
248 if (!split->mail_begin)
251 for (cp = split->mail_begin - 2; line < cp; cp--)
253 split->name_end = cp + 1;
256 if (!split->name_end)
259 for (cp = split->mail_begin; cp < line + len; cp++)
261 split->mail_end = cp;
264 if (!split->mail_end)
267 for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
269 if (line + len <= cp)
271 split->date_begin = cp;
272 span = strspn(cp, "0123456789");
275 split->date_end = split->date_begin + span;
276 for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
278 if (line + len <= cp || (*cp != '+' && *cp != '-'))
280 split->tz_begin = cp;
281 span = strspn(cp + 1, "0123456789");
284 split->tz_end = split->tz_begin + 1 + span;
288 split->date_begin = NULL;
289 split->date_end = NULL;
290 split->tz_begin = NULL;
291 split->tz_end = NULL;
295 static const char *env_hint =
297 "*** Please tell me who you are.\n"
301 " git config --global user.email \"you@example.com\"\n"
302 " git config --global user.name \"Your Name\"\n"
304 "to set your account\'s default identity.\n"
305 "Omit --global to set the identity only in this repository.\n"
308 const char *fmt_ident(const char *name, const char *email,
309 const char *date_str, int flag)
311 static char buffer[1000];
314 int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME);
315 int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME);
316 int name_addr_only = (flag & IDENT_NO_DATE);
319 name = ident_default_name();
321 email = ident_default_email();
326 if ((warn_on_no_name || error_on_no_name) &&
327 name == git_default_name && env_hint) {
328 fputs(env_hint, stderr);
329 env_hint = NULL; /* warn only once */
331 if (error_on_no_name)
332 die("empty ident %s <%s> not allowed", name, email);
333 pw = getpwuid(getuid());
335 die("You don't exist. Go away!");
336 strlcpy(git_default_name, pw->pw_name,
337 sizeof(git_default_name));
338 name = git_default_name;
341 strcpy(date, ident_default_date());
342 if (!name_addr_only && date_str && date_str[0]) {
343 if (parse_date(date_str, date, sizeof(date)) < 0)
344 die("invalid date format: %s", date_str);
347 i = copy(buffer, sizeof(buffer), 0, name);
348 i = add_raw(buffer, sizeof(buffer), i, " <");
349 i = copy(buffer, sizeof(buffer), i, email);
350 if (!name_addr_only) {
351 i = add_raw(buffer, sizeof(buffer), i, "> ");
352 i = copy(buffer, sizeof(buffer), i, date);
354 i = add_raw(buffer, sizeof(buffer), i, ">");
356 if (i >= sizeof(buffer))
357 die("Impossibly long personal identifier");
362 const char *fmt_name(const char *name, const char *email)
364 return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE);
367 const char *git_author_info(int flag)
369 return fmt_ident(getenv("GIT_AUTHOR_NAME"),
370 getenv("GIT_AUTHOR_EMAIL"),
371 getenv("GIT_AUTHOR_DATE"),
375 const char *git_committer_info(int flag)
377 if (getenv("GIT_COMMITTER_NAME"))
378 user_ident_explicitly_given |= IDENT_NAME_GIVEN;
379 if (getenv("GIT_COMMITTER_EMAIL"))
380 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
381 return fmt_ident(getenv("GIT_COMMITTER_NAME"),
382 getenv("GIT_COMMITTER_EMAIL"),
383 getenv("GIT_COMMITTER_DATE"),
387 int user_ident_sufficiently_given(void)
390 return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
392 return (user_ident_explicitly_given == IDENT_ALL_GIVEN);
396 int git_ident_config(const char *var, const char *value, void *data)
398 if (!strcmp(var, "user.name")) {
400 return config_error_nonbool(var);
401 strlcpy(git_default_name, value, sizeof(git_default_name));
402 user_ident_explicitly_given |= IDENT_NAME_GIVEN;
406 if (!strcmp(var, "user.email")) {
408 return config_error_nonbool(var);
409 strlcpy(git_default_email, value, sizeof(git_default_email));
410 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;