git.c 15.3 KB
Newer Older
1
#include "builtin.h"
2
#include "exec_cmd.h"
3
#include "cache.h"
4
#include "quote.h"
5
#include "run-command.h"
6

7
const char git_usage_string[] =
M
Matthieu Moy 已提交
8
	"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
9
	"           [-p|--paginate|--no-pager] [--no-replace-objects]\n"
M
Matthieu Moy 已提交
10
	"           [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
11
	"           [-c name=value\n"
M
Matthieu Moy 已提交
12
	"           [--help] COMMAND [ARGS]";
13

14 15 16
const char git_more_info_string[] =
	"See 'git help COMMAND' for more information on a specific command.";

J
Jeff King 已提交
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
static int use_pager = -1;
struct pager_config {
	const char *cmd;
	int val;
};

static int pager_command_config(const char *var, const char *value, void *data)
{
	struct pager_config *c = data;
	if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd))
		c->val = git_config_bool(var, value);
	return 0;
}

/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
int check_pager_config(const char *cmd)
{
	struct pager_config c;
	c.cmd = cmd;
	c.val = -1;
	git_config(pager_command_config, &c);
	return c.val;
}

static void commit_pager_choice(void) {
	switch (use_pager) {
	case 0:
		setenv("GIT_PAGER", "cat", 1);
		break;
	case 1:
		setup_pager();
		break;
	default:
		break;
	}
}

54
static int handle_options(const char ***argv, int *argc, int *envchanged)
55 56 57
{
	int handled = 0;

58 59 60
	if (!getenv("GIT_ASKPASS") && getenv("SSH_ASKPASS"))
		setenv("GIT_ASKPASS", getenv("SSH_ASKPASS"), 1);

61 62 63 64 65
	while (*argc > 0) {
		const char *cmd = (*argv)[0];
		if (cmd[0] != '-')
			break;

66 67 68 69 70 71 72 73 74 75 76
		/*
		 * For legacy reasons, the "version" and "help"
		 * commands can be written with "--" prepended
		 * to make them look like flags.
		 */
		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
			break;

		/*
		 * Check remaining flags.
		 */
77
		if (!prefixcmp(cmd, "--exec-path")) {
78 79
			cmd += 11;
			if (*cmd == '=')
80
				git_set_argv_exec_path(cmd + 1);
81 82 83 84
			else {
				puts(git_exec_path());
				exit(0);
			}
85 86 87
		} else if (!strcmp(cmd, "--html-path")) {
			puts(system_path(GIT_HTML_PATH));
			exit(0);
88
		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
J
Jeff King 已提交
89
			use_pager = 1;
90
		} else if (!strcmp(cmd, "--no-pager")) {
J
Jeff King 已提交
91
			use_pager = 0;
92 93
			if (envchanged)
				*envchanged = 1;
94 95
		} else if (!strcmp(cmd, "--no-replace-objects")) {
			read_replace_refs = 0;
96 97 98
			setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
			if (envchanged)
				*envchanged = 1;
99
		} else if (!strcmp(cmd, "--git-dir")) {
100 101 102 103
			if (*argc < 2) {
				fprintf(stderr, "No directory given for --git-dir.\n" );
				usage(git_usage_string);
			}
104
			setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
105 106
			if (envchanged)
				*envchanged = 1;
107 108
			(*argv)++;
			(*argc)--;
109
			handled++;
110
		} else if (!prefixcmp(cmd, "--git-dir=")) {
111
			setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
112 113
			if (envchanged)
				*envchanged = 1;
114 115 116 117 118 119
		} else if (!strcmp(cmd, "--work-tree")) {
			if (*argc < 2) {
				fprintf(stderr, "No directory given for --work-tree.\n" );
				usage(git_usage_string);
			}
			setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
120 121
			if (envchanged)
				*envchanged = 1;
122 123 124 125
			(*argv)++;
			(*argc)--;
		} else if (!prefixcmp(cmd, "--work-tree=")) {
			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
126 127
			if (envchanged)
				*envchanged = 1;
128
		} else if (!strcmp(cmd, "--bare")) {
129
			static char git_dir[PATH_MAX+1];
130
			is_bare_repository_cfg = 1;
131
			setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
132 133
			if (envchanged)
				*envchanged = 1;
134 135 136 137 138
		} else if (!strcmp(cmd, "-c")) {
			if (*argc < 2) {
				fprintf(stderr, "-c expects a configuration string\n" );
				usage(git_usage_string);
			}
139
			git_config_push_parameter((*argv)[1]);
140 141
			(*argv)++;
			(*argc)--;
142 143
		} else {
			fprintf(stderr, "Unknown option: %s\n", cmd);
144
			usage(git_usage_string);
145
		}
146 147 148 149 150 151 152 153

		(*argv)++;
		(*argc)--;
		handled++;
	}
	return handled;
}

154 155
static int handle_alias(int *argcp, const char ***argv)
{
156
	int envchanged = 0, ret = 0, saved_errno = errno;
157
	const char *subdir;
158
	int count, option_count;
159
	const char **new_argv;
160 161
	const char *alias_command;
	char *alias_string;
162
	int unused_nongit;
163

164
	subdir = setup_git_directory_gently(&unused_nongit);
165 166

	alias_command = (*argv)[0];
167
	alias_string = alias_lookup(alias_command);
168
	if (alias_string) {
169
		if (alias_string[0] == '!') {
170
			commit_pager_choice();
171
			if (*argcp > 1) {
172
				struct strbuf buf;
173

174 175
				strbuf_init(&buf, PATH_MAX);
				strbuf_addstr(&buf, alias_string);
176
				sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
177
				free(alias_string);
178
				alias_string = buf.buf;
179
			}
180 181 182 183 184 185
			trace_printf("trace: alias to shell cmd: %s => %s\n",
				     alias_command, alias_string + 1);
			ret = system(alias_string + 1);
			if (ret >= 0 && WIFEXITED(ret) &&
			    WEXITSTATUS(ret) != 127)
				exit(WEXITSTATUS(ret));
186
			die("Failed to run '%s' when expanding alias '%s'",
187 188
			    alias_string + 1, alias_command);
		}
189
		count = split_cmdline(alias_string, &new_argv);
190 191
		if (count < 0)
			die("Bad alias.%s string", alias_command);
192 193 194 195 196
		option_count = handle_options(&new_argv, &count, &envchanged);
		if (envchanged)
			die("alias '%s' changes environment variables\n"
				 "You can use '!git' in the alias to do this.",
				 alias_command);
197 198 199 200 201 202 203 204 205 206
		memmove(new_argv - option_count, new_argv,
				count * sizeof(char *));
		new_argv -= option_count;

		if (count < 1)
			die("empty alias for %s", alias_command);

		if (!strcmp(alias_command, new_argv[0]))
			die("recursive alias: %s", alias_command);

207
		trace_argv_printf(new_argv,
208 209
				  "trace: alias expansion: %s =>",
				  alias_command);
210

211
		new_argv = xrealloc(new_argv, sizeof(char *) *
212
				    (count + *argcp));
213
		/* insert after command name */
214
		memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
215

216 217
		*argv = new_argv;
		*argcp += count - 1;
218

219
		ret = 1;
220 221
	}

A
Alex Riesen 已提交
222
	if (subdir && chdir(subdir))
223
		die_errno("Cannot change to '%s'", subdir);
224

225 226
	errno = saved_errno;

227 228 229
	return ret;
}

230
const char git_version_string[] = GIT_VERSION;
J
Junio C Hamano 已提交
231

232 233
#define RUN_SETUP	(1<<0)
#define USE_PAGER	(1<<1)
234 235 236 237
/*
 * require working tree to be present -- anything uses this needs
 * RUN_SETUP for reading from the configuration file.
 */
238
#define NEED_WORK_TREE	(1<<2)
239

240 241 242 243 244 245
struct cmd_struct {
	const char *cmd;
	int (*fn)(int, const char **, const char *);
	int option;
};

J
Jeff King 已提交
246
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
247
{
248
	int status, help;
249
	struct stat st;
250 251 252
	const char *prefix;

	prefix = NULL;
253 254 255 256 257 258 259 260 261 262
	help = argc == 2 && !strcmp(argv[1], "-h");
	if (!help) {
		if (p->option & RUN_SETUP)
			prefix = setup_git_directory();

		if (use_pager == -1 && p->option & RUN_SETUP)
			use_pager = check_pager_config(p->cmd);
		if (use_pager == -1 && p->option & USE_PAGER)
			use_pager = 1;
	}
J
Jeff King 已提交
263 264
	commit_pager_choice();

265
	if (!help && p->option & NEED_WORK_TREE)
M
Mike Hommey 已提交
266 267
		setup_work_tree();

268
	trace_argv_printf(argv, "trace: built-in: git");
269

270 271
	status = p->fn(argc, argv, prefix);
	if (status)
272
		return status;
273 274 275 276 277 278 279 280 281

	/* Somebody closed stdout? */
	if (fstat(fileno(stdout), &st))
		return 0;
	/* Ignore write errors for pipes and sockets.. */
	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
		return 0;

	/* Check for ENOSPC and EIO errors.. */
282
	if (fflush(stdout))
283
		die_errno("write failure on standard output");
284 285 286
	if (ferror(stdout))
		die("unknown write failure on standard output");
	if (fclose(stdout))
287
		die_errno("close failed on standard output");
288
	return 0;
289 290 291
}

