server: Lookup user only once.
[paraslash.git] / client.c
index f4a4ad50769cafcdd4ec0d0f0806e20b4ee13fcc..873edc163b3e5f5164307d647724cf6655ec0d5f 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 1997-2011 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1997-2013 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
-/** \file client.c the client program used to connect to para_server */
+/** \file client.c The client program used to connect to para_server. */
 
 #include <regex.h>
 #include <signal.h>
@@ -54,7 +54,7 @@ static void exec_pre_select(struct sched *s, struct task *t)
                sched_min_delay(s);
 }
 
-static void exec_post_select(__a_unused struct sched *s, struct task *t)
+static int exec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct exec_task *et = container_of(t, struct exec_task, task);
        struct btr_node *btrn = et->btrn;
@@ -63,10 +63,8 @@ static void exec_post_select(__a_unused struct sched *s, struct task *t)
        int ret;
 
        ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
-       if (ret <= 0) {
-               t->error = ret;
-               return;
-       }
+       if (ret <= 0)
+               return ret;
        sz = btr_next_buffer(btrn, &buf);
        if (sz <= 1)
                goto out;
@@ -76,6 +74,7 @@ static void exec_post_select(__a_unused struct sched *s, struct task *t)
        et->result_buf[et->result_size - 1] = '\0';
 out:
        btr_consume(btrn, sz);
+       return 0;
 }
 
 static int make_client_argv(const char *line)
@@ -114,11 +113,11 @@ static int execute_client_command(const char *cmd, char **result)
                goto out;
        schedule(&command_sched);
        *result = exec_task.result_buf;
-       btr_remove_node(exec_task.btrn);
+       btr_remove_node(&exec_task.btrn);
        client_disconnect(ct);
        ret = 1;
 out:
-       btr_free_node(exec_task.btrn);
+       btr_remove_node(&exec_task.btrn);
        if (ret < 0)
                free(exec_task.result_buf);
        return ret;
@@ -307,7 +306,7 @@ static void setatt_completer(struct i9e_completion_info *ci,
                free(orig);
        }
        sl[2 * num_atts] = NULL;
-       ret = i9e_extract_completions(ci->word, sl, &cr->matches);
+       i9e_extract_completions(ci->word, sl, &cr->matches);
 out:
        free(buf);
        free_argv(sl);
@@ -446,24 +445,17 @@ static int client_i9e_line_handler(char *line)
        int ret;
 
        client_disconnect(ct);
-       if (!line || !*line)
-               return 0;
-       PARA_DEBUG_LOG("line handler: %s\n", line);
+       PARA_DEBUG_LOG("line: %s\n", line);
        ret = make_client_argv(line);
-       if (ret < 0)
+       if (ret <= 0)
                return ret;
        ret = client_connect(ct, &sched, NULL, NULL);
        if (ret < 0)
                return ret;
-       i9e_attach_to_stdout(ct->btrn);
+       i9e_attach_to_stdout(ct->btrn[0]);
        return 1;
 }
 
-static void client_sighandler(int s)
-{
-       i9e_signal_dispatch(s);
-}
-
 static struct i9e_completer completers[] = {
        SERVER_COMPLETERS
        AFS_COMPLETERS
@@ -483,7 +475,7 @@ __noreturn static void interactive_session(void)
                .completers = completers,
        };
 
-       PARA_NOTICE_LOG("\n%s\n", VERSION_TEXT("client"));
+       PARA_NOTICE_LOG("\n%s\n", version_text("client"));
        if (ct->conf.history_file_given)
                history_file = para_strdup(ct->conf.history_file_arg);
        else {
@@ -494,7 +486,7 @@ __noreturn static void interactive_session(void)
        }
        ici.history_file = history_file;
 
-       act.sa_handler = client_sighandler;
+       act.sa_handler = i9e_signal_dispatch;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGINT, &act, NULL);
@@ -536,28 +528,37 @@ __noreturn static void print_completions(void)
 
 #endif /* HAVE_READLINE */
 
-static void supervisor_post_select(struct sched *s, struct task *t)
+struct supervisor_task {
+       bool stdout_task_started;
+       struct task task;
+};
+
+static int supervisor_post_select(struct sched *s, struct task *t)
 {
-       if (ct->task.error < 0) {
-               t->error = ct->task.error;
-               return;
+       struct supervisor_task *svt = container_of(t, struct supervisor_task,
+               task);
+
+       if (ct->task.error < 0)
+               return ct->task.error;
+       if (!svt->stdout_task_started && ct->status == CL_EXECUTING) {
+               stdout_set_defaults(&sot);
+               register_task(s, &sot.task);
+               svt->stdout_task_started = true;
+               return 1;
        }
        if (ct->status == CL_SENDING) {
                stdin_set_defaults(&sit);
                register_task(s, &sit.task);
-               t->error = -E_TASK_STARTED;
-               return;
-       }
-       if (ct->status == CL_RECEIVING) {
-               stdout_set_defaults(&sot);
-               register_task(s, &sot.task);
-               t->error = -E_TASK_STARTED; return;
+               return -E_TASK_STARTED;
        }
+       return 0;
 }
 
-static struct task svt = {
-       .post_select = supervisor_post_select,
-       .status = "supervisor task"
+static struct supervisor_task supervisor_task = {
+       .task = {
+               .post_select = supervisor_post_select,
+               .status = "supervisor task"
+       }
 };
 
 /**
@@ -601,21 +602,30 @@ int main(int argc, char *argv[])
         */
        sit.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "stdin"));
-       ret = client_open(argc, argv, &ct, &client_loglevel, sit.btrn, NULL, &sched);
+       ret = client_connect(ct, &sched, sit.btrn, NULL);
        if (ret < 0)
                goto out;
        sot.btrn = btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = "stdout", .parent = ct->btrn));
-       register_task(&sched, &svt);
+               EMBRACE(.name = "stdout", .parent = ct->btrn[0]));
+       register_task(&sched, &supervisor_task.task);
        ret = schedule(&sched);
+       if (ret >= 0 && ct->task.error < 0) {
+               switch(ct->task.error) {
+               /* these are not errors */
+               case -E_SERVER_CMD_SUCCESS:
+               case -E_EOF:
+               case -E_SERVER_EOF:
+               case -E_BTR_EOF:
+                       ret = 0;
+                       break;
+               default: ret = -E_SERVER_CMD_FAILURE;
+               }
+       }
 out:
+       if (ret < 0)
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        client_close(ct);
-       btr_free_node(sit.btrn);
-       btr_free_node(sot.btrn);
-       if (ret < 0) {
-               /* can not use PARA_LOG here because ct is NULL */
-               fprintf(stderr, "%s\n", para_strerror(-ret));
-               return EXIT_FAILURE;
-       }
-       return EXIT_SUCCESS;
+       btr_remove_node(&sit.btrn);
+       btr_remove_node(&sot.btrn);
+       return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }