ident.c 10.8 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * ident.c
 *
 * create git identifier lines of the form "name <email> date"
 *
 * Copyright (C) 2005 Linus Torvalds
 */
#include "cache.h"

10 11
static struct strbuf git_default_name = STRBUF_INIT;
static struct strbuf git_default_email = STRBUF_INIT;
12
static struct strbuf git_default_date = STRBUF_INIT;
13 14 15 16

#define IDENT_NAME_GIVEN 01
#define IDENT_MAIL_GIVEN 02
#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
17 18
static int committer_ident_explicitly_given;
static int author_ident_explicitly_given;
19

20 21 22 23 24 25
#ifdef NO_GECOS_IN_PWENT
#define get_gecos(ignored) "&"
#else
#define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
#endif

26
static void copy_gecos(const struct passwd *w, struct strbuf *name)
27
{
28
	char *src;
29 30 31 32 33

	/* Traditionally GECOS field had office phone numbers etc, separated
	 * with commas.  Also & stands for capitalized form of the login name.
	 */

34
	for (src = get_gecos(w); *src && *src != ','; src++) {
35
		int ch = *src;
36 37 38
		if (ch != '&')
			strbuf_addch(name, ch);
		else {
39
			/* Sorry, Mr. McDonald... */
40 41
			strbuf_addch(name, toupper(*w->pw_name));
			strbuf_addstr(name, w->pw_name + 1);
42 43 44 45
		}
	}
}

46
static int add_mailname_host(struct strbuf *buf)
47 48
{
	FILE *mailname;
49
	struct strbuf mailnamebuf = STRBUF_INIT;
50 51 52 53 54 55 56 57

	mailname = fopen("/etc/mailname", "r");
	if (!mailname) {
		if (errno != ENOENT)
			warning("cannot open /etc/mailname: %s",
				strerror(errno));
		return -1;
	}
58
	if (strbuf_getline(&mailnamebuf, mailname, '\n') == EOF) {
59 60 61
		if (ferror(mailname))
			warning("cannot read /etc/mailname: %s",
				strerror(errno));
62
		strbuf_release(&mailnamebuf);
63 64 65 66
		fclose(mailname);
		return -1;
	}
	/* success! */
67 68
	strbuf_addbuf(buf, &mailnamebuf);
	strbuf_release(&mailnamebuf);
69 70 71 72
	fclose(mailname);
	return 0;
}

E
Elia Pinto 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
static int canonical_name(const char *host, struct strbuf *out)
{
	int status = -1;

#ifndef NO_IPV6
	struct addrinfo hints, *ai;
	memset (&hints, '\0', sizeof (hints));
	hints.ai_flags = AI_CANONNAME;
	if (!getaddrinfo(host, NULL, &hints, &ai)) {
		if (ai && strchr(ai->ai_canonname, '.')) {
			strbuf_addstr(out, ai->ai_canonname);
			status = 0;
		}
		freeaddrinfo(ai);
	}
#else
	struct hostent *he = gethostbyname(buf);
	if (he && strchr(he->h_name, '.')) {
		strbuf_addstr(out, he->h_name);
		status = 0;
	}
#endif /* NO_IPV6 */

	return status;
}

99
static void add_domainname(struct strbuf *out)
100
{
101
	char buf[1024];
102

103
	if (gethostname(buf, sizeof(buf))) {
104
		warning("cannot get host name: %s", strerror(errno));
105
		strbuf_addstr(out, "(none)");
106 107
		return;
	}
108
	if (strchr(buf, '.'))
109
		strbuf_addstr(out, buf);
E
Elia Pinto 已提交
110
	else if (canonical_name(buf, out) < 0)
111
		strbuf_addf(out, "%s.(none)", buf);
112 113
}

114
static void copy_email(const struct passwd *pw, struct strbuf *email)
115
{
116 117 118 119
	/*
	 * Make up a fake email address
	 * (name + '@' + hostname [+ '.' + domainname])
	 */
120 121 122 123
	strbuf_addstr(email, pw->pw_name);
	strbuf_addch(email, '@');

	if (!add_mailname_host(email))
124
		return;	/* read from "/etc/mailname" (Debian) */
125
	add_domainname(email);
126 127
}

128
const char *ident_default_name(void)
129
{
130
	if (!git_default_name.len) {
131
		copy_gecos(xgetpwuid_self(), &git_default_name);
132
		strbuf_trim(&git_default_name);
133
	}
134
	return git_default_name.buf;
135
}
136

137 138
const char *ident_default_email(void)
{
139
	if (!git_default_email.len) {
M
Matt Kraai 已提交
140 141
		const char *email = getenv("EMAIL");

142
		if (email && email[0]) {
143
			strbuf_addstr(&git_default_email, email);
144 145
			committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
			author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
146 147
		} else
			copy_email(xgetpwuid_self(), &git_default_email);
148
		strbuf_trim(&git_default_email);
149
	}
150
	return git_default_email.buf;
151 152
}

