- port to Cygwin (DLL support, etc.)
[citadel.git] / citadel / sendcommand.c
1 /*
2  * $Id$
3  *
4  * Command-line utility to transmit a server command.
5  *
6  */
7
8
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <ctype.h>
17
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #include <signal.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include "citadel.h"
33 #include "tools.h"
34 #include "ipc.h"
35 #include "server.h"
36 #include "dynloader.h"
37 #include "config.h"
38
39 #define LOCKFILE "/tmp/LCK.sendcommand"
40
41 /*
42  * make sure only one copy of sendcommand runs at a time, using lock files
43  */
44 int set_lockfile(void)
45 {
46         FILE *lfp;
47         int onppid;
48
49         if ((lfp = fopen(LOCKFILE, "r")) != NULL) {
50                 fscanf(lfp, "%d", &onppid);
51                 fclose(lfp);
52                 if (!kill(onppid, 0) || errno == EPERM)
53                         return 1;
54         }
55         lfp = fopen(LOCKFILE, "w");
56         fprintf(lfp, "%ld\n", (long) getpid());
57         fclose(lfp);
58         return (0);
59 }
60
61 void remove_lockfile(void)
62 {
63         unlink(LOCKFILE);
64 }
65
66 /*
67  * Why both cleanup() and nq_cleanup() ?  Notice the alarm() call in
68  * cleanup() .  If for some reason sendcommand hangs waiting for the server
69  * to clean up, the alarm clock goes off and the program exits anyway.
70  * The cleanup() routine makes a check to ensure it's not reentering, in
71  * case the ipc module looped it somehow.
72  */
73 void nq_cleanup(int e)
74 {
75         remove_lockfile();
76         exit(e);
77 }
78
79 void cleanup(int e)
80 {
81         static int nested = 0;
82
83         alarm(30);
84         signal(SIGALRM, nq_cleanup);
85         if (nested++ < 1)
86                 serv_puts("QUIT");
87         nq_cleanup(e);
88 }
89
90 /*
91  * This is implemented as a function rather than as a macro because the
92  * client-side IPC modules expect logoff() to be defined.  They call logoff()
93  * when a problem connecting or staying connected to the server occurs.
94  */
95 void logoff(int e)
96 {
97         cleanup(e);
98 }
99
100 /*
101  * Connect sendcommand to the Citadel server running on this computer.
102  */
103 void np_attach_to_server(void)
104 {
105         char hostbuf[SIZ], portbuf[SIZ];
106         char buf[SIZ];
107         char *args[] =
108         {"sendcommand", NULL};
109
110         fprintf(stderr, "Attaching to server...\n");
111         attach_to_server(1, args, hostbuf, portbuf);
112         serv_gets(buf);
113         fprintf(stderr, "%s\n", &buf[4]);
114         sprintf(buf, "IPGM %d", config.c_ipgm_secret);
115         serv_puts(buf);
116         serv_gets(buf);
117         fprintf(stderr, "%s\n", &buf[4]);
118         if (buf[0] != '2') {
119                 cleanup(2);
120         }
121 }
122
123
124
125 /*
126  * main
127  */
128 int main(int argc, char **argv)
129 {
130         int a;
131         char cmd[SIZ];
132         char buf[SIZ];
133
134         strcpy(bbs_home_directory, BBSDIR);
135
136         strcpy(cmd, "");
137         /*
138          * Change directories if specified
139          */
140         for (a = 1; a < argc; ++a) {
141                 if (!strncmp(argv[a], "-h", 2)) {
142                         strcpy(bbs_home_directory, argv[a]);
143                         strcpy(bbs_home_directory, &bbs_home_directory[2]);
144                         home_specified = 1;
145                 } else {
146                         if (strlen(cmd) > 0)
147                                 strcat(cmd, " ");
148                         strcat(cmd, argv[a]);
149                 }
150         }
151
152         get_config();
153
154         signal(SIGINT, cleanup);
155         signal(SIGQUIT, cleanup);
156         signal(SIGHUP, cleanup);
157         signal(SIGTERM, cleanup);
158
159         fprintf(stderr, "sendcommand: started.  pid=%ld\n", (long) getpid());
160         fprintf(stderr, "Running from %s\n", bbs_home_directory);
161         fflush(stderr);
162         np_attach_to_server();
163         fflush(stderr);
164
165         fprintf(stderr, "%s\n", cmd);
166         serv_puts(cmd);
167         serv_gets(buf);
168         fprintf(stderr, "%s\n", buf);
169
170         if (buf[0] == '1') {
171                 while (serv_gets(buf), strcmp(buf, "000")) {
172                         printf("%s\n", buf);
173                 }
174         } else if (buf[0] == '4') {
175                 do {
176                         if (fgets(buf, sizeof buf, stdin) == NULL)
177                                 strcpy(buf, "000");
178                         if (strlen(buf) > 0)
179                                 if (buf[strlen(buf) - 1] == '\n')
180                                         buf[strlen(buf) - 1] = 0;
181                         if (strlen(buf) > 0)
182                                 if (buf[strlen(buf) - 1] == '\r')
183                                         buf[strlen(buf) - 1] = 0;
184                         if (strcmp(buf, "000"))
185                                 serv_puts(buf);
186                 } while (strcmp(buf, "000"));
187                 serv_puts("000");
188         }
189         fprintf(stderr, "sendcommand: processing ended.\n");
190         cleanup(0);
191         return 0;
192 }