static void handle_internal_command(int argc, const char **argv)
292 293
{
	const char *cmd = argv[0];
294
	static struct cmd_struct commands[] = {
295
		{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
296
		{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
297
		{ "annotate", cmd_annotate, RUN_SETUP },
J
Junio C Hamano 已提交
298
		{ "apply", cmd_apply },
299
		{ "archive", cmd_archive },
300
		{ "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE },
301
		{ "blame", cmd_blame, RUN_SETUP },
J
Junio C Hamano 已提交
302
		{ "branch", cmd_branch, RUN_SETUP },
303
		{ "bundle", cmd_bundle },
304
		{ "cat-file", cmd_cat_file, RUN_SETUP },
D
Daniel Barkalow 已提交
305
		{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
306 307
		{ "checkout-index", cmd_checkout_index,
			RUN_SETUP | NEED_WORK_TREE},
P
Peter Eriksen 已提交
308
		{ "check-ref-format", cmd_check_ref_format },
309
		{ "check-attr", cmd_check_attr, RUN_SETUP },
R
Rene Scharfe 已提交
310
		{ "cherry", cmd_cherry, RUN_SETUP },
311
		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
D
Daniel Barkalow 已提交
312
		{ "clone", cmd_clone },
S
Shawn Bohrer 已提交
313
		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
K
Kristian Høgsberg 已提交
314
		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
315
		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
316
		{ "config", cmd_config },
317
		{ "count-objects", cmd_count_objects, RUN_SETUP },
S
Shawn O. Pearce 已提交
318
		{ "describe", cmd_describe, RUN_SETUP },
319
		{ "diff", cmd_diff },
320
		{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
321 322
		{ "diff-index", cmd_diff_index, RUN_SETUP },
		{ "diff-tree", cmd_diff_tree, RUN_SETUP },
323
		{ "fast-export", cmd_fast_export, RUN_SETUP },
D
Daniel Barkalow 已提交
324
		{ "fetch", cmd_fetch, RUN_SETUP },
325
		{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
326
		{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
327
		{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
328
		{ "format-patch", cmd_format_patch, RUN_SETUP },
329 330
		{ "fsck", cmd_fsck, RUN_SETUP },
		{ "fsck-objects", cmd_fsck, RUN_SETUP },
J
James Bowes 已提交
331
		{ "gc", cmd_gc, RUN_SETUP },
J
Junio C Hamano 已提交
332
		{ "get-tar-commit-id", cmd_get_tar_commit_id },
333
		{ "grep", cmd_grep },
334
		{ "hash-object", cmd_hash_object },
J
Junio C Hamano 已提交
335
		{ "help", cmd_help },
L
Linus Torvalds 已提交
336
		{ "index-pack", cmd_index_pack },
337
		{ "init", cmd_init_db },
J
Junio C Hamano 已提交
338
		{ "init-db", cmd_init_db },
339 340 341
		{ "log", cmd_log, RUN_SETUP | USE_PAGER },
		{ "ls-files", cmd_ls_files, RUN_SETUP },
		{ "ls-tree", cmd_ls_tree, RUN_SETUP },
D
Daniel Barkalow 已提交
342
		{ "ls-remote", cmd_ls_remote },
J
Junio C Hamano 已提交
343 344
		{ "mailinfo", cmd_mailinfo },
		{ "mailsplit", cmd_mailsplit },
M
Miklos Vajna 已提交
345
		{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
J
Junio C Hamano 已提交
346
		{ "merge-base", cmd_merge_base, RUN_SETUP },
347
		{ "merge-file", cmd_merge_file },
L
Linus Torvalds 已提交
348
		{ "merge-index", cmd_merge_index, RUN_SETUP },
349
		{ "merge-ours", cmd_merge_ours, RUN_SETUP },
D
Daniel Barkalow 已提交
350
		{ "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
A
Avery Pennarun 已提交
351 352
		{ "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
		{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
J
Junio C Hamano 已提交
353
		{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
354
		{ "merge-tree", cmd_merge_tree, RUN_SETUP },
L
Linus Torvalds 已提交
355
		{ "mktag", cmd_mktag, RUN_SETUP },
J
Junio C Hamano 已提交
356
		{ "mktree", cmd_mktree, RUN_SETUP },
357
		{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
358
		{ "name-rev", cmd_name_rev, RUN_SETUP },
J
Johan Herland 已提交
359
		{ "notes", cmd_notes, RUN_SETUP },
360
		{ "pack-objects", cmd_pack_objects, RUN_SETUP },
361
		{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
L
Linus Torvalds 已提交
362
		{ "patch-id", cmd_patch_id },
D
Daniel Barkalow 已提交
363
		{ "peek-remote", cmd_ls_remote },
364
		{ "pickaxe", cmd_blame, RUN_SETUP },
365 366
		{ "prune", cmd_prune, RUN_SETUP },
		{ "prune-packed", cmd_prune_packed, RUN_SETUP },
367
		{ "push", cmd_push, RUN_SETUP },
368
		{ "read-tree", cmd_read_tree, RUN_SETUP },
J
Junio C Hamano 已提交
369
		{ "receive-pack", cmd_receive_pack },
J
Junio C Hamano 已提交
370
		{ "reflog", cmd_reflog, RUN_SETUP },
J
Johannes Schindelin 已提交
371
		{ "remote", cmd_remote, RUN_SETUP },
C
Christian Couder 已提交
372
		{ "replace", cmd_replace, RUN_SETUP },
373
		{ "repo-config", cmd_config },
J
Johannes Schindelin 已提交
374
		{ "rerere", cmd_rerere, RUN_SETUP },
C
Carlos Rica 已提交
375
		{ "reset", cmd_reset, RUN_SETUP },
376
		{ "rev-list", cmd_rev_list, RUN_SETUP },
J
Junio C Hamano 已提交
377
		{ "rev-parse", cmd_rev_parse },
378
		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
379
		{ "rm", cmd_rm, RUN_SETUP },
380
		{ "send-pack", cmd_send_pack, RUN_SETUP },
381
		{ "shortlog", cmd_shortlog, USE_PAGER },
382 383
		{ "show-branch", cmd_show_branch, RUN_SETUP },
		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
384
		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
J
Junio C Hamano 已提交
385
		{ "stripspace", cmd_stripspace },
386
		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
C
Carlos Rica 已提交
387
		{ "tag", cmd_tag, RUN_SETUP },
R
Rene Scharfe 已提交
388
		{ "tar-tree", cmd_tar_tree },
389
		{ "unpack-file", cmd_unpack_file, RUN_SETUP },
390 391 392
		{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
		{ "update-index", cmd_update_index, RUN_SETUP },
		{ "update-ref", cmd_update_ref, RUN_SETUP },
393
		{ "update-server-info", cmd_update_server_info, RUN_SETUP },
F
Franck Bui-Huu 已提交
394
		{ "upload-archive", cmd_upload_archive },
L
Linus Torvalds 已提交
395
		{ "var", cmd_var },
C
Carlos Rica 已提交
396
		{ "verify-tag", cmd_verify_tag, RUN_SETUP },
J
Junio C Hamano 已提交
397
		{ "version", cmd_version },
398 399
		{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
		{ "write-tree", cmd_write_tree, RUN_SETUP },
R
Rene Scharfe 已提交
400
		{ "verify-pack", cmd_verify_pack },
401
		{ "show-ref", cmd_show_ref, RUN_SETUP },
402
		{ "pack-refs", cmd_pack_refs, RUN_SETUP },
403 404
	};
	int i;
405 406 407 408 409
	static const char ext[] = STRIP_EXTENSION;

	if (sizeof(ext) > 1) {
		i = strlen(argv[0]) - strlen(ext);
		if (i > 0 && !strcmp(argv[0] + i, ext)) {
410
			char *argv0 = xstrdup(argv[0]);
411 412 413 414
			argv[0] = cmd = argv0;
			argv0[i] = '\0';
		}
	}
415

L
Linus Torvalds 已提交
416 417 418 419 420 421
	/* Turn "git cmd --help" into "git help cmd" */
	if (argc > 1 && !strcmp(argv[1], "--help")) {
		argv[1] = argv[0];
		argv[0] = cmd = "help";
	}

422 423 424 425
	for (i = 0; i < ARRAY_SIZE(commands); i++) {
		struct cmd_struct *p = commands+i;
		if (strcmp(p->cmd, cmd))
			continue;
J
Jeff King 已提交
426
		exit(run_builtin(p, argc, argv));
427 428 429
	}
}

430 431
static void execv_dashed_external(const char **argv)
{
432
	struct strbuf cmd = STRBUF_INIT;
433
	const char *tmp;
434
	int status;
435

436 437
	commit_pager_choice();

438 439 440 441 442 443 444 445 446 447 448 449 450
	strbuf_addf(&cmd, "git-%s", argv[0]);

	/*
	 * argv[0] must be the git command, but the argv array
	 * belongs to the caller, and may be reused in
	 * subsequent loop iterations. Save argv[0] and
	 * restore it on error.
	 */
	tmp = argv[0];
	argv[0] = cmd.buf;

	trace_argv_printf(argv, "trace: exec:");

451 452 453 454
	/*
	 * if we fail because the command is not found, it is
	 * OK to return. Otherwise, we just pass along the status code.
	 */
455
	status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);
456
	if (status >= 0 || errno != ENOENT)
457
		exit(status);
458 459 460 461 462 463

	argv[0] = tmp;

	strbuf_release(&cmd);
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
static int run_argv(int *argcp, const char ***argv)
{
	int done_alias = 0;

	while (1) {
		/* See if it's an internal command */
		handle_internal_command(*argcp, *argv);

		/* .. then try the external ones */
		execv_dashed_external(*argv);

		/* It could be an alias -- this works around the insanity
		 * of overriding "git log" with "git show" by having
		 * alias.log = show
		 */
		if (done_alias || !handle_alias(argcp, argv))
			break;
		done_alias = 1;
	}

	return done_alias;
}

487

488
int main(int argc, const char **argv)
489
{
490
	const char *cmd;
491

492 493
	cmd = git_extract_argv0_path(argv[0]);
	if (!cmd)
494
		cmd = "git-help";
495

496 497 498 499 500 501 502 503 504 505
	/*
	 * "git-xxxx" is the same as "git xxxx", but we obviously:
	 *
	 *  - cannot take flags in between the "git" and the "xxxx".
	 *  - cannot execute it externally (since it would just do
	 *    the same thing over again)
	 *
	 * So we just directly call the internal command handler, and
	 * die if that one cannot handle it.
	 */
506
	if (!prefixcmp(cmd, "git-")) {
507 508
		cmd += 4;
		argv[0] = cmd;
509
		handle_internal_command(argc, argv);
510 511
		die("cannot handle %s internally", cmd);
	}
512

513
	/* Look for flags.. */
514 515
	argv++;
	argc--;
516
	handle_options(&argv, &argc, NULL);
517
	if (argc > 0) {
518
		if (!prefixcmp(argv[0], "--"))
519 520
			argv[0] += 2;
	} else {
521
		/* The user didn't specify a command; give them help */
522
		commit_pager_choice();
523 524
		printf("usage: %s\n\n", git_usage_string);
		list_common_cmds_help();
525
		printf("\n%s\n", git_more_info_string);
526
		exit(1);
527
	}
528
	cmd = argv[0];
529 530

	/*
531
	 * We use PATH to find git commands, but we prepend some higher
M
Mike Ralphson 已提交
532
	 * precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
533 534
	 * environment, and the $(gitexecdir) from the Makefile at build
	 * time.
535
	 */
536
	setup_path();
537

J
Junio C Hamano 已提交
538
	while (1) {
539 540 541 542
		static int done_help = 0;
		static int was_alias = 0;
		was_alias = run_argv(&argc, &argv);
		if (errno != ENOENT)
J
Junio C Hamano 已提交
543
			break;
544
		if (was_alias) {
545
			fprintf(stderr, "Expansion of alias '%s' failed; "
546
				"'%s' is not a git command\n",
547 548 549
				cmd, argv[0]);
			exit(1);
		}
550 551 552 553 554
		if (!done_help) {
			cmd = argv[0] = help_unknown_cmd(cmd);
			done_help = 1;
		} else
			break;
555
	}
556 557

	fprintf(stderr, "Failed to run command '%s': %s\n",
558
		cmd, strerror(errno));
559 560 561

	return 1;
}