153
static const char *ident_default_date(void)
154
{
155 156 157
	if (!git_default_date.len)
		datestamp(&git_default_date);
	return git_default_date.buf;
158 159 160 161
}

static int crud(unsigned char c)
{
A
Alex Riesen 已提交
162 163 164 165 166 167 168 169
	return  c <= 32  ||
		c == '.' ||
		c == ',' ||
		c == ':' ||
		c == ';' ||
		c == '<' ||
		c == '>' ||
		c == '"' ||
170
		c == '\\' ||
A
Alex Riesen 已提交
171
		c == '\'';
172 173 174 175 176 177
}

/*
 * Copy over a string to the destination, but avoid special
 * characters ('\n', '<' and '>') and remove crud at the end
 */
178
static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src)
179
{
180
	size_t i, len;
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	unsigned char c;

	/* Remove crud from the beginning.. */
	while ((c = *src) != 0) {
		if (!crud(c))
			break;
		src++;
	}

	/* Remove crud from the end.. */
	len = strlen(src);
	while (len > 0) {
		c = src[len-1];
		if (!crud(c))
			break;
		--len;
	}

	/*
	 * Copy the rest to the buffer, but avoid the special
J
Junio C Hamano 已提交
201
	 * characters '\n' '<' and '>' that act as delimiters on
202 203
	 * an identification line. We can only remove crud, never add it,
	 * so 'len' is our maximum.
204
	 */
205
	strbuf_grow(sb, len);
206 207 208 209 210 211
	for (i = 0; i < len; i++) {
		c = *src++;
		switch (c) {
		case '\n': case '<': case '>':
			continue;
		}
212
		sb->buf[sb->len++] = c;
213
	}
214
	sb->buf[sb->len] = '\0';
215 216
}

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
/*
 * Reverse of fmt_ident(); given an ident line, split the fields
 * to allow the caller to parse it.
 * Signal a success by returning 0, but date/tz fields of the result
 * can still be NULL if the input line only has the name/email part
 * (e.g. reading from a reflog entry).
 */
int split_ident_line(struct ident_split *split, const char *line, int len)
{
	const char *cp;
	size_t span;
	int status = -1;

	memset(split, 0, sizeof(*split));

	split->name_begin = line;
	for (cp = line; *cp && cp < line + len; cp++)
		if (*cp == '<') {
			split->mail_begin = cp + 1;
			break;
		}
	if (!split->mail_begin)
		return status;

241
	for (cp = split->mail_begin - 2; line <= cp; cp--)
242 243 244 245
		if (!isspace(*cp)) {
			split->name_end = cp + 1;
			break;
		}
246 247 248 249
	if (!split->name_end) {
		/* no human readable name */
		split->name_end = split->name_begin;
	}
250 251 252 253 254 255 256 257 258

	for (cp = split->mail_begin; cp < line + len; cp++)
		if (*cp == '>') {
			split->mail_end = cp;
			break;
		}
	if (!split->mail_end)
		return status;

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
	/*
	 * Look from the end-of-line to find the trailing ">" of the mail
	 * address, even though we should already know it as split->mail_end.
	 * This can help in cases of broken idents with an extra ">" somewhere
	 * in the email address.  Note that we are assuming the timestamp will
	 * never have a ">" in it.
	 *
	 * Note that we will always find some ">" before going off the front of
	 * the string, because will always hit the split->mail_end closing
	 * bracket.
	 */
	for (cp = line + len - 1; *cp != '>'; cp--)
		;

	for (cp = cp + 1; cp < line + len && isspace(*cp); cp++)
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
		;
	if (line + len <= cp)
		goto person_only;
	split->date_begin = cp;
	span = strspn(cp, "0123456789");
	if (!span)
		goto person_only;
	split->date_end = split->date_begin + span;
	for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
		;
	if (line + len <= cp || (*cp != '+' && *cp != '-'))
		goto person_only;
	split->tz_begin = cp;
	span = strspn(cp + 1, "0123456789");
	if (!span)
		goto person_only;
	split->tz_end = split->tz_begin + 1 + span;
	return 0;

person_only:
	split->date_begin = NULL;
	split->date_end = NULL;
	split->tz_begin = NULL;
	split->tz_end = NULL;
	return 0;
}

301
static const char *env_hint =
302
"\n"
303
"*** Please tell me who you are.\n"
304 305 306
"\n"
"Run\n"
"\n"
307
"  git config --global user.email \"you@example.com\"\n"
308
"  git config --global user.name \"Your Name\"\n"
309
"\n"
310 311
"to set your account\'s default identity.\n"
"Omit --global to set the identity only in this repository.\n"
312
"\n";
313

314 315
const char *fmt_ident(const char *name, const char *email,
		      const char *date_str, int flag)
