/*****************************************************************************\
* Copyright (c) 2004 Pelle Johansson. *
* All rights reserved. *
* *
* This file is part of the moftpd package. Use and distribution of *
* this software is governed by the terms in the file LICENCE, which *
* should have come with this package. *
\*****************************************************************************/
/* $moftpd: admin.c 1251 2005-03-06 22:24:29Z morth $ */
#ifndef _SYSTEM_H
#include "system.h"
#endif
#include "utf8fs/memory.h"
const char *sockPath = VARDIR "/run/" PACKAGE_NAME ".acct";
int debug = 0;
void usage (void)
{
fprintf (stderr, "Usage: %s [-f <socket>] list\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] msg <id> <message>\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] msgall <message>\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] abort <id> [<message>]\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] disconnect <id> [<message>]\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] discabort <id> [<message>]\n", getprogname ());
fprintf (stderr, " %s [-f <socket>] reload\n", getprogname ());
exit(1);
}
int parse_options (int argc, char ***argv)
{
int ch;
if (getenv("MOFTP_SOCKET"))
{
sockPath = tstring (getenv ("MOFTP_SOCKET"));
if(!sockPath)
{
perror ("tstring");
return -1;
}
}
while((ch = getopt(argc, *argv, "f:")) != -1)
{
switch(ch)
{
case 'f':
sockPath = tstring (optarg);
if(!sockPath)
{
perror ("tstring");
return -1;
}
break;
default:
usage ();
}
}
*argv += optind;
return argc - optind;
}
const char *combine_args (char *argv[], int nargs)
{
int l = -1, i;
char *res, *rp;
for (i = 0; i < nargs; i++)
l += strlen (argv[i]) + 1;
if (l <= 0)
return "";
rp = res = talloc (l);
if (!res)
{
perror ("talloc");
return NULL;
}
for (i = 0; i < nargs; i++)
{
#ifdef HAVE_STPCPY
rp = stpcpy (rp, argv[i]);
#else
strcpy (rp, argv[i]);
rp += strlen (rp);
#endif
*rp++ = ' ';
}
*--rp = 0;
return res;
}
int accounter (int sock, const char *format, ...)
{
va_list ap;
char *str, *sp;
int res;
#ifdef HAVE_VASPRINTF
int doFree;
#endif
va_start (ap, format);
#ifdef HAVE_VASPRINTF
vasprintf (&str, format, ap);
doFree = 1;
#else
str = talloc (4097);
if (str)
vsnprintf (str, 4096, format, ap);
#endif
va_end (ap);
if (!str)
{
str = tstring (format);
#ifdef HAVE_VASPRINTF
doFree = 0;
#endif
}
while ((sp = strchr (str, '\n')) && *(sp + 1))
*sp = '?';
res = write (sock, str, strlen (str));
#ifdef HAVE_VASPRINTF
if (doFree)
free (str);
#endif
if (res < 0)
return -1;
return 0;
}
int ok_message (int sock, const char *type, int id, const char *message)
{
int l;
char buf[4096], *bp;
if (id != -1)
l = accounter (sock, "%s %d %s\n", type, id, message);
else
l = accounter (sock, "%s %s", type, message);
if (l)
{
perror ("accounter");
return 1;
}
l = read (sock, buf, sizeof (buf) - 1);
if (l < 0)
{
perror ("read");
return 1;
}
buf[l] = 0;
bp = strchr (buf, '\n');
if (bp)
*bp = 0;
if (!strcmp (buf, "OK"))
return 0;
if (!strcmp (buf, "INVALID"))
fprintf (stderr, "Invalid connection id.\n");
else
fprintf (stderr, "Unknown error.\n");
return 1;
}
int main (int argc, char *argv[])
{
int sock;
struct sockaddr_un addr;
int bl, l, i;
char buf[4096], *bp, *nbp;
const char *msg;
setprogname (argv[0]);
argc = parse_options (argc, &argv);
if (argc < 0)
return 1;
if (!argc)
usage ();
sock = socket (PF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
return 1;
}
addr.sun_family = AF_UNIX;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
addr.sun_len = sizeof (addr);
#endif
strncpy (addr.sun_path, sockPath, sizeof (addr.sun_path) - 1);
addr.sun_path[sizeof (addr.sun_path) - 1] = 0;
if (connect (sock, (struct sockaddr*)&addr, sizeof (addr)))
{
perror ("connect");
return 1;
}
if (!strcasecmp (argv[0], "LIST"))
{
if (argc != 1)
usage ();
if (accounter (sock, "LIST\n"))
{
perror ("accounter");
return 1;
}
bl = l = 0;
while (bl > 0 || (l = read (sock, buf + bl, sizeof (buf) - bl)) > 0)
{
if (l > 0)
bl += l;
nbp = memchr (buf, '\n', bl);
if (nbp)
*nbp++ = 0;
if (!strcmp (buf, "END"))
break;
printf ("%s\n", buf);
if (!nbp)
break;
bl -= nbp - buf;
memmove (buf, nbp, bl);
l = 0;
}
}
else if (!strcasecmp (argv[0], "MSG"))
{
if (argc < 3 || !*argv[1])
usage ();
i = strtol (argv[1], &bp, 0);
if (*bp)
usage ();
msg = combine_args (argv + 2, argc - 2);
if (!msg)
return 1;
if (!*msg)
{
fprintf (stderr, "No message given.\n");
return 1;
}
if (ok_message (sock, "MSG", i, msg))
return 1;
}
else if (!strcasecmp (argv[0], "MSGALL"))
{
if (argc < 2)
usage ();
msg = combine_args (argv + 1, argc - 1);
if (!msg)
return 1;
if (!*msg)
{
fprintf (stderr, "No message given.\n");
return 1;
}
if (ok_message (sock, "MSGALL", -1, msg))
return 1;
}
else if (!strcasecmp (argv[0], "ABORT"))
{
if (argc < 2 || !*argv[1])
usage ();
i = strtol (argv[1], &bp, 0);
if (*bp)
usage ();
msg = combine_args (argv + 2, argc - 2);
if (!msg)
return 1;
if (ok_message (sock, "ABORT", i, msg))
return 1;
}
else if (!strcasecmp (argv[0], "DISCONNECT"))
{
if (argc < 2 || !*argv[1])
usage ();
i = strtol (argv[1], &bp, 0);
if (*bp)
usage ();
msg = combine_args (argv + 2, argc - 2);
if (!msg)
return 1;
if (ok_message (sock, "DISCONNECT", i, msg))
return 1;
}
else if (!strcasecmp (argv[0], "DISCABORT"))
{
if (argc < 2 || !*argv[1])
usage ();
i = strtol (argv[1], &bp, 0);
if (*bp)
usage ();
msg = combine_args (argv + 2, argc - 2);
if (!msg)
return 1;
if (ok_message (sock, "DISCABORT", i, msg))
return 1;
}
else if (!strcasecmp (argv[0], "RELOAD"))
{
if (argc != 1)
usage ();
if (accounter (sock, "RELOAD\n"))
{
perror ("accounter");
return 1;
}
printf ("Configuration reloading.\n");
}
else
usage ();
close (sock);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1