Exemple #1
0
static void
notify_shutdown(void)
{
#if defined (BOARD_GPIO_BTN_PWR_CUT) && defined (BOARD_GPIO_BTN_PWR_INT)
	unsigned int i_button_value = BTN_PRESSED;

	if (cpu_gpio_get_pin(BOARD_GPIO_BTN_PWR_INT, &i_button_value) < 0)
		return;

	if (i_button_value == BTN_PRESSED)
		return;

	/* POWER button is released, shutdown now */
	cpu_gpio_irq_set(BOARD_GPIO_BTN_PWR_INT, 0, 0, 0);

	reset_signals();

	printf("Button POWER is released, shutdown system...\n");

	shutdown_router(2);

	printf("\nShutdown!\n\n");

	usleep(10000);

	sync();

	/* Power OFF */
	cpu_gpio_set_pin(BOARD_GPIO_BTN_PWR_CUT, 0);
#endif
}
Exemple #2
0
/* signals handling */
static void
catch_sig_fatal(int sig)
{
	sig_term_received = 1;

	printf("%s signal: %s\n", "fatal", strsignal(sig));

	if (sig == SIGQUIT) {
		shutdown_router(1);
		return;
	}

	reset_signals();

	shutdown_router(0);

	kill(-1, SIGTERM);
	sleep(1);
	sync();

	reboot(RB_AUTOBOOT);

	do {
		sleep(1);
	} while (1);
}
Exemple #3
0
static pid_t
run_shell(int timeout, int nowait)
{
	pid_t pid;
	char tz[128];
	char *envp[] = {
		"TERM=" CONSOLE_TERMINAL,
		"TERMINFO=/usr/share/terminfo",
		"PATH=" SYS_EXEC_PATH,
		"SHELL=" SYS_SHELL,
		"USER="******"HOME=" INIT_HOME_PATH,
		tz,
		NULL
	};

	/* Wait for user input */
//	if (waitfor (STDIN_FILENO, timeout) <= 0)
//		return 0;

	switch ((pid = fork())) {
	case -1:
		perror("fork");
		return 0;
	case 0:
		/* Reset signal handlers set for parent process */
		reset_signals();

		/* Reopen console */
		init_console();

		/* Pass on TZ */
		time_zone_x_mapping();
		snprintf(tz, sizeof(tz), "TZ=%s", nvram_safe_get("time_zone_x"));

		/* Now run it.  The new program will take over this PID, 
		 * so nothing further in init.c should be run. */
		execve(SYS_SHELL, (char *[]) { SYS_SHELL, NULL }, envp);

		/* We're still here?  Some error happened. */
		perror(SYS_SHELL);
		exit(errno);
	default:
		if (nowait)
			return pid;
		else {
			waitpid(pid, NULL, 0);
			return 0;
		}
	}
int lookup_mount(const char *root, const char *name, int name_len, void *context)
{
	struct lookup_context *ctxt = (struct lookup_context *) context;
	char *mapent, *mapp, *tmp;
	char errbuf[1024], *errp;
	char ch;
	int pipefd[2], epipefd[2];
	pid_t f;
	int files_left;
	int status;
	fd_set readfds, ourfds;
	enum state { st_space, st_map, st_done } state;
	int quoted = 0;
	int ret = 1;
	int max_fd;
	int distance;
	int alloci = 1;

	debug(MODPREFIX "looking up %s", name);

	mapent = (char *)malloc(MAPENT_MAX_LEN + 1);
	if (!mapent) {
		error(MODPREFIX "malloc: %s\n", strerror(errno));
		return 1;
	}

	/*
	 * We don't use popen because we don't want to run /bin/sh plus we
	 * want to send stderr to the syslog, and we don't use spawnl()
	 * because we need the pipe hooks
	 */

	if (pipe(pipefd)) {
		error(MODPREFIX "pipe: %m");
		goto out_free;
	}
	if (pipe(epipefd)) {
		close(pipefd[0]);
		close(pipefd[1]);
		goto out_free;
	}

	f = fork();
	if (f < 0) {
		close(pipefd[0]);
		close(pipefd[1]);
		close(epipefd[0]);
		close(epipefd[1]);
		error(MODPREFIX "fork: %m");
		goto out_free;
	} else if (f == 0) {
		reset_signals();
		close(pipefd[0]);
		close(epipefd[0]);
		dup2(pipefd[1], STDOUT_FILENO);
		dup2(epipefd[1], STDERR_FILENO);
		close(pipefd[1]);
		close(epipefd[1]);
		execl(ctxt->mapname, ctxt->mapname, name, NULL);
		_exit(255);	/* execl() failed */
	}
	close(pipefd[1]);
	close(epipefd[1]);

	mapp = mapent;
	errp = errbuf;
	state = st_space;

	FD_ZERO(&ourfds);
	FD_SET(pipefd[0], &ourfds);
	FD_SET(epipefd[0], &ourfds);

	max_fd = pipefd[0] > epipefd[0] ? pipefd[0] : epipefd[0];

	files_left = 2;

	while (files_left != 0) {
		readfds = ourfds;
		if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0 && errno != EINTR)
			break;

		/* Parse maps from stdout */
		if (FD_ISSET(pipefd[0], &readfds)) {
			if (read(pipefd[0], &ch, 1) < 1) {
				FD_CLR(pipefd[0], &ourfds);
				files_left--;
				state = st_done;
			}

			if (!quoted && ch == '\\') {
				quoted = 1;
				continue;
			}

			switch (state) {
			case st_space:
				if (quoted || !isspace(ch)) {
					*mapp++ = ch;
					state = st_map;
				}
				break;
			case st_map:
				if (!quoted && ch == '\n') {
					*mapp = '\0';
					state = st_done;
					break;
				}

				/* We overwrite up to 3 characters, so we
				 * need to make sure we have enough room
				 * in the buffer for this. */
				/* else */
				if (mapp - mapent > 
				    ((MAPENT_MAX_LEN+1) * alloci) - 3) {
					/*
					 * Alloc another page for map entries.
					 */
					distance = mapp - mapent;
					tmp = realloc(mapent,
						      ((MAPENT_MAX_LEN + 1) * 
						       ++alloci));
					if (!tmp) {
						alloci--;
						error(MODPREFIX "realloc: %s\n",
						      strerror(errno));
						break;
					}
					mapent = tmp;
					mapp = tmp + distance;
				}
				/* 
				 * Eat \ quoting \n, otherwise pass it
				 * through for the parser
				 */
				if (quoted) {
					if (ch == '\n')
						*mapp++ = ' ';
					else {
						*mapp++ = '\\';
						*mapp++ = ch;
					}
				} else
					*mapp++ = ch;
				break;
			case st_done:
				/* Eat characters till there's no more output */
				break;
			}
		}
		quoted = 0;

		/* Deal with stderr */
		if (FD_ISSET(epipefd[0], &readfds)) {
			if (read(epipefd[0], &ch, 1) < 1) {
				FD_CLR(epipefd[0], &ourfds);
				files_left--;
			} else if (ch == '\n') {
				*errp = '\0';
				if (errbuf[0])
					error(">> %s", errbuf);
				errp = errbuf;
			} else {
				if (errp >= &errbuf[1023]) {
					*errp = '\0';
					error(">> %s", errbuf);
					errp = errbuf;
				}
				*(errp++) = ch;
			}
		}
	}

	if (mapp)
		*mapp = '\0';
	if (errp > errbuf) {
		*errp = '\0';
		error(">> %s", errbuf);
	}

	close(pipefd[0]);
	close(epipefd[0]);

	if (waitpid(f, &status, 0) != f) {
		error(MODPREFIX "waitpid: %m");
		goto out_free;
	}

	if (mapp == mapent || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
		error(MODPREFIX "lookup for %s failed", name);
		goto out_free;
	}

	debug(MODPREFIX "%s -> %s", name, mapent);

	ret = ctxt->parse->parse_mount(root, name, name_len,
				       mapent, ctxt->parse->context);
out_free:
	free(mapent);
	return ret;
}
Exemple #5
0
int init_cgi(request * req)
{
#ifndef EXCLUDE_CGI
    int child_pid;
    int pipes[2];
    int use_pipes = 0;
#endif

    SQUASH_KA(req);

#ifndef EXCLUDE_CGI
    if (req->cgi_type) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
    DEBUG(DEBUG_CGI_ENV) {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            log_error_time();
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }

    /* we want to use pipes whenever it's a CGI or directory */
    /* otherwise (NPH, gunzip) we want no pipes */
    if (req->cgi_type == CGI ||
        (!req->cgi_type &&
         (req->pathname[strlen(req->pathname) - 1] == '/'))) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_doc(req);
            perror("pipe");
            return 0;
        }

        /* set the read end of the socket to non-blocking */
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch (child_pid) {
    case -1:
        /* fork unsuccessful */
        /* FIXME: There is a problem here. send_r_error (called by
         * boa_perror) would work for NPH and CGI, but not for GUNZIP.  
         * Fix that. 
         */
        boa_perror(req, "fork failed");
        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        return 0;
        break;
    case 0:
        /* child */
        reset_signals();

        if (req->cgi_type == CGI || req->cgi_type == NPH) {
            char *c;
            unsigned int l;
            char *newpath, *oldpath;

            c = strrchr(req->pathname, '/');
            if (!c) {
                /* there will always be a '.' */
                log_error_doc(req);
                fprintf(stderr,
                        "unable to find '/' in req->pathname: \"%s\"\n",
                        req->pathname);
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            *c = '\0';

            if (chdir(req->pathname) != 0) {
                int saved_errno = errno;
                log_error_doc(req);
                fprintf(stderr, "Could not chdir to \"%s\":",
                        req->pathname);
                errno = saved_errno;
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            oldpath = req->pathname;
            req->pathname = ++c;
            l = strlen(req->pathname) + 3;
            /* prefix './' */
            newpath = malloc(sizeof (char) * l);
            if (!newpath) {
                /* there will always be a '.' */
                log_error_doc(req);
                perror("unable to malloc for newpath");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }
            newpath[0] = '.';
            newpath[1] = '/';
            memcpy(&newpath[2], req->pathname, l - 2); /* includes the trailing '\0' */
            free(oldpath);
            req->pathname = newpath;
        }
        if (use_pipes) {
            /* close the 'read' end of the pipes[] */
            close(pipes[0]);
            /* tie CGI's STDOUT to our write end of pipe */
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - pipes");
                _exit(EXIT_FAILURE);
            }
            close(pipes[1]);
        } else {
            /* tie stdout to socket */
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - fd");
                _exit(EXIT_FAILURE);
            }
            close(req->fd);
        }
        /* Switch socket flags back to blocking */
        if (set_block_fd(STDOUT_FILENO) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            _exit(EXIT_FAILURE);
        }
        /* tie post_data_fd to POST stdin */
        if (req->method == M_POST) { /* tie stdin to file */
// davidhsu ----------------------
#ifndef NEW_POST
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
#endif
//-------------------------------	
			
        }

#ifdef USE_SETRLIMIT
        /* setrlimit stuff.
         * This is neat!
         * RLIMIT_STACK    max stack size
         * RLIMIT_CORE     max core file size
         * RLIMIT_RSS      max resident set size
         * RLIMIT_NPROC    max number of processes
         * RLIMIT_NOFILE   max number of open files
         * RLIMIT_MEMLOCK  max locked-in-memory address space
         * RLIMIT_AS       address space (virtual memory) limit
         *
         * RLIMIT_CPU      CPU time in seconds
         * RLIMIT_DATA     max data size
         *
         * Currently, we only limit the CPU time and the DATA segment
         * We also "nice" the process.
         *
         * This section of code adapted from patches sent in by Steve Thompson
         * (no email available)
         */

        {
            struct rlimit rl;
            int retval;

            if (cgi_rlimit_cpu) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_cpu;
                retval = setrlimit(RLIMIT_CPU, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_CPU,%d): %s\n",
                            rlimit_cpu, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_limit_data) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_data;
                retval = setrlimit(RLIMIT_DATA, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_DATA,%d): %s\n",
                            rlimit_data, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_nice) {
                retval = nice(cgi_nice);
                if (retval == -1) {
                    log_error_time();
                    perror("nice");
                    _exit(EXIT_FAILURE);
                }
            }
        }
