X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=client.c;h=bc5132b6ffe620558f78f390eba70ebad6faae59;hp=56e7cc5c538939323cec4ba4b4ff62df018538d1;hb=d4603bf234d23adb56b208efb90ce66772c4ef5b;hpb=e58586b7395a84e5883b077d89b92c8ac649a1f2 diff --git a/client.c b/client.c index 56e7cc5c..bc5132b6 100644 --- a/client.c +++ b/client.c @@ -1,19 +1,16 @@ -/* - * Copyright (C) 1997-2014 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 1997 Andre Noll , see file COPYING. */ /** \file client.c The client program used to connect to para_server. */ #include #include +#include +#include "client.lsg.h" #include "para.h" #include "list.h" #include "sched.h" #include "crypt.h" -#include "client.cmdline.h" #include "string.h" #include "stdin.h" #include "stdout.h" @@ -22,7 +19,8 @@ #include "error.h" #include "version.h" -INIT_CLIENT_ERRLISTS; +/** Array of error strings. */ +DEFINE_PARA_ERRLIST; static struct sched sched; static struct client_task *ct; @@ -35,28 +33,27 @@ __printf_2_3 void (*para_log)(int, const char*, ...) = stderr_log; #ifdef HAVE_READLINE #include "interactive.h" -#include "server_completion.h" -#include "afs_completion.h" +#include "server_cmd.lsg.h" struct exec_task { - struct task task; + struct task *task; struct btr_node *btrn; char *result_buf; size_t result_size; }; -static void exec_pre_select(struct sched *s, struct task *t) +static void exec_pre_select(struct sched *s, void *context) { - struct exec_task *et = container_of(t, struct exec_task, task); + struct exec_task *et = context; int ret = btr_node_status(et->btrn, 0, BTR_NT_LEAF); if (ret != 0) sched_min_delay(s); } -static int exec_post_select(__a_unused struct sched *s, struct task *t) +static int exec_post_select(__a_unused struct sched *s, void *context) { - struct exec_task *et = container_of(t, struct exec_task, task); + struct exec_task *et = context; struct btr_node *btrn = et->btrn; char *buf; size_t sz; @@ -77,41 +74,81 @@ out: return 0; } -static int make_client_argv(const char *line) +/* Called from the line handler and the completers. This overwrites ct->lpr. */ +static int create_merged_lpr(const char *line) { - int ret; + const struct lls_command *cmd = CLIENT_CMD_PTR; + int argc, ret; + char *cmdline, **argv, *errctx; + struct lls_parse_result *argv_lpr; + static struct lls_parse_result *orig_lpr; - free_argv(ct->conf.inputs); - ret = create_argv(line, " ", &ct->conf.inputs); - if (ret >= 0) - ct->conf.inputs_num = ret; + if (!orig_lpr) + orig_lpr = ct->lpr; + ct->lpr = NULL; + cmdline = make_message("-- %s", line); + ret = create_shifted_argv(cmdline, " ", &argv); + free(cmdline); + if (ret < 0) + return ret; + argc = ret; + if (argc == 2) { /* no words (only blanks in line) */ + free_argv(argv); + return 0; + } + argv[0] = para_strdup("--"); + /* + * The original lpr for the interactive session has no non-option + * arguments. We create a fresh lpr from the words in "line" and merge + * it with the orignal lpr. + */ + ret = lls(lls_parse(argc, argv, cmd, &argv_lpr, &errctx)); + free_argv(argv); + if (ret < 0) + goto fail; + ret = lls(lls_merge(orig_lpr, argv_lpr, cmd, &ct->lpr, &errctx)); + lls_free_parse_result(argv_lpr, cmd); + if (ret < 0) + goto fail; + return 1; +fail: + if (errctx) + PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + free(errctx); + assert(ret < 0); return ret; } +/* called from completers */ static int execute_client_command(const char *cmd, char **result) { int ret; struct sched command_sched = {.default_timeout = {.tv_sec = 1}}; struct exec_task exec_task = { - .task = { - .pre_select = exec_pre_select, - .post_select = exec_post_select, - .status = "client exec task", - }, .result_buf = para_strdup(""), .result_size = 1, }; + struct lls_parse_result *old_lpr = ct->lpr; + *result = NULL; - ret = make_client_argv(cmd); - if (ret < 0) + ret = create_merged_lpr(cmd); + if (ret <= 0) goto out; exec_task.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "exec_collect")); - register_task(&command_sched, &exec_task.task); + exec_task.task = task_register(&(struct task_info) { + .name = "client exec", + .pre_select = exec_pre_select, + .post_select = exec_post_select, + .context = &exec_task, + }, &command_sched); ret = client_connect(ct, &command_sched, NULL, exec_task.btrn); if (ret < 0) goto out; schedule(&command_sched); + sched_shutdown(&command_sched); + lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR); + ct->lpr = old_lpr; *result = exec_task.result_buf; btr_remove_node(&exec_task.btrn); ret = 1; @@ -172,7 +209,7 @@ static void complete_lsblob(const char *blob_type, struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-i", "-l", "-r", NULL}; + char *opts[] = {LSG_SERVER_CMD_LSIMG_OPTS, NULL}; if (ci->word[0] == '-') return i9e_complete_option(opts, ci, cr); @@ -203,24 +240,36 @@ I9E_DUMMY_COMPLETER(pause); I9E_DUMMY_COMPLETER(play); I9E_DUMMY_COMPLETER(si); I9E_DUMMY_COMPLETER(term); -I9E_DUMMY_COMPLETER(version); I9E_DUMMY_COMPLETER(stop); I9E_DUMMY_COMPLETER(addatt); I9E_DUMMY_COMPLETER(init); +I9E_DUMMY_COMPLETER(tasks); static struct i9e_completer completers[]; static void help_completer(struct i9e_completion_info *ci, - struct i9e_completion_result *result) + struct i9e_completion_result *cr) { - result->matches = i9e_complete_commands(ci->word, completers); + char *opts[] = {LSG_SERVER_CMD_HELP_OPTS, NULL}; + + if (ci->word[0] == '-') { + i9e_complete_option(opts, ci, cr); + return; + } + cr->matches = i9e_complete_commands(ci->word, completers); } static void stat_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-n=", "-p", NULL}; - //PARA_CRIT_LOG("word: %s\n", ci->word); + char *opts[] = {LSG_SERVER_CMD_STAT_OPTS, NULL}; + i9e_complete_option(opts, ci, cr); +} + +static void version_completer(struct i9e_completion_info *ci, + struct i9e_completion_result *cr) +{ + char *opts[] = {LSG_SERVER_CMD_VERSION_OPTS, NULL}; i9e_complete_option(opts, ci, cr); } @@ -257,7 +306,7 @@ static void sender_completer(struct i9e_completion_info *ci, static void add_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-a", "-l", "-f", "-v", "--", NULL}; + char *opts[] = {LSG_SERVER_CMD_ADD_OPTS, NULL}; if (ci->word[0] == '-') i9e_complete_option(opts, ci, cr); @@ -267,11 +316,7 @@ static void add_completer(struct i9e_completion_info *ci, static void ls_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = { - "--", "-l", "-ls", "-ll", "-lv", "-lp", "-lm", "-lc", "-p", - "-a", "-r", "-d", "-sp", "-sl", "-ss", "-sn", "-sf", "-sc", - "-si", "-sy", "-sb", "-sd", "-sa", NULL - }; + char *opts[] = {LSG_SERVER_CMD_LS_OPTS, NULL}; if (ci->word[0] == '-') i9e_complete_option(opts, ci, cr); cr->filename_completion_desired = true; @@ -314,12 +359,8 @@ out: static void lsatt_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-i", "-l", "-r", NULL}; - - if (ci->word[0] == '-') - i9e_complete_option(opts, ci, cr); - else - complete_attributes(ci->word, &cr->matches); + char *opts[] = {LSG_SERVER_CMD_LSATT_OPTS, NULL}; + i9e_complete_option(opts, ci, cr); } static void mvatt_completer(struct i9e_completion_info *ci, @@ -337,14 +378,14 @@ static void rmatt_completer(struct i9e_completion_info *ci, static void check_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-a", "-m", "-p", NULL}; + char *opts[] = {LSG_SERVER_CMD_CHECK_OPTS, NULL}; i9e_complete_option(opts, ci, cr); } static void rm_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-v", "-f", "-p", NULL}; + char *opts[] = {LSG_SERVER_CMD_RM_OPTS, NULL}; if (ci->word[0] == '-') { i9e_complete_option(opts, ci, cr); @@ -356,7 +397,7 @@ static void rm_completer(struct i9e_completion_info *ci, static void touch_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-n=", "-l=", "-y=", "-i=", "-a=", "-v", "-p", NULL}; + char *opts[] = {LSG_SERVER_CMD_TOUCH_OPTS, NULL}; if (ci->word[0] == '-') i9e_complete_option(opts, ci, cr); @@ -366,7 +407,7 @@ static void touch_completer(struct i9e_completion_info *ci, static void cpsi_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { - char *opts[] = {"-a", "-y", "-i", "-l", "-n", "-v", NULL}; + char *opts[] = {LSG_SERVER_CMD_CPSI_OPTS, NULL}; if (ci->word[0] == '-') i9e_complete_option(opts, ci, cr); @@ -442,9 +483,13 @@ DEFINE_BLOB_COMPLETER(mv, pl) static int client_i9e_line_handler(char *line) { int ret; + static bool first = true; - PARA_DEBUG_LOG("line: %s\n", line); - ret = make_client_argv(line); + if (first) + first = false; + else + lls_free_parse_result(ct->lpr, CLIENT_CMD_PTR); + ret = create_merged_lpr(line); if (ret <= 0) return ret; ret = client_connect(ct, &sched, NULL, NULL); @@ -455,15 +500,16 @@ static int client_i9e_line_handler(char *line) } static struct i9e_completer completers[] = { - SERVER_COMPLETERS - AFS_COMPLETERS +#define LSG_SERVER_CMD_CMD(_name) {.name = #_name, \ + .completer = _name ## _completer} + LSG_SERVER_CMD_SUBCOMMANDS +#undef LSG_SERVER_CMD_CMD {.name = NULL} }; __noreturn static void interactive_session(void) { int ret; - char *history_file; struct sigaction act; struct i9e_client_info ici = { .fds = {0, 1, 2}, @@ -474,16 +520,15 @@ __noreturn static void interactive_session(void) }; PARA_NOTICE_LOG("\n%s\n", version_text("client")); - if (ct->conf.history_file_given) - history_file = para_strdup(ct->conf.history_file_arg); + if (CLIENT_OPT_GIVEN(HISTORY_FILE, ct->lpr)) + ici.history_file = para_strdup(CLIENT_OPT_STRING_VAL( + HISTORY_FILE, ct->lpr)); else { char *home = para_homedir(); - history_file = make_message("%s/.paraslash/client.history", + ici.history_file = make_message("%s/.paraslash/client.history", home); free(home); } - ici.history_file = history_file; - act.sa_handler = i9e_signal_dispatch; sigemptyset(&act.sa_mask); act.sa_flags = 0; @@ -495,6 +540,7 @@ __noreturn static void interactive_session(void) goto out; para_log = i9e_log; ret = schedule(&sched); + sched_shutdown(&sched); i9e_close(); para_log = stderr_log; out: @@ -506,7 +552,9 @@ out: __noreturn static void print_completions(void) { - int ret = i9e_print_completions(completers); + int ret; + + ret = i9e_print_completions(completers); exit(ret <= 0? EXIT_FAILURE : EXIT_SUCCESS); } @@ -528,16 +576,16 @@ __noreturn static void print_completions(void) struct supervisor_task { bool stdout_task_started; - struct task task; + struct task *task; }; -static int supervisor_post_select(struct sched *s, struct task *t) +static int supervisor_post_select(struct sched *s, void *context) { - struct supervisor_task *svt = container_of(t, struct supervisor_task, - task); + struct supervisor_task *svt = context; + int ret = task_status(ct->task); - if (ct->task.error < 0) - return ct->task.error; + if (ret < 0) + return ret; if (!svt->stdout_task_started && ct->status == CL_EXECUTING) { stdout_task_register(&sot, s); svt->stdout_task_started = true; @@ -550,12 +598,7 @@ static int supervisor_post_select(struct sched *s, struct task *t) return 0; } -static struct supervisor_task supervisor_task = { - .task = { - .post_select = supervisor_post_select, - .status = "supervisor task" - } -}; +static struct supervisor_task supervisor_task; /** * The client program to connect to para_server. @@ -574,7 +617,8 @@ static struct supervisor_task supervisor_task = { * * \return EXIT_SUCCESS or EXIT_FAILURE * - * \sa client_open(), stdin.c, stdout.c, para_client(1), para_server(1) + * \sa \ref client_open(), \ref stdin.c, \ref stdout.c, para_client(1), + * para_server(1). */ int main(int argc, char *argv[]) { @@ -586,7 +630,7 @@ int main(int argc, char *argv[]) ret = client_parse_config(argc, argv, &ct, &client_loglevel); if (ret < 0) goto out; - if (ct->conf.complete_given) + if (CLIENT_OPT_GIVEN(COMPLETE, ct->lpr)) print_completions(); if (ret == 0) interactive_session(); /* does not return */ @@ -603,18 +647,26 @@ int main(int argc, char *argv[]) goto out; sot.btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stdout", .parent = ct->btrn[0])); - register_task(&sched, &supervisor_task.task); + supervisor_task.task = task_register(&(struct task_info) { + .name = "supervisor", + .post_select = supervisor_post_select, + .context = &supervisor_task, + }, &sched); + 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; + if (ret >= 0) { + ret = task_status(ct->task); + if (ret < 0) { + switch (ret) { + /* 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; + } } } sched_shutdown(&sched);