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",
79 if (len && buf[len-1] == '\n')
84 static void add_domainname(char *buf, size_t len)
88 const char *domainname;
90 if (gethostname(buf, len)) {
91 warning("cannot get host name: %s", strerror(errno));
92 strlcpy(buf, "(none)", len);
95 namelen = strlen(buf);
96 if (memchr(buf, '.', namelen))
99 he = gethostbyname(buf);
100 buf[namelen++] = '.';
103 if (he && (domainname = strchr(he->h_name, '.')))
104 strlcpy(buf, domainname + 1, len);
106 strlcpy(buf, "(none)", len);
109 static void copy_email(const struct passwd *pw)
112 * Make up a fake email address
113 * (name + '@' + hostname [+ '.' + domainname])
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++] = '@';
121 if (!add_mailname_host(git_default_email + len,
122 sizeof(git_default_email) - len))
123 return; /* read from "/etc/mailname" (Debian) */
124 add_domainname(git_default_email + len,
125 sizeof(git_default_email) - len);
128 const char *ident_default_name(void)
130 if (!git_default_name[0]) {
131 struct passwd *pw = getpwuid(getuid());
133 die("You don't exist. Go away!");
134 copy_gecos(pw, git_default_name, sizeof(git_default_name));
136 return git_default_name;
139 const char *ident_default_email(void)
141 if (!git_default_email[0]) {
142 const char *email = getenv("EMAIL");
144 if (email && email[0]) {
145 strlcpy(git_default_email, email,
146 sizeof(git_default_email));
147 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
149 struct passwd *pw = getpwuid(getuid());
151 die("You don't exist. Go away!");
155 return git_default_email;
158 const char *ident_default_date(void)
160 if (!git_default_date[0])
161 datestamp(git_default_date, sizeof(git_default_date));
162 return git_default_date;
165 static int add_raw(char *buf, size_t size, int offset, const char *str)
167 size_t len = strlen(str);
168 if (offset + len > size)
170 memcpy(buf + offset, str, len);
174 static int crud(unsigned char c)
189 * Copy over a string to the destination, but avoid special
190 * characters ('\n', '<' and '>') and remove crud at the end
192 static int copy(char *buf, size_t size, int offset, const char *src)
197 /* Remove crud from the beginning.. */
198 while ((c = *src) != 0) {
204 /* Remove crud from the end.. */
214 * Copy the rest to the buffer, but avoid the special
215 * characters '\n' '<' and '>' that act as delimiters on
216 * an identification line
218 for (i = 0; i < len; i++) {
221 case '\n': case '<': case '>':
232 * Reverse of fmt_ident(); given an ident line, split the fields
233 * to allow the caller to parse it.
234 * Signal a success by returning 0, but date/tz fields of the result
235 * can still be NULL if the input line only has the name/email part
236 * (e.g. reading from a reflog entry).
238 int split_ident_line(struct ident_split *split, const char *line, int len)
244 memset(split, 0, sizeof(*split));
246 split->name_begin = line;
247 for (cp = line; *cp && cp < line + len; cp++)
249 split->mail_begin = cp + 1;
252 if (!split->mail_begin)
255 for (cp = split->mail_begin - 2; line < cp; cp--)
257 split->name_end = cp + 1;
260 if (!split->name_end)
263 for (cp = split->mail_begin; cp < line + len; cp++)
265 split->mail_end = cp;
268 if (!split->mail_end)
271 for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
273 if (line + len <= cp)
275 split->date_begin = cp;
276 span = strspn(cp, "0123456789");
279 split->date_end = split->date_begin + span;
280 for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
282 if (line + len <= cp || (*cp != '+' && *cp != '-'))
284 split->tz_begin = cp;
285 span = strspn(cp + 1, "0123456789");
288 split->tz_end = split->tz_begin + 1 + span;
292 split->date_begin = NULL;
293 split->date_end = NULL;
294 split->tz_begin = NULL;
295 split->tz_end = NULL;
299 static const char *env_hint =
301 "*** Please tell me who you are.\n"
305 " git config --global user.email \"you@example.com\"\n"
306 " git config --global user.name \"Your Name\"\n"
308 "to set your account\'s default identity.\n"
309 "Omit --global to set the identity only in this repository.\n"
312 const char *fmt_ident(const char *name, const char *email,
313 const char *date_str, int flag)
315 static char buffer[1000];
318 int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME);
319 int name_addr_only = (flag & IDENT_NO_DATE);
322 name = ident_default_name();
324 email = ident_default_email();
329 if (error_on_no_name) {
330 if (name == git_default_name)
331 fputs(env_hint, stderr);
332 die("empty ident %s <%s> not allowed", name, email);
334 pw = getpwuid(getuid());
336 die("You don't exist. Go away!");
340 strcpy(date, ident_default_date());
341 if (!name_addr_only && date_str && date_str[0]) {
342 if (parse_date(date_str, date, sizeof(date)) < 0)
343 die("invalid date format: %s", date_str);
346 i = copy(buffer, sizeof(buffer), 0, name);
347 i = add_raw(buffer, sizeof(buffer), i, " <");
348 i = copy(buffer, sizeof(buffer), i, email);
349 if (!name_addr_only) {
350 i = add_raw(buffer, sizeof(buffer), i, "> ");
351 i = copy(buffer, sizeof(buffer), i, date);
353 i = add_raw(buffer, sizeof(buffer), i, ">");
355 if (i >= sizeof(buffer))
356 die("Impossibly long personal identifier");
361 const char *fmt_name(const char *name, const char *email)
363 return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE);
366 const char *git_author_info(int flag)
368 return fmt_ident(getenv("GIT_AUTHOR_NAME"),
369 getenv("GIT_AUTHOR_EMAIL"),
370 getenv("GIT_AUTHOR_DATE"),
374 const char *git_committer_info(int flag)
376 if (getenv("GIT_COMMITTER_NAME"))
377 user_ident_explicitly_given |= IDENT_NAME_GIVEN;
378 if (getenv("GIT_COMMITTER_EMAIL"))
379 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
380 return fmt_ident(getenv("GIT_COMMITTER_NAME"),
381 getenv("GIT_COMMITTER_EMAIL"),
382 getenv("GIT_COMMITTER_DATE"),
386 int user_ident_sufficiently_given(void)
389 return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
391 return (user_ident_explicitly_given == IDENT_ALL_GIVEN);
395 int git_ident_config(const char *var, const char *value, void *data)
397 if (!strcmp(var, "user.name")) {
399 return config_error_nonbool(var);
400 strlcpy(git_default_name, value, sizeof(git_default_name));
401 user_ident_explicitly_given |= IDENT_NAME_GIVEN;
405 if (!strcmp(var, "user.email")) {
407 return config_error_nonbool(var);
408 strlcpy(git_default_email, value, sizeof(git_default_email));
409 user_ident_explicitly_given |= IDENT_MAIL_GIVEN;