316
{
317
	static struct strbuf ident = STRBUF_INIT;
318
	int strict = (flag & IDENT_STRICT);
319
	int want_date = !(flag & IDENT_NO_DATE);
320
	int want_name = !(flag & IDENT_NO_NAME);
321

322
	if (want_name && !name)
323 324 325
		name = ident_default_name();
	if (!email)
		email = ident_default_email();
326

327
	if (want_name && !*name) {
328 329
		struct passwd *pw;

330
		if (strict) {
331
			if (name == git_default_name.buf)
332
				fputs(env_hint, stderr);
333
			die("empty ident name (for <%s>) not allowed", email);
334
		}
335
		pw = xgetpwuid_self();
336
		name = pw->pw_name;
337
	}
338

339 340 341 342
	if (strict && email == git_default_email.buf &&
	    strstr(email, "(none)")) {
		fputs(env_hint, stderr);
		die("unable to auto-detect email address (got '%s')", email);
343
	}
344

345
	strbuf_reset(&ident);
346 347 348
	if (want_name) {
		strbuf_addstr_without_crud(&ident, name);
		strbuf_addstr(&ident, " <");
349
	}
350
	strbuf_addstr_without_crud(&ident, email);
351 352
	if (want_name)
			strbuf_addch(&ident, '>');
353
	if (want_date) {
354
		strbuf_addch(&ident, ' ');
355 356 357 358 359 360
		if (date_str && date_str[0]) {
			if (parse_date(date_str, &ident) < 0)
				die("invalid date format: %s", date_str);
		}
		else
			strbuf_addstr(&ident, ident_default_date());
361
	}
362

363
	return ident.buf;
364
}
365

366 367
const char *fmt_name(const char *name, const char *email)
{
368
	return fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE);
369 370
}

371
const char *git_author_info(int flag)
372
{
373 374 375 376
	if (getenv("GIT_AUTHOR_NAME"))
		author_ident_explicitly_given |= IDENT_NAME_GIVEN;
	if (getenv("GIT_AUTHOR_EMAIL"))
		author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
377
	return fmt_ident(getenv("GIT_AUTHOR_NAME"),
378
			 getenv("GIT_AUTHOR_EMAIL"),
379
			 getenv("GIT_AUTHOR_DATE"),
380
			 flag);
381 382
}

383
const char *git_committer_info(int flag)
384
{
385
	if (getenv("GIT_COMMITTER_NAME"))
386
		committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
387
	if (getenv("GIT_COMMITTER_EMAIL"))
388
		committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
389
	return fmt_ident(getenv("GIT_COMMITTER_NAME"),
390
			 getenv("GIT_COMMITTER_EMAIL"),
391
			 getenv("GIT_COMMITTER_DATE"),
392
			 flag);
393
}
394

395
static int ident_is_sufficient(int user_ident_explicitly_given)
396 397 398 399 400 401 402
{
#ifndef WINDOWS
	return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
#else
	return (user_ident_explicitly_given == IDENT_ALL_GIVEN);
#endif
}
403

404 405 406 407 408 409 410 411 412 413
int committer_ident_sufficiently_given(void)
{
	return ident_is_sufficient(committer_ident_explicitly_given);
}

int author_ident_sufficiently_given(void)
{
	return ident_is_sufficient(author_ident_explicitly_given);
}

414 415 416 417 418
int git_ident_config(const char *var, const char *value, void *data)
{
	if (!strcmp(var, "user.name")) {
		if (!value)
			return config_error_nonbool(var);
419 420
		strbuf_reset(&git_default_name);
		strbuf_addstr(&git_default_name, value);
421 422
		committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
		author_ident_explicitly_given |= IDENT_NAME_GIVEN;
423 424 425 426 427 428
		return 0;
	}

	if (!strcmp(var, "user.email")) {
		if (!value)
			return config_error_nonbool(var);
429 430
		strbuf_reset(&git_default_email);
		strbuf_addstr(&git_default_email, value);
431 432
		committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
		author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
433 434 435 436 437
		return 0;
	}

	return 0;
}
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466

static int buf_cmp(const char *a_begin, const char *a_end,
		   const char *b_begin, const char *b_end)
{
	int a_len = a_end - a_begin;
	int b_len = b_end - b_begin;
	int min = a_len < b_len ? a_len : b_len;
	int cmp;

	cmp = memcmp(a_begin, b_begin, min);
	if (cmp)
		return cmp;

	return a_len - b_len;
}

int ident_cmp(const struct ident_split *a,
	      const struct ident_split *b)
{
	int cmp;

	cmp = buf_cmp(a->mail_begin, a->mail_end,
		      b->mail_begin, b->mail_end);
	if (cmp)
		return cmp;

	return buf_cmp(a->name_begin, a->name_end,
		       b->name_begin, b->name_end);
}