#endif

        umask(cgi_umask);       /* change umask *again* u=rwx,g=rxw,o= */

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tie STDERR (current log_error) to cgi_log_fd,
         *  then we ought to tie it to /dev/null
         *  FIXME: we currently don't tie it to /dev/null, we leave it
         *  tied to whatever 'error_log' points to.  This means CGIs can
         *  scribble on the error_log, probably a bad thing.
         */
        if (cgi_log_fd) {
            dup2(cgi_log_fd, STDERR_FILENO);
        }

        if (req->cgi_type) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      (void *) NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, (void *) NULL);
#endif
        }
        /* execve failed */
        log_error_doc(req);
        fprintf(stderr, "Unable to execve/execl pathname: \"%s\"",
                req->pathname);
        perror("");
        _exit(EXIT_FAILURE);
        break;

    default:
        /* parent */
        /* if here, fork was successful */
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {

// davidhsu ----------------
#ifndef NEW_POST
             close(req->post_data_fd); /* child closed it too */
             req->post_data_fd = 0;
#else			 
		if (req->post_data) {
			free(req->post_data);
			req->post_data = NULL;
		}
		req->post_data_len = 0;
		req->post_data_idx = 0;
#endif		
//------------------------

        }

        /* NPH, GUNZIP, etc... all go straight to the fd */
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->cgi_type == CGI) {
            req->cgi_status = CGI_PARSE; /* got to parse cgi header */
            /* for cgi_header... I get half the buffer! */
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            /* I get all the buffer! */
            req->header_line = req->header_end = req->buffer;
        }

        /* reset req->filepos for logging (it's used in pipe.c) */
        /* still don't know why req->filesize might be reset though */
        req->filepos = 0;
        break;
    }
