/* The name this program was run with. */
static char *program_name = NULL;
+static char **orig_argv;
+static int orig_argc;
+
/* If nonzero, display usage information and exit. */
static bool show_help = false;
static int cmd_start(int argc, char *argv[]) {
- int i, j;
- char *c;
+ if(connect_tincd(false)) {
+ if(netname)
+ fprintf(stderr, "A tincd is already running for net `%s' with pid %d.\n", netname, pid);
+ else
+ fprintf(stderr, "A tincd is already running with pid %d.\n", pid);
+ return 0;
+ }
- argc += optind;
- argv -= optind;
- char *slash = strrchr(argv[0], '/');
+ char *c;
+ char *slash = strrchr(program_name, '/');
#ifdef HAVE_MINGW
- if ((c = strrchr(argv[0], '\\')) > slash)
+ if ((c = strrchr(program_name, '\\')) > slash)
slash = c;
#endif
if (slash++)
- xasprintf(&c, "%.*stincd", (int)(slash - argv[0]), argv[0]);
+ xasprintf(&c, "%.*stincd", (int)(slash - program_name), program_name);
else
c = "tincd";
- argv[0] = c;
+ int nargc = 0;
+ char **nargv = xmalloc_and_zero((orig_argc + argc) * sizeof *nargv);
- for(i = j = 1; argv[i]; ++i)
- if (i != optind && strcmp(argv[i], "--") != 0)
- argv[j++] = argv[i];
+ for(int i = 0; i < orig_argc; i++)
+ nargv[nargc++] = orig_argv[i];
+ for(int i = 1; i < argc; i++)
+ nargv[nargc++] = argv[i];
- argv[j] = NULL;
- execvp(c, argv);
- fprintf(stderr, "Could not start %s: %s\n", c, strerror(errno));
+#ifdef HAVE_MINGW
+ execvp(c, nargv);
+ fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
return 1;
+#else
+ pid_t pid = fork();
+ if(pid == -1) {
+ fprintf(stderr, "Could not fork: %s\n", strerror(errno));
+ return 1;
+ }
+
+ if(!pid)
+ exit(execvp(c, nargv));
+
+ int status = -1;
+ if(waitpid(pid, &status, 0) != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
+ fprintf(stderr, "Error starting %s\n", c);
+ return 1;
+ }
+
+ return 0;
+#endif
}
static int cmd_stop(int argc, char *argv[]) {
if(!remove_service())
return 1;
#endif
+ close(fd);
+ pid = 0;
+ fd = -1;
+
return 0;
}
return NULL;
}
+static char *complete_config(const char *text, int state) {
+ const char *sub[] = {"get", "set", "add", "del"};
+ static int i;
+ if(!state) {
+ i = 0;
+ if(!strchr(rl_line_buffer + 7, ' '))
+ i = -4;
+ else {
+ bool found = false;
+ for(int i = 0; i < 4; i++) {
+ if(!strncasecmp(rl_line_buffer + 7, sub[i], strlen(sub[i])) && rl_line_buffer[7 + strlen(sub[i])] == ' ') {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ return NULL;
+ }
+ } else {
+ i++;
+ }
+
+ while(i < 0 || variables[i].name) {
+ if(i < 0 && !strncasecmp(sub[i + 4], text, strlen(text)))
+ return xstrdup(sub[i + 4]);
+ if(i >= 0) {
+ char *dot = strchr(text, '.');
+ if(dot) {
+ if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
+ char *match;
+ xasprintf(&match, "%.*s.%s", dot - text, text, variables[i].name);
+ return match;
+ }
+ } else {
+ if(!strncasecmp(variables[i].name, text, strlen(text)))
+ return xstrdup(variables[i].name);
+ }
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+static char *complete_info(const char *text, int state) {
+ static int i;
+ if(!state) {
+ i = 0;
+ if(!connect_tincd(false))
+ return NULL;
+ // Check the list of nodes
+ sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
+ sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
+ }
+
+ while(recvline(fd, line, sizeof line)) {
+ char item[4096];
+ int n = sscanf(line, "%d %d %s", &code, &req, item);
+ if(n == 2) {
+ i++;
+ if(i >= 2)
+ break;
+ else
+ continue;
+ }
+
+ if(n != 3) {
+ fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
+ break;
+ }
+
+ if(!strncmp(item, text, strlen(text)))
+ return xstrdup(strip_weight(item));
+ }
+
+ return NULL;
+}
+
+static char *complete_nothing(const char *text, int state) {
+ return NULL;
+}
+
static char **completion (const char *text, int start, int end) {
char **matches = NULL;
matches = rl_completion_matches(text, complete_command);
else if(!strncasecmp(rl_line_buffer, "dump ", 5))
matches = rl_completion_matches(text, complete_dump);
+ else if(!strncasecmp(rl_line_buffer, "config ", 7))
+ matches = rl_completion_matches(text, complete_config);
+ else if(!strncasecmp(rl_line_buffer, "info ", 5))
+ matches = rl_completion_matches(text, complete_info);
return matches;
}
#ifdef HAVE_READLINE
rl_readline_name = "tinc";
+ rl_completion_entry_function = complete_nothing;
rl_attempted_completion_function = completion;
rl_filename_completion_desired = 0;
char *copy = NULL;
if(tty) {
free(copy);
free(line);
+ rl_basic_word_break_characters = "\t\n ";
line = readline(prompt);
if(line)
copy = xstrdup(line);
}
#else
if(tty)
- fputs(stdout, prompt);
+ fputs(prompt, stdout);
line = fgets(buf, sizeof buf, stdin);
#endif
int main(int argc, char *argv[]) {
program_name = argv[0];
+ orig_argv = argv;
+ orig_argc = argc;
if(!parse_options(argc, argv))
return 1;