Пример #1
0
static int restore_untracked(struct object_id *u_tree)
{
	int res;
	struct child_process cp = CHILD_PROCESS_INIT;

	/*
	 * We need to run restore files from a given index, but without
	 * affecting the current index, so we use GIT_INDEX_FILE with
	 * run_command to fork processes that will not interfere.
	 */
	cp.git_cmd = 1;
	argv_array_push(&cp.args, "read-tree");
	argv_array_push(&cp.args, oid_to_hex(u_tree));
	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
			 stash_index_path.buf);
	if (run_command(&cp)) {
		remove_path(stash_index_path.buf);
		return -1;
	}

	child_process_init(&cp);
	cp.git_cmd = 1;
	argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
			 stash_index_path.buf);

	res = run_command(&cp);
	remove_path(stash_index_path.buf);
	return res;
}
Пример #2
0
static struct child_process *git_proxy_connect(int fd[2], char *host)
{
	const char *port = STR(DEFAULT_GIT_PORT);
	struct child_process *proxy;

	get_host_and_port(&host, &port);

	if (looks_like_command_line_option(host))
		die("strange hostname '%s' blocked", host);
	if (looks_like_command_line_option(port))
		die("strange port '%s' blocked", port);

	proxy = xmalloc(sizeof(*proxy));
	child_process_init(proxy);
	argv_array_push(&proxy->args, git_proxy_command);
	argv_array_push(&proxy->args, host);
	argv_array_push(&proxy->args, port);
	proxy->in = -1;
	proxy->out = -1;
	if (start_command(proxy))
		die("cannot start proxy %s", git_proxy_command);
	fd[0] = proxy->out; /* read from proxy stdout */
	fd[1] = proxy->in;  /* write to proxy stdin */
	return proxy;
}
Пример #3
0
static int clone_submodule(const char *path, const char *gitdir, const char *url,
			   const char *depth, const char *reference, int quiet)
{
	struct child_process cp;
	child_process_init(&cp);

	argv_array_push(&cp.args, "clone");
	argv_array_push(&cp.args, "--no-checkout");
	if (quiet)
		argv_array_push(&cp.args, "--quiet");
	if (depth && *depth)
		argv_array_pushl(&cp.args, "--depth", depth, NULL);
	if (reference && *reference)
		argv_array_pushl(&cp.args, "--reference", reference, NULL);
	if (gitdir && *gitdir)
		argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);

	argv_array_push(&cp.args, url);
	argv_array_push(&cp.args, path);

	cp.git_cmd = 1;
	cp.env = local_repo_env;
	cp.no_stdin = 1;

	return run_command(&cp);
}
Пример #4
0
int run_column_filter(int colopts, const struct column_options *opts)
{
	struct argv_array *argv;

	if (fd_out != -1)
		return -1;

	child_process_init(&column_process);
	argv = &column_process.args;

	argv_array_push(argv, "column");
	argv_array_pushf(argv, "--raw-mode=%d", colopts);
	if (opts && opts->width)
		argv_array_pushf(argv, "--width=%d", opts->width);
	if (opts && opts->indent)
		argv_array_pushf(argv, "--indent=%s", opts->indent);
	if (opts && opts->padding)
		argv_array_pushf(argv, "--padding=%d", opts->padding);

	fflush(stdout);
	column_process.in = -1;
	column_process.out = dup(1);
	column_process.git_cmd = 1;

	if (start_command(&column_process))
		return -2;

	fd_out = dup(1);
	close(1);
	dup2(column_process.in, 1);
	close(column_process.in);
	return 0;
}
Пример #5
0
static int pp_collect_finished(struct parallel_processes *pp)
{
	int i, code;
	int n = pp->max_processes;
	int result = 0;

	while (pp->nr_processes > 0) {
		for (i = 0; i < pp->max_processes; i++)
			if (pp->children[i].state == GIT_CP_WAIT_CLEANUP)
				break;
		if (i == pp->max_processes)
			break;

		code = finish_command(&pp->children[i].process);

		code = pp->task_finished(code,
					 &pp->children[i].err, pp->data,
					 &pp->children[i].data);

		if (code)
			result = code;
		if (code < 0)
			break;

		pp->nr_processes--;
		pp->children[i].state = GIT_CP_FREE;
		pp->pfd[i].fd = -1;
		child_process_init(&pp->children[i].process);

		if (i != pp->output_owner) {
			strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
			strbuf_reset(&pp->children[i].err);
		} else {
			strbuf_write(&pp->children[i].err, stderr);
			strbuf_reset(&pp->children[i].err);

			/* Output all other finished child processes */
			strbuf_write(&pp->buffered_output, stderr);
			strbuf_reset(&pp->buffered_output);

			/*
			 * Pick next process to output live.
			 * NEEDSWORK:
			 * For now we pick it randomly by doing a round
			 * robin. Later we may want to pick the one with
			 * the most output or the longest or shortest
			 * running process time.
			 */
			for (i = 0; i < n; i++)
				if (pp->children[(pp->output_owner + i) % n].state == GIT_CP_WORKING)
					break;
			pp->output_owner = (pp->output_owner + i) % n;
		}
	}
	return result;
}
Пример #6
0
static void pp_init(struct parallel_processes *pp,
		    int n,
		    get_next_task_fn get_next_task,
		    start_failure_fn start_failure,
		    task_finished_fn task_finished,
		    void *data)
{
	int i;

	if (n < 1)
		n = online_cpus();

	pp->max_processes = n;

	trace_printf("run_processes_parallel: preparing to run up to %d tasks", n);

	pp->data = data;
	if (!get_next_task)
		die("BUG: you need to specify a get_next_task function");
	pp->get_next_task = get_next_task;

	pp->start_failure = start_failure ? start_failure : default_start_failure;
	pp->task_finished = task_finished ? task_finished : default_task_finished;

	pp->nr_processes = 0;
	pp->output_owner = 0;
	pp->shutdown = 0;
	pp->children = xcalloc(n, sizeof(*pp->children));
	pp->pfd = xcalloc(n, sizeof(*pp->pfd));
	strbuf_init(&pp->buffered_output, 0);

	for (i = 0; i < n; i++) {
		strbuf_init(&pp->children[i].err, 0);
		child_process_init(&pp->children[i].process);
		pp->pfd[i].events = POLLIN | POLLHUP;
		pp->pfd[i].fd = -1;
	}

	pp_for_signal = pp;
	sigchain_push_common(handle_children_on_signal);
}
Пример #7
0
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
	subprocess_start_fn startfn)
{
	int err;
	struct child_process *process;
	const char *argv[] = { cmd, NULL };

	entry->cmd = cmd;
	process = &entry->process;

	child_process_init(process);
	process->argv = argv;
	process->use_shell = 1;
	process->in = -1;
	process->out = -1;
	process->clean_on_exit = 1;
	process->clean_on_exit_handler = subprocess_exit_handler;

	err = start_command(process);
	if (err) {
		error("cannot fork to run subprocess '%s'", cmd);
		return err;
	}

	hashmap_entry_init(entry, strhash(cmd));

	err = startfn(entry);
	if (err) {
		error("initialization for subprocess '%s' failed", cmd);
		subprocess_stop(hashmap, entry);
		return err;
	}

	hashmap_add(hashmap, entry);
	return 0;
}
Пример #8
0
static const char *push_to_deploy(unsigned char *sha1,
				  struct argv_array *env,
				  const char *work_tree)
{
	const char *update_refresh[] = {
		"update-index", "-q", "--ignore-submodules", "--refresh", NULL
	};
	const char *diff_files[] = {
		"diff-files", "--quiet", "--ignore-submodules", "--", NULL
	};
	const char *diff_index[] = {
		"diff-index", "--quiet", "--cached", "--ignore-submodules",
		NULL, "--", NULL
	};
	const char *read_tree[] = {
		"read-tree", "-u", "-m", NULL, NULL
	};
	struct child_process child = CHILD_PROCESS_INIT;

	child.argv = update_refresh;
	child.env = env->argv;
	child.dir = work_tree;
	child.no_stdin = 1;
	child.stdout_to_stderr = 1;
	child.git_cmd = 1;
	if (run_command(&child))
		return "Up-to-date check failed";

	/* run_command() does not clean up completely; reinitialize */
	child_process_init(&child);
	child.argv = diff_files;
	child.env = env->argv;
	child.dir = work_tree;
	child.no_stdin = 1;
	child.stdout_to_stderr = 1;
	child.git_cmd = 1;
	if (run_command(&child))
		return "Working directory has unstaged changes";

	/* diff-index with either HEAD or an empty tree */
	diff_index[4] = head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX;

	child_process_init(&child);
	child.argv = diff_index;
	child.env = env->argv;
	child.no_stdin = 1;
	child.no_stdout = 1;
	child.stdout_to_stderr = 0;
	child.git_cmd = 1;
	if (run_command(&child))
		return "Working directory has staged changes";

	read_tree[3] = sha1_to_hex(sha1);
	child_process_init(&child);
	child.argv = read_tree;
	child.env = env->argv;
	child.dir = work_tree;
	child.no_stdin = 1;
	child.no_stdout = 1;
	child.stdout_to_stderr = 0;
	child.git_cmd = 1;
	if (run_command(&child))
		return "Could not update working tree to new HEAD";

	return NULL;
}
Пример #9
0
/*
 * This returns a dummy child_process if the transport protocol does not
 * need fork(2), or a struct child_process object if it does.  Once done,
 * finish the connection with finish_connect() with the value returned from
 * this function (it is safe to call finish_connect() with NULL to support
 * the former case).
 *
 * If it returns, the connect is successful; it just dies on errors (this
 * will hopefully be changed in a libification effort, to return NULL when
 * the connection failed).
 */
