X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fsendcommand.c;h=caca87fd9a534ff09c7887aad60da0be7b048f11;hb=b826c3117bb7ddf1386a4811cb2eb47ea4e1097c;hp=87e56037f14edb8a2c0824bfa97f101f1b35ca27;hpb=c5dcefbe1b55c201cb1ed948d859c1c1ff6ab51b;p=citadel.git diff --git a/citadel/sendcommand.c b/citadel/sendcommand.c index 87e56037f..caca87fd9 100644 --- a/citadel/sendcommand.c +++ b/citadel/sendcommand.c @@ -1,8 +1,18 @@ /* - * $Id$ + * Command-line utility to transmit a server command. + * + * Copyright (c) 1987-2021 by the citadel.org team + * + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ - +#include #include #include #include @@ -11,159 +21,208 @@ #include #include #include -#include #include #include #include +#include +#include #include "citadel.h" -#include "tools.h" -#include "ipc.h" -#include "config.h" +#include "citadel_dirs.h" +#include -#define LOCKFILE "/var/lock/LCK.sendcommand" - -struct config config; -extern int home_specified; +int serv_sock = (-1); +int uds_connectsock(char *sockpath) +{ + int s; + struct sockaddr_un addr; -/* - * make sure only one copy of sendcommand runs at a time, using lock files - */ -int set_lockfile(void) { - FILE *lfp; - int onppid; - - if ((lfp = fopen(LOCKFILE,"r")) != NULL) { - fscanf(lfp,"%d",&onppid); - fclose(lfp); - if (!kill(onppid, 0) || errno == EPERM) return 1; - } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sockpath, sizeof addr.sun_path); - lfp=fopen(LOCKFILE,"w"); - fprintf(lfp,"%ld\n",(long)getpid()); - fclose(lfp); - return(0); + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + fprintf(stderr, "sendcommand: Can't create socket: %s\n", strerror(errno)); + exit(3); } -void remove_lockfile(void) { - unlink(LOCKFILE); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + fprintf(stderr, "sendcommand: can't connect: %s\n", strerror(errno)); + close(s); + exit(3); } + return s; +} + + /* - * Why both cleanup() and nq_cleanup() ? Notice the alarm() call in - * cleanup() . If for some reason sendcommand hangs waiting for the server - * to clean up, the alarm clock goes off and the program exits anyway. - * The cleanup() routine makes a check to ensure it's not reentering, in - * case the ipc module looped it somehow. + * input binary data from socket */ -void nq_cleanup(int e) +void serv_read(char *buf, int bytes) { - remove_lockfile(); - exit(e); - } + int len, rlen; -void cleanup(int e) -{ - static int nested = 0; - - alarm(30); - signal(SIGALRM,nq_cleanup); - if (nested++ < 1) serv_puts("QUIT"); - nq_cleanup(e); + len = 0; + while (len < bytes) { + rlen = read(serv_sock, &buf[len], bytes - len); + if (rlen < 1) { + return; + } + len = len + rlen; } +} + /* - * This is implemented as a function rather than as a macro because the - * client-side IPC modules expect logoff() to be defined. They call logoff() - * when a problem connecting or staying connected to the server occurs. + * send binary to server */ -void logoff(int e) +void serv_write(char *buf, int nbytes) { - cleanup(e); + int bytes_written = 0; + int retval; + while (bytes_written < nbytes) { + retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written); + if (retval < 1) { + return; + } + bytes_written = bytes_written + retval; } +} + /* - * Connect sendcommand to the Citadel server running on this computer. + * input string from socket - implemented in terms of serv_read() */ -void np_attach_to_server(void) { - char buf[256]; - char portname[8]; - char *args[] = { "sendcommand", "localhost", NULL, NULL } ; - - fprintf(stderr, "Attaching to server...\n"); - sprintf(portname, "%d", config.c_port_number); - args[2] = portname; - attach_to_server(3, args); - serv_gets(buf); - fprintf(stderr, "%s\n",&buf[4]); - sprintf(buf,"IPGM %d", config.c_ipgm_secret); - serv_puts(buf); - serv_gets(buf); - fprintf(stderr, "%s\n",&buf[4]); - if (buf[0]!='2') { - cleanup(2); +void serv_gets(char *buf) +{ + int i; + + /* Read one character at a time. + */ + for (i = 0;; i++) { + serv_read(&buf[i], 1); + if (buf[i] == '\n' || i == (SIZ-1)) + break; + } + + /* If we got a long line, discard characters until the newline. + */ + if (i == (SIZ-1)) { + while (buf[i] != '\n') { + serv_read(&buf[i], 1); } } + /* Strip all trailing nonprintables (crlf) + */ + buf[i] = 0; +} /* - * main + * send line to server - implemented in terms of serv_write() */ -int main(int argc, char **argv) +void serv_puts(char *buf) { - int a; - char cmd[256]; - char buf[256]; + serv_write(buf, strlen(buf)); + serv_write("\n", 1); +} - strcpy(bbs_home_directory, BBSDIR); - strcpy(cmd, ""); - /* - * Change directories if specified - */ - for (a=1; a0) strcat(cmd, " "); - strcat(cmd, argv[a]); - } +/* + * Main loop. Do things and have fun. + */ +int main(int argc, char **argv) +{ + int a; + int watchdog = 60; + char buf[SIZ]; + int xfermode = 0; + char ctdldir[PATH_MAX]=CTDLDIR; + + /* Parse command line */ + while ((a = getopt(argc, argv, "h:w:")) != EOF) { + switch (a) { + case 'h': + strncpy(ctdldir, optarg, sizeof ctdldir); + break; + case 'w': + watchdog = atoi(optarg); + break; + default: + fprintf(stderr, "sendcommand: usage: sendcommand [-h server_dir] [-w watchdog_timeout]\n"); + return(1); } + } - get_config(); + fprintf(stderr, "sendcommand: started (pid=%d) connecting to Citadel server with data directory %s\n", + (int) getpid(), + ctdldir + ); + fflush(stderr); - signal(SIGINT,cleanup); - signal(SIGQUIT,cleanup); - signal(SIGHUP,cleanup); - signal(SIGTERM,cleanup); + if (chdir(ctdldir) != 0) { + fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno)); + exit(errno); + } - fprintf(stderr, "sendcommand: started. pid=%ld\n",(long)getpid()); - fflush(stderr); - np_attach_to_server(); - fflush(stderr); + alarm(watchdog); + serv_sock = uds_connectsock(file_citadel_admin_socket); + serv_gets(buf); + fprintf(stderr, "%s\n", buf); - fprintf(stderr, "%s\n", cmd); - serv_puts(cmd); + strcpy(buf, ""); + for (a=optind; a 0) { + if (buf[strlen(buf)-1] == '\n') { + buf[strlen(buf)-1] = 0; } + serv_puts(buf); + } + serv_puts("000"); + } + + if ((xfermode == '1') || (xfermode == '8')) { /* receive text */ + while(serv_gets(buf), strcmp(buf, "000")) { + printf("%s\n", buf); } - else if (buf[0]=='4') { - do { - if (fgets(buf, 255, stdin)==NULL) strcpy(buf, "000"); - if (strcmp(buf, "000")) serv_puts(buf); - } while (strcmp(buf, "000")); + } + + if (xfermode == '6') { /* receive binary */ + size_t len = atoi(&buf[4]); + size_t bytes_remaining = len; + + while (bytes_remaining > 0) { + size_t this_block = bytes_remaining; + if (this_block > SIZ) this_block = SIZ; + serv_read(buf, this_block); + fwrite(buf, this_block, 1, stdout); + bytes_remaining -= this_block; } + } + + close(serv_sock); + alarm(0); /* cancel the watchdog timer */ fprintf(stderr, "sendcommand: processing ended.\n"); - cleanup(0); - return 0; + if (xfermode == '5') { + return(1); } + return(0); +}