+static int execute_command(const gchar *command, const gchar *username,
+ const gchar *password, const gchar *lttd_path, const gchar *fac_path)
+{
+ pid_t pid;
+ int fdpty;
+ pid = forkpty(&fdpty, NULL, NULL, NULL);
+ int retval = 0;
+
+ if(pid > 0) {
+ /* parent */
+ gchar buf[256];
+ int status;
+ ssize_t count;
+ /* discuss with su */
+ struct timeval timeout;
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ struct pollfd pollfd;
+ int num_rdy;
+ int num_hup = 0;
+ enum read_state { GET_LINE, GET_SEMI, GET_SPACE } read_state = GET_LINE;
+
+ retval = fcntl(fdpty, F_SETFL, O_WRONLY);
+ if(retval == -1) {
+ perror("Error in fcntl");
+ goto wait_child;
+ }
+
+ /* Read the output from the child terminal before the prompt. If no data in
+ * 200 ms, we stop reading to give the password */
+ g_info("Reading from child console...");
+ while(1) {
+ pollfd.fd = fdpty;
+ pollfd.events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
+
+ num_rdy = poll(&pollfd, 1, -1);
+ if(num_rdy == -1) {
+ perror("Poll error");
+ goto wait_child;
+ }
+
+ /* Timeout : Stop waiting for chars */
+ if(num_rdy == 0) goto wait_child;
+
+ switch(pollfd.revents) {
+ case POLLERR:
+ g_warning("Error returned in polling fd\n");
+ num_hup++;
+ break;
+ case POLLHUP:
+ g_info("Polling FD : hung up.");
+ num_hup++;
+ break;
+ case POLLNVAL:
+ g_warning("Polling fd tells it is not open");
+ num_hup++;
+ break;
+ case POLLPRI:
+ case POLLIN:
+ count = read (fdpty, buf, 256);
+ if(count > 0) {
+ unsigned int i;
+ buf[count] = '\0';
+ g_printf("%s", buf);
+ for(i=0; i<count; i++) {
+ switch(read_state) {
+ case GET_LINE:
+ if(buf[i] == '\n') {
+ read_state = GET_SEMI;
+ g_debug("Tracecontrol input line skip\n");
+ }
+ break;
+ case GET_SEMI:
+ if(buf[i] == ':') {
+ g_debug("Tracecontrol input : marker found\n");
+ read_state = GET_SPACE;
+ }
+ break;
+ case GET_SPACE:
+ if(buf[i] == ' ') {
+ g_debug("Tracecontrol input space marker found\n");
+ goto write_password;
+ }
+ break;
+ }
+ }
+ } else if(count == -1) {
+ perror("Error in read");
+ goto wait_child;
+ }
+ break;
+ }
+ if(num_hup > 0) {
+ g_warning("Child hung up too fast");
+ goto wait_child;
+ }
+ }
+write_password:
+ fsync(fdpty);
+ pollfd.fd = fdpty;
+ pollfd.events = POLLOUT|POLLERR|POLLHUP|POLLNVAL;
+
+ num_rdy = poll(&pollfd, 1, -1);
+ if(num_rdy == -1) {
+ perror("Poll error");
+ goto wait_child;
+ }
+
+ /* Write the password */
+ g_info("Got su prompt, now writing password...");
+ int ret;
+ sleep(1);
+ ret = write(fdpty, password, strlen(password));
+ if(ret < 0) perror("Error in write");
+ ret = write(fdpty, "\n", 1);
+ if(ret < 0) perror("Error in write");
+ fsync(fdpty);
+ /* Take the output from the terminal and show it on the real console */
+ g_info("Getting data from child terminal...");
+ while(1) {
+ int num_hup = 0;
+ pollfd.fd = fdpty;
+ pollfd.events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
+
+ num_rdy = poll(&pollfd, 1, -1);
+ if(num_rdy == -1) {
+ perror("Poll error");
+ goto wait_child;
+ }
+ if(num_rdy == 0) break;
+
+ if(pollfd.revents & (POLLERR|POLLNVAL)) {
+ g_warning("Error returned in polling fd\n");
+ num_hup++;
+ }
+
+ if(pollfd.revents & (POLLIN|POLLPRI) ) {
+ count = read (fdpty, buf, 256);
+ if(count > 0) {
+ buf[count] = '\0';
+ printf("%s", buf);
+ } else if(count == -1) {
+ perror("Error in read");
+ goto wait_child;
+ }
+ }
+
+ if(pollfd.revents & POLLHUP) {
+ g_info("Polling FD : hung up.");
+ num_hup++;
+ }
+
+ if(num_hup > 0) goto wait_child;
+ }
+wait_child:
+ g_info("Waiting for child exit...");
+
+ ret = waitpid(pid, &status, 0);
+
+ if(ret == -1) {
+ g_warning("An error occured in wait : %s",
+ strerror(errno));
+ } else {
+ if(WIFEXITED(status))
+ if(WEXITSTATUS(status) != 0) {
+ retval = WEXITSTATUS(status);
+ g_warning("An error occured in the su command : %s",
+ strerror(retval));
+ }
+ }
+
+ g_info("Child exited.");
+
+ } else if(pid == 0) {
+ /* Setup environment variables */
+ if(strcmp(lttd_path, "") != 0)
+ setenv("LTT_DAEMON", lttd_path, 1);
+ if(strcmp(fac_path, "") != 0)
+ setenv("LTT_FACILITIES", fac_path, 1);
+
+ /* One comment line (must be only one) */
+ g_printf("Executing (as %s) : %s\n", username, command);
+
+ execlp("su", "su", "-p", "-c", command, username, NULL);
+ exit(-1); /* not supposed to happen! */
+
+ //gint ret = execvp();
+
+ } else {
+ /* error */
+ g_warning("Error happened when forking for su");
+ }
+
+ return retval;
+}
+
+