struct child_process *git_connect(int fd[2], const char *url,
				  const char *prog, int flags)
{
	char *hostandport, *path;
	struct child_process *conn = &no_fork;
	enum protocol protocol;
	struct strbuf cmd = STRBUF_INIT;

	/* Without this we cannot rely on waitpid() to tell
	 * what happened to our children.
	 */
	signal(SIGCHLD, SIG_DFL);

	protocol = parse_connect_url(url, &hostandport, &path);
	if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
		printf("Diag: url=%s\n", url ? url : "NULL");
		printf("Diag: protocol=%s\n", prot_name(protocol));
		printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
		printf("Diag: path=%s\n", path ? path : "NULL");
		conn = NULL;
	} else if (protocol == PROTO_GIT) {
		/*
		 * Set up virtual host information based on where we will
		 * connect, unless the user has overridden us in
		 * the environment.
		 */
		char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST");
		if (target_host)
			target_host = xstrdup(target_host);
		else
			target_host = xstrdup(hostandport);

		transport_check_allowed("git");

		/* These underlying connection commands die() if they
		 * cannot connect.
		 */
		if (git_use_proxy(hostandport))
			conn = git_proxy_connect(fd, hostandport);
		else
			git_tcp_connect(fd, hostandport, flags);
		/*
		 * Separate original protocol components prog and path
		 * from extended host header with a NUL byte.
		 *
		 * Note: Do not add any other headers here!  Doing so
		 * will cause older git-daemon servers to crash.
		 */
		packet_write(fd[1],
			     "%s %s%chost=%s%c",
			     prog, path, 0,
			     target_host, 0);
		free(target_host);
	} else {
		conn = xmalloc(sizeof(*conn));
		child_process_init(conn);

		strbuf_addstr(&cmd, prog);
		strbuf_addch(&cmd, ' ');
		sq_quote_buf(&cmd, path);

		conn->in = conn->out = -1;
		if (protocol == PROTO_SSH) {
			const char *ssh;
			int putty, tortoiseplink = 0;
			char *ssh_host = hostandport;
			const char *port = NULL;
			transport_check_allowed("ssh");
			get_host_and_port(&ssh_host, &port);

			if (!port)
				port = get_port(ssh_host);

			if (flags & CONNECT_DIAG_URL) {
				printf("Diag: url=%s\n", url ? url : "NULL");
				printf("Diag: protocol=%s\n", prot_name(protocol));
				printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
				printf("Diag: port=%s\n", port ? port : "NONE");
				printf("Diag: path=%s\n", path ? path : "NULL");

				free(hostandport);
				free(path);
				free(conn);
				return NULL;
			}

			ssh = getenv("GIT_SSH_COMMAND");
			if (ssh) {
				conn->use_shell = 1;
				putty = 0;
			} else {
				const char *base;
				char *ssh_dup;

				ssh = getenv("GIT_SSH");
				if (!ssh)
					ssh = "ssh";

				ssh_dup = xstrdup(ssh);
				base = basename(ssh_dup);

				tortoiseplink = !strcasecmp(base, "tortoiseplink") ||
					!strcasecmp(base, "tortoiseplink.exe");
				putty = !strcasecmp(base, "plink") ||
					!strcasecmp(base, "plink.exe") || tortoiseplink;

				free(ssh_dup);
			}

			argv_array_push(&conn->args, ssh);
			if (tortoiseplink)
				argv_array_push(&conn->args, "-batch");
			if (port) {
				/* P is for PuTTY, p is for OpenSSH */
				argv_array_push(&conn->args, putty ? "-P" : "-p");
				argv_array_push(&conn->args, port);
			}
			argv_array_push(&conn->args, ssh_host);
		} else {
			/* remove repo-local variables from the environment */
			conn->env = local_repo_env;
			conn->use_shell = 1;
			transport_check_allowed("file");
		}
		argv_array_push(&conn->args, cmd.buf);

		if (start_command(conn))
			die("unable to fork");

		fd[0] = conn->out; /* read from child's stdout */
		fd[1] = conn->in;  /* write to child's stdin */
		strbuf_release(&cmd);
	}
	free(hostandport);
	free(path);
	return conn;
}
Пример #10
0
/*
 * This returns the dummy child_process `no_fork` if the transport protocol
 * does not need fork(2), or a struct child_process object if it does.  Once
 * done, finish the connection with finish_connect() with the value returned
 * from this function (it is safe to call finish_connect() with NULL to
 * support the former case).
 *
 * If it returns, the connect is successful; it just dies on errors (this
 * will hopefully be changed in a libification effort, to return NULL when
 * the connection failed).
 */
