1 /* $Id: ctlinnd.c 6155 2003-01-19 19:58:25Z rra $
3 ** Send control messages to the InterNetNews daemon.
12 #include "inn/innconf.h"
13 #include "inn/messages.h"
20 ** Datatype for an entry in the command table.
22 typedef struct _COMMAND {
31 static COMMAND Commands[] = {
32 { "addhist", "id arr exp post token...\tAdd history line",
33 5, SC_ADDHIST, true },
34 { "allow", "reason...\t\t\tAllow remote connections",
36 { "begin", "site\t\t\tStart newly-added site",
38 { "cancel", "id\t\t\tCancel message locally",
39 1, SC_CANCEL, false },
40 { "changegroup", "group rest\tChange mode of group",
41 2, SC_CHANGEGROUP, false },
42 { "checkfile", "\t\t\tCheck syntax of newsfeeds file",
43 0, SC_CHECKFILE, false },
44 { "drop", "site\t\t\tStop feeding site",
46 { "feedinfo", "site\t\t\tPrint state of feed to site*",
47 1, SC_FEEDINFO, false },
49 { "tcl", "flag\t\t\tEnable or disable Tcl filtering",
50 1, SC_FILTER, false },
51 #endif /* defined(DO_TCL) */
52 { "flush", "site\t\t\tFlush feed for site*",
54 { "flushlogs", "\t\t\tFlush log files",
55 0, SC_FLUSHLOGS, false },
56 { "go", "reason...\t\t\tRestart after pause or throttle",
58 { "hangup", "channel\t\tHangup specified incoming channel",
59 1, SC_HANGUP, false },
60 { "logmode", "\t\t\t\tSend server mode to syslog",
61 0, SC_LOGMODE, false },
62 { "mode", "\t\t\t\tPrint operating mode",
64 { "name", "nnn\t\t\tPrint name of specified channel*",
66 { "newgroup", "group rest creator\tCreate new group",
67 3, SC_NEWGROUP, false },
68 { "param", "letter value\t\tChange command-line parameters",
70 { "pause", "reason...\t\tShort-term pause in accepting articles",
73 { "perl", "flag\t\t\tEnable or disable Perl filtering",
75 #endif /* defined(DO_PERL) */
76 #if defined(DO_PYTHON)
77 { "python", "flag\t\t\tEnable or disable Python filtering",
78 1, SC_PYTHON, false },
79 #endif /* (DO_PYTHON) */
80 { "readers", "flag text...\t\tEnable or disable newsreading",
81 2, SC_READERS, true },
82 { "reject", "reason...\t\t\tReject remote connections",
84 { "reload", "what reason...\t\tRe-read config files*",
86 { "renumber", "group\t\tRenumber the active file*",
87 1, SC_RENUMBER, false },
88 { "reserve", "reason...\t\tReserve the next pause or throttle",
89 1, SC_RESERVE, true },
90 { "rmgroup", "group\t\t\tRemove named group",
91 1, SC_RMGROUP, false },
92 { "send", "feed text...\t\tSend text to exploder feed",
94 { "shutdown", "reason...\t\tShut down server",
95 1, SC_SHUTDOWN, true },
96 { "stathist", "filename|off\t\tLog into filename some history stats",
97 1, SC_STATHIST, false },
98 { "status", "interval|off\t\tTurn innd status generation on or off",
99 1, SC_STATUS, false },
100 { "kill", "signal site\t\tSend signal to site's process",
101 2, SC_SIGNAL, false },
102 { "throttle", "reason...\t\tStop accepting articles",
103 1, SC_THROTTLE, true },
104 { "timer", "interval|off\t\tTurn performance monitoring on or off",
105 1, SC_TIMER, false },
106 { "trace", "innd|#|nnrpd flag\tTurn tracing on or off",
107 2, SC_TRACE, false },
108 { "xabort", "text...\t\tAbort the server",
109 1, SC_XABORT, true },
110 { "lowmark", "filename\t\tReset active file low article marks",
111 1, SC_LOWMARK, false },
112 { "renumberlow", "filename\t\tReset active file low article marks",
113 1, SC_LOWMARK, false },
114 { "xexec", "path\t\t\tExec new server",
121 ** Print a help summary.
129 printf("Command summary:\n");
130 for (cp = Commands; cp < ARRAY_END(Commands); cp++)
131 printf(" %s %s\n", cp->Command, cp->Text);
132 printf("* Empty string means all sites/groups/etc.\n");
133 printf("... All trailing words are glued together.\n");
136 for (cp = Commands; cp < ARRAY_END(Commands); cp++)
137 if (strcmp(p, cp->Command) == 0) {
138 printf("Command usage:\n");
139 printf(" %s %s\n", cp->Command, cp->Text);
142 printf("No such command.\n");
148 ** Print a command-usage message and exit.
151 WrongArgs(COMMAND *cp)
153 printf("Wrong number of arguments -- usage:\n");
154 printf(" %s %s\n", cp->Command, cp->Text);
160 ** Print an error message and exit.
163 Failed(const char *p)
166 syswarn("cannot %s (%s failure)", p, ICCfailure);
168 syswarn("cannot %s", p);
175 ** Print an error reporting incorrect usage.
178 Usage(const char *what)
180 fprintf(stderr, "Usage error (%s) -- try -h for help.\n", what);
185 int main(int ac, char *av[])
187 static char Y[] = "y";
188 static char EMPTY[] = "";
201 /* First thing, set up our identity. */
202 message_program_name = "ctlinnd";
205 if (!innconf_read(NULL))
209 ICCsettimeout(CTLINND_TIMEOUT);
212 while ((i = getopt(ac, av, "hst:")) != EOF)
217 case 'h': /* Get help */
220 case 's': /* Silent -- no output */
223 case 't': /* Time to wait for reply */
224 ICCsettimeout(atoi(optarg));
232 Usage("missing command");
234 /* Look up the command word and move to the arguments. */
235 if (strcmp(av[0], "help") == 0)
237 for (cp = Commands; cp < ARRAY_END(Commands); cp++)
238 if (strcmp(av[0], cp->Command) == 0)
240 if (cp == ARRAY_END(Commands))
241 Usage("unknown command");
245 /* Check argument count. */
246 if (cp->Letter == SC_NEWGROUP) {
247 /* Newgroup command has defaults. */
271 else if (ac > cp->argc && cp->Glue) {
272 /* Glue any extra words together. */
273 for (length = 0, i = cp->argc - 1; (p = av[i++]) != NULL; )
274 length += strlen(p) + 1;
275 new = xmalloc(length);
277 for (i = cp->argc - 1; av[i]; i++) {
279 strlcat(new, " ", length);
280 strlcat(new, av[i], length);
282 av[cp->argc - 1] = new;
285 else if (ac != cp->argc)
286 /* All other commands must have the right number of arguments. */
289 /* For newgroup and changegroup, make sure the mode is valid. */
290 if (cp->Letter == SC_NEWGROUP || cp->Letter == SC_CHANGEGROUP) {
293 Usage("Bad group mode");
296 case NF_FLAG_EXCLUDED:
297 case NF_FLAG_MODERATED:
299 case NF_FLAG_NOLOCAL:
305 /* Make sure there are no separators in the parameters. */
306 for (i = 0; (p = av[i++]) != NULL; )
307 if (strchr(p, SC_SEP) != NULL)
308 die("illegal character \\%03o in %s", SC_SEP, p);
310 /* Do the real work. */
312 Failed("setup communication");
313 i = ICCcommand(cp->Letter, (const char **) av, &reply);
316 p = concatpath(innconf->pathrun, _PATH_SERVERPID);
317 if (stat(p, &Sb) < 0)
318 warn("no innd.pid file; did server die?");
320 snprintf(buff, sizeof(buff), "send \"%s\" command", cp->Command);
326 /* Skip "<exitcode><space>" part of reply. */
327 for (p = reply; *p && CTYPE(isdigit, *p); p++)
329 while (*p && ISWHITE(*p))
338 Failed("end communication");