remove unused code for locking
[citadel.git] / citadel / utils / sendcommand.c
1 /*
2  * Command-line utility to transmit a server command.
3  *
4  * Copyright (c) 1987-2010 by the citadel.org team
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "ctdl_module.h"
22
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <ctype.h>
31
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 #  include <sys/time.h>
38 # else
39 #  include <time.h>
40 # endif
41 #endif
42
43 #include <signal.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <libcitadel.h>
47 #include "citadel.h"
48 #include "citadel_ipc.h"
49 #include "server.h"
50 #include "config.h"
51
52 static CtdlIPC *ipc = NULL;
53
54 /*
55  * Why both cleanup() and nq_cleanup() ?  Notice the alarm() call in
56  * cleanup() .  If for some reason sendcommand hangs waiting for the server
57  * to clean up, the alarm clock goes off and the program exits anyway.
58  * The cleanup() routine makes a check to ensure it's not reentering, in
59  * case the ipc module looped it somehow.
60  */
61 void nq_cleanup(int e)
62 {
63         if (e == SIGALRM)
64                 fprintf(stderr, "\nWatch dog time out.\n");
65         exit(e);
66 }
67
68 /*
69  * send binary to server
70  */
71 void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes)
72 {
73         unsigned int bytes_written = 0;
74         int retval;
75 /*
76 #if defined(HAVE_OPENSSL)
77         if (ipc->ssl) {
78                 serv_write_ssl(ipc, buf, nbytes);
79                 return;
80         }
81 #endif
82 */
83         while (bytes_written < nbytes) {
84                 retval = write(ipc->sock, &buf[bytes_written],
85                                nbytes - bytes_written);
86                 if (retval < 1) {
87                         connection_died(ipc, 0);
88                         return;
89                 }
90                 bytes_written += retval;
91         }
92 }
93
94
95 void cleanup(int e)
96 {
97         static int nested = 0;
98
99         alarm(30);
100         signal(SIGALRM, nq_cleanup);
101         serv_write(ipc, "\n", 1);
102         if (nested++ < 1)
103                 CtdlIPCQuit(ipc);
104         nq_cleanup(e);
105 }
106
107 /*
108  * This is implemented as a function rather than as a macro because the
109  * client-side IPC modules expect logoff() to be defined.  They call logoff()
110  * when a problem connecting or staying connected to the server occurs.
111  */
112 void logoff(int e)
113 {
114         cleanup(e);
115 }
116
117 /*
118  * Connect sendcommand to the Citadel server running on this computer.
119  */
120 void np_attach_to_server(char *host, char *port)
121 {
122         char buf[SIZ];
123         char hostbuf[256], portbuf[256];
124         char *args[] =
125         {"sendcommand", NULL};
126         int r;
127
128         fprintf(stderr, "Attaching to server...\n");
129         strcpy(hostbuf, host);
130         strcpy(portbuf, port);
131         ipc = CtdlIPC_new(1, args, hostbuf, portbuf);
132         if (!ipc) {
133                 fprintf(stderr, "Can't connect: %s\n", strerror(errno));
134                 exit(3);
135         }
136         CtdlIPC_chat_recv(ipc, buf);
137         fprintf(stderr, "%s\n", &buf[4]);
138         snprintf(buf, sizeof buf, "IPGM %d", config.c_ipgm_secret);
139         r = CtdlIPCInternalProgram(ipc, config.c_ipgm_secret, buf);
140         fprintf(stderr, "%s\n", buf);
141         if (r / 100 != 2) {
142                 cleanup(2);
143         }
144 }
145
146
147 void sendcommand_die(void) {
148         exit(0);
149 }
150
151
152
153 int main(int argc, char **argv)
154 {
155         int a;
156         char cmd[SIZ];
157         char buf[SIZ];
158         int watchdog = 60;
159
160         int relh=0;
161         int home=0;
162         char relhome[PATH_MAX]="";
163         char ctdldir[PATH_MAX]=CTDLDIR;
164         fd_set read_fd;
165         struct timeval tv;
166         int ret;
167         int server_shutting_down = 0;
168         
169         strcpy(ctdl_home_directory, DEFAULT_PORT);
170
171         strcpy(cmd, "");
172         /*
173          * Change directories if specified
174          */
175         for (a = 1; a < argc; ++a) {
176                 if (!strncmp(argv[a], "-h", 2)) {
177                         relh=argv[a][2]!='/';
178                         if (!relh) safestrncpy(ctdl_home_directory, &argv[a][2],
179                                                                    sizeof ctdl_home_directory);
180                         else
181                                 safestrncpy(relhome, &argv[a][2],
182                                                         sizeof relhome);
183                         home=1;
184                 } else if (!strncmp(argv[a], "-w", 2)) {
185                         watchdog = atoi(&argv[a][2]);
186                         if (watchdog<1)
187                                 watchdog=1;
188                 } else {
189                         if (!IsEmptyStr(cmd))
190                                 strcat(cmd, " ");
191                         strcat(cmd, argv[a]);
192                 }
193         }
194
195         calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
196         get_config();
197
198         signal(SIGINT, cleanup);
199         signal(SIGQUIT, cleanup);
200         signal(SIGHUP, cleanup);
201         signal(SIGTERM, cleanup);
202
203         fprintf(stderr, "sendcommand: started (pid=%d) "
204                         "running in %s\n",
205                         (int) getpid(),
206                         ctdl_home_directory);
207         fflush(stderr);
208
209         alarm(watchdog);
210         signal(SIGALRM, nq_cleanup); /* Set up a watchdog type timer in case we hang */
211         
212         np_attach_to_server(UDS, ctdl_home_directory);
213         fflush(stderr);
214         setIPCDeathHook(sendcommand_die);
215
216         fprintf(stderr, "%s\n", cmd);
217         CtdlIPC_chat_send(ipc, cmd);
218         CtdlIPC_chat_recv(ipc, buf);
219         fprintf(stderr, "%s\n", buf);
220
221         tv.tv_sec = 0;
222         tv.tv_usec = 1000;
223
224         if (!strncasecmp(&buf[1], "31", 2)) {
225                 server_shutting_down = 1;
226         }
227
228         if (buf[0] == '1') {
229                 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf, "000")) {
230                         printf("%s\n", buf);
231                         alarm(watchdog); /* Kick the watchdog timer */
232                 }
233         } else if (buf[0] == '4') {
234                 do {
235                         if (fgets(buf, sizeof buf, stdin) == NULL)
236                                 strcpy(buf, "000");
237                         if (!IsEmptyStr(buf))
238                                 if (buf[strlen(buf) - 1] == '\n')
239                                         buf[strlen(buf) - 1] = 0;
240                         if (!IsEmptyStr(buf))
241                                 if (buf[strlen(buf) - 1] == '\r')
242                                         buf[strlen(buf) - 1] = 0;
243                         if (strcmp(buf, "000"))
244                                 CtdlIPC_chat_send(ipc, buf);
245                         
246                         FD_ZERO(&read_fd);
247                         FD_SET(ipc->sock, &read_fd);
248                         ret = select(ipc->sock+1, &read_fd, NULL, NULL,  &tv);
249                         if (ret == -1) {
250                                 if (!(errno == EINTR || errno == EAGAIN))
251                                         fprintf(stderr, "select() failed: %s", strerror(errno));
252                                 return(1);
253                         }
254
255                         if (ret != 0) {
256                                 size_t n;
257                                 char rbuf[SIZ];
258
259                                 rbuf[0] = '\0';
260                                 n = read(ipc->sock, rbuf, SIZ);
261                                 if (n>0) {
262                                         rbuf[n]='\0';
263                                         fprintf(stderr, "%s", rbuf);
264                                         fflush (stdout);
265                                 }
266                         }
267                         alarm(watchdog); /* Kick the watchdog timer */
268                 } while (strcmp(buf, "000"));
269                 CtdlIPC_chat_send(ipc, "\n");
270                 CtdlIPC_chat_send(ipc, "000");
271         }
272         alarm(0);       /* Shutdown the watchdog timer */
273         fprintf(stderr, "sendcommand: processing ended.\n");
274
275         /* Clean up and log off ... unless the server indicated that the command
276          * we sent is shutting it down, in which case we want to just cut the
277          * connection and exit.
278          */
279         if (server_shutting_down) {
280                 nq_cleanup(0);
281         }
282         else {
283                 cleanup(0);
284         }
285         return 0;
286 }
287
288 /*
289  * Stub function
290  */
291 void stty_ctdl(int cmd) {
292 }
293
294