struct child_process *git_connect(int fd[2], const char *url,
				  const char *prog, int flags)
{
	char *hostandport, *path;
	struct child_process *conn;
	enum protocol protocol;

	/* Without this we cannot rely on waitpid() to tell
	 * what happened to our children.
	 */
	signal(SIGCHLD, SIG_DFL);

	protocol = parse_connect_url(url, &hostandport, &path);
	if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
		printf("Diag: url=%s\n", url ? url : "NULL");
		printf("Diag: protocol=%s\n", prot_name(protocol));
		printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
		printf("Diag: path=%s\n", path ? path : "NULL");
		conn = NULL;
	} else if (protocol == PROTO_GIT) {
		conn = git_connect_git(fd, hostandport, path, prog, flags);
	} else {
		struct strbuf cmd = STRBUF_INIT;
		const char *const *var;

		conn = xmalloc(sizeof(*conn));
		child_process_init(conn);

		if (looks_like_command_line_option(path))
			die("strange pathname '%s' blocked", path);

		strbuf_addstr(&cmd, prog);
		strbuf_addch(&cmd, ' ');
		sq_quote_buf(&cmd, path);

		/* remove repo-local variables from the environment */
		for (var = local_repo_env; *var; var++)
			argv_array_push(&conn->env_array, *var);

		conn->use_shell = 1;
		conn->in = conn->out = -1;
		if (protocol == PROTO_SSH) {
			char *ssh_host = hostandport;
			const char *port = NULL;
			transport_check_allowed("ssh");
			get_host_and_port(&ssh_host, &port);

			if (!port)
				port = get_port(ssh_host);

			if (flags & CONNECT_DIAG_URL) {
				printf("Diag: url=%s\n", url ? url : "NULL");
				printf("Diag: protocol=%s\n", prot_name(protocol));
				printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
				printf("Diag: port=%s\n", port ? port : "NONE");
				printf("Diag: path=%s\n", path ? path : "NULL");

				free(hostandport);
				free(path);
				free(conn);
				strbuf_release(&cmd);
				return NULL;
			}
			fill_ssh_args(conn, ssh_host, port, flags);
		} else {
			transport_check_allowed("file");
			if (get_protocol_version_config() > 0) {
				argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
						 get_protocol_version_config());
			}
		}
		argv_array_push(&conn->args, cmd.buf);

		if (start_command(conn))
			die("unable to fork");

		fd[0] = conn->out; /* read from child's stdout */
		fd[1] = conn->in;  /* write to child's stdin */
		strbuf_release(&cmd);
	}
	free(hostandport);
	free(path);
	return conn;
}
Пример #11
0
// * ================================================================================ *
// @ main
// * ================================================================================ *
int main(int argc, char ** argv)
{
	//open the log file
	pLogFile = &CCLogFile;
	CCLogFile.startlog(1);
	CCLogFile.SetLogSize(2*1000*1000);
	CCLogFile.SetLoglevel(1);
	CCLogFile.logopen();
	
	if ( myconfig.readfile(CONFIG_FILE_PATH) == 0 )
	{
		printf("appserver: read config file '%s' error\n", CONFIG_FILE_PATH);
		LOG(LOG1, "appserver: read config file '%s' error\n", CONFIG_FILE_PATH);
		sleep(2);
		exit(0);
	}
	
	CCLogFile.SetLoglevel(ToInt(myconfig["LogLevel"][1]));
	
	
	//TANG 2010-9-4 11:02
	//处理命令行参数
	if ( argc == 3 && strcmp(argv[1], "reload") == 0 && strcmp(argv[2], "config") == 0 )
	{
		send_msg_reload_config("127.0.0.1", (( ToInt(myconfig["AppServerListenPort"][1]) > 0 ) ? ToInt(myconfig["AppServerListenPort"][1]) : 4016));
		exit(0);
	}
	
	
	LOG(LOG1, "appserver: start\n");
	
	child_process_init(SN3_SERVICE_NUMBER);
	
	//application_envinit();
	//LOG(LOG1, "appserver: application_envinit() done\n");

	_appserver_initial();
	LOG(LOG1, "appserver: _appserver_initial() done\n");

	nthread_create(thread_sockserver, NULL, 64*1024);
	nthread_create(thread_procdata_sendsmsg, NULL, 64*1024);
	
	tcp_server1.SetpLog(&CCLogFile);
	tcp_server1.SetCallBackFunc(deal_client_msg);
	if ( ToInt(myconfig["AppServerListenPort"][1]) > 0 )
	{
		tcp_server1.Listen(ToInt(myconfig["AppServerListenPort"][1]), 180);
	}
	else
	{
		tcp_server1.Listen(4016, 180);
	}

	//NPOSITION pos;
	//rundata_realtest* p_runtest;
	
	string s_terminal, s_msg_type;
	
	time_t t_check_hb_timeout = time(NULL);
	time_t t_check_test_timeout = time(NULL);
	
	while(g_appserver.m_runing)
	{
		child_process_hb(SN3_SERVICE_NUMBER);
		
		/*
		pos = NULL;
		while(NULL != (p_runtest = realtest_next(pos))) 
		{
			if ( time(NULL) >= p_runtest->tm_end )
			{
				CClientMsg::ansy_getitem(p_runtest->s_testdata.c_str(), "terminal", s_terminal);
				CClientMsg::ansy_getitem(p_runtest->s_testdata.c_str(), "msg", s_msg_type);
				
				//PESQ的实时测试,ftp扫描单元可能直接修改数据库的测试结果为X
				CNString sql;
				sql.Format("select * from BUSSOP where BUSSOP_ID = '%s' and (STATUS != 'X' and STATUS != 'Y');", p_runtest->s_bussopid.c_str());
				DATASET dbresult;
				if ( DB1.db_select(sql.c_str(), dbresult, LOG6) > 0 )
				{
					LOG(LOG1, "测试超时 [%s] '%c', s_bussopid='%s', timeout=%ds\n\n", 
						s_terminal.c_str(), 
						p_runtest->u_buss, 
						p_runtest->s_bussopid.c_str(), 
						p_runtest->tm_end - p_runtest->tm_start
						);
					
					int i_rescode = 1;
					if ( dbresult[0]["STATUS"] == "W" ) i_rescode = 5001;
					
					appserver_dbupdate_bussop_error(p_runtest->s_bussopid.c_str(), i_rescode);
				}
				
				t_uchar u_buss = p_runtest->u_buss;
				
				p_runtest = realtest_next(pos);
				
				realtest_delete(s_terminal.c_str(), u_buss);
			}
		}
		*/
		
		n_sleep(1000);
		
		if ( time(NULL) >= t_check_hb_timeout + 10*60 )
		{
			CNString sql;
			sql.Format("select * from CONFIG_TERMINAL where TERMINAL_STATE = 0 and HEARTBEAT_STATE = 0 and %u >= T_RECV_HEARTBEAT + %d;", 
					time(NULL), ToInt(myconfig["SMS_HEARTBEAT_TIMEOUT"][1]));
			
			DATASET dbresult;
			if ( DB1.db_select(sql.c_str(), dbresult, LOG6) > 0 )
			{
				//某终端心跳短信超时
				for ( int i=0; i<dbresult.size(); i++ )
				{
					string s_terminal = dbresult[i]["TERMINAL_ID"];
					string s_bussopid;
					string s_starttime = time_format_str(time(NULL), 1);
					_ori_bussopid(s_bussopid, BUSSOPTYPE_ROUTINE, s_terminal.c_str(), "IA", s_starttime.c_str());
					appserver_dbinsert_bussop(s_bussopid.c_str(), BUSSOPTYPE_ROUTINE, "IA", s_terminal.c_str(), s_starttime.c_str(), "", 'X');
					insert_bussop_exception_result(s_bussopid.c_str(), "HEARTBEAT_TMOUT");
					update_terminal_heartbeat_timeout(s_terminal.c_str());
				}
			}
			
			t_check_hb_timeout = time(NULL);
		}
		
		if ( time(NULL) >= t_check_test_timeout + 60 )
		{
			DATASET dbresult;
			CNString sql;
			sql.Format("SELECT * from BUSSOP where (STATUS != 'X' and STATUS != 'Y') and INIVATE_TYPE = 'T' and '%s' >= TIMEOUT order by STARTTIME;", 
						time_format_str(time(NULL), 1).c_str());
			
			if ( DB1.db_select(sql.c_str(), dbresult, LOG6) > 0 )
			{
				//测试超时
				for ( int i=0; i<dbresult.size(); i++ )
				{
					LOG(LOG1, "DB 测试超时 terminal='%s', KQI='%s', s_bussopid='%s', tid='%s', timeout=%ds\n\n", 
							dbresult[i]["TERMINAL_ID"].c_str(), 
							dbresult[i]["KQI_TYPE"].c_str(), 
							dbresult[i]["BUSSOP_ID"].c_str(), 
							dbresult[i]["TID"].c_str(), 
							time_string_to_time_t(dbresult[i]["TIMEOUT"]) - time_string_to_time_t(dbresult[i]["STARTTIME"])
							);
					
					int i_rescode = 1;
					if ( dbresult[i]["STATUS"] == "W" ) i_rescode = 5001;
					
					appserver_dbupdate_bussop_error(dbresult[i]["BUSSOP_ID"].c_str(), i_rescode);
				}
			}
			
			t_check_test_timeout = time(NULL);
		}
	}

	_appserver_destroy();
	
	tcp_server1.Close();
	
	LOG(LOG1, "appserver: exit\n");
	return 0;
}
Пример #12
0
static int get_next_submodule(struct child_process *cp,
			      struct strbuf *err, void *data, void **task_cb)
{
	int ret = 0;
	struct submodule_parallel_fetch *spf = data;