#endif //!EXCLUDE_CGI

    return 1;
}
Exemple #6
0
/*
 * Interrupt handler.  Stop curses and exit gracefully.
 */
void cleanup_sig(int sig)
{
#ifdef IGNORE_CTRL_C
    if (sig == SIGINT) {
	/*
	 * Need to rearm the signal.
	 */
#ifdef DJGPP
	if (wathndlcbrk) {
	    sig_handler_watt(sig);	/* Use WATT-32 signal handler */
	}
#endif /* DJGPP */
	signal(SIGINT, cleanup_sig);
	sigint = TRUE;
#ifdef DJGPP
	_eth_release();
	_eth_init();
#endif /* DJGPP */
	return;
    }
#endif /* IGNORE_CTRL_C */

#ifdef VMS
    if (!dump_output_immediately) {
	int c;

	/*
	 * Reassert the AST.
	 */
	(void) signal(SIGINT, cleanup_sig);
	if (!LYCursesON)
	    return;

	/*
	 * Refresh screen to get rid of "cancel" message, then query.
	 */
	lynx_force_repaint();
	LYrefresh();

	/*
	 * Ask if exit is intended.
	 */
	if (LYQuitDefaultYes == TRUE) {
	    c = HTConfirmDefault(REALLY_EXIT, YES);
	} else {
	    c = HTConfirmDefault(REALLY_EXIT, NO);
	}
	HadVMSInterrupt = TRUE;
	if (LYQuitDefaultYes == TRUE) {
	    if (c == NO) {
		return;
	    }
	} else if (c != YES) {
	    return;
	}
    }
#endif /* VMS */

    /*
     * Ignore further interrupts.  - mhc:  11/2/91
     */
#ifndef NOSIGHUP
    (void) signal(SIGHUP, SIG_IGN);
#endif /* NOSIGHUP */

#ifdef VMS
    /*
     * Use ttclose() from cleanup() for VMS if not dumping.
     */
    if (dump_output_immediately)
#else /* Unix: */
    (void) signal(SIGINT, SIG_IGN);
#endif /* VMS */

    (void) signal(SIGTERM, SIG_IGN);

    if (traversal)
	dump_traversal_history();

#ifndef NOSIGHUP
    if (sig != SIGHUP) {
#endif /* NOSIGHUP */

	if (!dump_output_immediately) {
	    /*
	     * cleanup() also calls cleanup_files().
	     */
	    cleanup();
	}
	if (sig != 0) {
	    SetOutputMode(O_TEXT);
	    printf("\n\n%s %d\n\n",
		   gettext("Exiting via interrupt:"),
		   sig);
	    fflush(stdout);
	}
#ifndef NOSIGHUP
    } else {
	cleanup_files();
    }
#endif /* NOSIGHUP */

    if (sig != 0) {
	exit_immediately(EXIT_SUCCESS);
    } else {
	reset_signals();
    }
}
static int fdt_spawn_connection(server *srv,
				 fdt_server *s_server) {

	int status;
	struct timeval tv = { 0, 100 * 1000 };
	struct sockaddr_un fdt_addr_un;
	struct sockaddr *fdt_addr;

	socklen_t servlen;

	if (buffer_is_empty(s_server->unixsocket)) {
		log_error_write(srv, __FILE__, __LINE__, "s",
			"Socket path missing");
		return -1;
	}

	memset(&fdt_addr, 0, sizeof(fdt_addr));

	fdt_addr_un.sun_family = AF_UNIX;
	strcpy(fdt_addr_un.sun_path, s_server->unixsocket->ptr);

	servlen = s_server->unixsocket->used + sizeof(fdt_addr_un.sun_family);
	fdt_addr = (struct sockaddr *) &fdt_addr_un;

	/** We first try to connect to the backend to see if it is already present or not. If it is present then we do not need to fork that process*/
	if (-1 == (s_server->fdt_sfd = socket(AF_UNIX, SOCK_STREAM, 0))) {
		log_error_write(srv, __FILE__, __LINE__, "ss",
				"failed:", strerror(errno));
		return -1;
	}

	if (-1 == connect(s_server->fdt_sfd, fdt_addr, servlen)) {
		/* server is not up, spawn it  */
		log_error_write(srv, __FILE__, __LINE__, "sb",
			"spawning a new fdt proc, socket:", s_server->unixsocket);

		pid_t child;
		int val;

		if (errno != ENOENT &&
		    !buffer_is_empty(s_server->unixsocket)) {
			unlink(s_server->unixsocket->ptr);
		}

		close(s_server->fdt_sfd);

		/** here we create a socket bind to address and then go in listen state. Reason behind this is that the server process is ideally suppose to start and then listen on this socket but it so happens that there is a race condition that lighttpd does connect before the child could do listen so in that case connect fails 2nd time so the best way to do is do the listen in parent itself and then do fork and then after fork in child process that listen socket will still be open. While in parent process we can close that socket and  reopen it again and do connect*/
		/* reopen socket */
		if (-1 == (s_server->fdt_sfd = socket(AF_UNIX, SOCK_STREAM, 0))) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
				"socket failed:", strerror(errno));
			return -1;
		}

		val = 1;
		if (setsockopt(s_server->fdt_sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
					"socketsockopt failed:", strerror(errno));
			return -1;
		}

		/* create socket */
		if (-1 == bind(s_server->fdt_sfd, fdt_addr, servlen)) {
			log_error_write(srv, __FILE__, __LINE__, "sbs",
				"bind failed for:",
				s_server->service_name,
				strerror(errno));
			return -1;
		}

		if (-1 == listen(s_server->fdt_sfd, 1024)) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
				"listen failed:", strerror(errno));
			return -1;
		}

		switch ((child = fork())) {
		case 0: {

			size_t i = 0;
			char *c;
			char_array env;
			char_array arg;

			/* create environment */
			env.ptr = NULL;
			env.size = 0;
			env.used = 0;

			arg.ptr = NULL;
			arg.size = 0;
			arg.used = 0;

/** build clean enviornment basically says what all environ variables do you want to copy from the environ of the lighttpd and pass it to child process. Currently we dont need this right now but we mihgt need it later on
			// build clean environment 
			if (s_server->bin_env_copy->used) {
				for (i = 0; i < s_server->bin_env_copy->used; i++) {
					data_string *ds = (data_string *)s_server->bin_env_copy->data[i];
					char *ge;

					if (NULL != (ge = getenv(ds->value->ptr))) {
						env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
					}
				}
			} else {
				for (i = 0; environ[i]; i++) {
					char *eq;

					if (NULL != (eq = strchr(environ[i], '='))) {
						env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
					}
				}
			}*/

			for (i = 0; environ[i]; i++) {
				char *eq;

				if (NULL != (eq = strchr(environ[i], '='))) {
					env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
				}
			}

			/* create environment */
			for (i = 0; i < s_server->bin_env->used; i++) {
				data_string *ds = (data_string *)s_server->bin_env->data[i];

				env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
			}

			/** The socket file descirtor handle is passed in environmental variables to the client.*/
			char *env_key = calloc(1, sizeof(char)*10);
			char *env_value = calloc(1, sizeof(char)*4);

			memcpy(env_key, "SOCKET_FD", 9);
			sprintf(env_value,"%d", s_server->fdt_sfd);
			env_add(&env, env_key, 9, env_value, strlen(env_value));

/*			log_error_write(srv, __FILE__, __LINE__, "ss",
					"socket fd in child process is", env_value);*/
			free(env_key);
			free(env_value);

			env.ptr[env.used] = NULL;

			parse_binpath(&arg, s_server->bin_path);

			/* chdir into the base of the bin-path,
			 * search for the last / */
			if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
				*c = '\0';

				/* change to the physical directory */
				if (-1 == chdir(arg.ptr[0])) {
					*c = '/';
					log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]);
				}
				*c = '/';
			}

			reset_signals();

			/* exec the fdt process */
			execve(arg.ptr[0], arg.ptr, env.ptr);

			log_error_write(srv, __FILE__, __LINE__, "sbs",
					"execve failed for:", s_server->bin_path, strerror(errno)); 

			exit(errno);

			break;
		}
		case -1:
			/* error */
			break;
		default:
			/* father */

			/* wait */
			select(0, NULL, NULL, NULL, &tv);

			switch (waitpid(child, &status, WNOHANG)) {
			case 0:
				/* child still running after timeout, good */
				break;
			case -1:
				/* no PID found ? should never happen */
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"pid not found:", strerror(errno));
				return -1;
			default:
				log_error_write(srv, __FILE__, __LINE__, "sbs",
						"the fdt-transfer-backend", s_server->bin_path, "failed to start:");
				/* the child should not terminate at all */
				if (WIFEXITED(status)) {
					log_error_write(srv, __FILE__, __LINE__, "sdb",
							"child exited with status",
							WEXITSTATUS(status), s_server->bin_path);
				} else if (WIFSIGNALED(status)) {
					log_error_write(srv, __FILE__, __LINE__, "sd",
							"terminated by signal:",
							WTERMSIG(status));

					if (WTERMSIG(status) == 11) {
						log_error_write(srv, __FILE__, __LINE__, "s",
								"to be exact: it segfaulted, crashed, died, ... you get the idea." );
					}
				} else {
					log_error_write(srv, __FILE__, __LINE__, "sd",
							"child died somehow:",
							status);
				}
				return -1;
			}

			/* register process */
			s_server->pid = child;

			close(s_server->fdt_sfd);

			/* reopen socket */
			if (-1 == (s_server->fdt_sfd = socket(AF_UNIX, SOCK_STREAM, 0))) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
					"socket failed:", strerror(errno));
				return -1;
			}
	
			if (-1 == connect(s_server->fdt_sfd, fdt_addr, servlen)) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
					"connect failed 2nd time This should never happen:", strerror(errno));
				return -1;
			}

			fdevent_register(srv->ev, s_server->fdt_sfd, fdt_handle_fdevent, s_server);
			if (-1 == fdevent_fcntl_set(srv->ev, s_server->fdt_sfd)) {
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"fcntl failed:", strerror(errno));
	
				return HANDLER_ERROR;
			}

			fdevent_event_set(srv->ev, NULL, s_server->fdt_sfd, FDEVENT_HUP);

			break;
		}
	} else {
		s_server->pid = 0;

		log_error_write(srv, __FILE__, __LINE__, "sb",
				"(debug) socket is already used; won't spawn:",
				s_server->service_name);
	}

	s_server->state = PROC_STATE_RUNNING;

	return 0;
}