	for (; spf->count < active_nr; spf->count++) {
		struct strbuf submodule_path = STRBUF_INIT;
		struct strbuf submodule_git_dir = STRBUF_INIT;
		struct strbuf submodule_prefix = STRBUF_INIT;
		const struct cache_entry *ce = active_cache[spf->count];
		const char *git_dir, *default_argv;
		const struct submodule *submodule;

		if (!S_ISGITLINK(ce->ce_mode))
			continue;

		submodule = submodule_from_path(null_sha1, ce->name);
		if (!submodule)
			submodule = submodule_from_name(null_sha1, ce->name);

		default_argv = "yes";
		if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
			if (submodule &&
			    submodule->fetch_recurse !=
						RECURSE_SUBMODULES_NONE) {
				if (submodule->fetch_recurse ==
						RECURSE_SUBMODULES_OFF)
					continue;
				if (submodule->fetch_recurse ==
						RECURSE_SUBMODULES_ON_DEMAND) {
					if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
						continue;
					default_argv = "on-demand";
				}
			} else {
				if ((config_fetch_recurse_submodules == RECURSE_SUBMODULES_OFF) ||
				    gitmodules_is_unmerged)
					continue;
				if (config_fetch_recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) {
					if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
						continue;
					default_argv = "on-demand";
				}
			}
		} else if (spf->command_line_option == RECURSE_SUBMODULES_ON_DEMAND) {
			if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
				continue;
			default_argv = "on-demand";
		}

		strbuf_addf(&submodule_path, "%s/%s", spf->work_tree, ce->name);
		strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
		strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name);
		git_dir = read_gitfile(submodule_git_dir.buf);
		if (!git_dir)
			git_dir = submodule_git_dir.buf;
		if (is_directory(git_dir)) {
			child_process_init(cp);
			cp->dir = strbuf_detach(&submodule_path, NULL);
			cp->env = local_repo_env;
			cp->git_cmd = 1;
			if (!spf->quiet)
				strbuf_addf(err, "Fetching submodule %s%s\n",
					    spf->prefix, ce->name);
			argv_array_init(&cp->args);
			argv_array_pushv(&cp->args, spf->args.argv);
			argv_array_push(&cp->args, default_argv);
			argv_array_push(&cp->args, "--submodule-prefix");
			argv_array_push(&cp->args, submodule_prefix.buf);
			ret = 1;
		}
		strbuf_release(&submodule_path);
		strbuf_release(&submodule_git_dir);
		strbuf_release(&submodule_prefix);
		if (ret) {
			spf->count++;
			return 1;
		}
	}
	return 0;
}