aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-01-02 11:18:28 +0200
committerSergey Poznyakoff <gray@gnu.org>2016-01-02 11:20:42 +0200
commit061afaf6385340f87bbeaa6d7e8ff6befa532551 (patch)
tree7d42952187b6c035caba9c74cfb6cb8dfd651354 /src
parent00e6c3c3ed06a258a02943fc49fa7c528025d747 (diff)
downloadpies-061afaf6385340f87bbeaa6d7e8ff6befa532551.tar.gz
pies-061afaf6385340f87bbeaa6d7e8ff6befa532551.tar.bz2
piesctl: Implement all basic commands, except "restart"
Diffstat (limited to 'src')
-rw-r--r--src/ctl.c4
-rw-r--r--src/piesctl-cl.opt8
-rw-r--r--src/piesctl.c338
3 files changed, 336 insertions, 14 deletions
diff --git a/src/ctl.c b/src/ctl.c
index ce13dab..cbc5fea 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -1,8 +1,8 @@
/* This file is part of GNU Pies.
- Copyright (C) 2007-2013 Sergey Poznyakoff
+ Copyright (C) 2007-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -1443,13 +1443,13 @@ res_programs (struct ctlio *io, enum http_method meth,
else
{
if (!(prog->v.p.comp->flags & CF_DISABLED))
ctlio_reply (io, 409, "already running");
else
{
- prog->v.p.comp->flags &= CF_DISABLED;
+ prog->v.p.comp->flags &= ~CF_DISABLED;
prog->v.p.status = status_enabled;
kill (getpid (), SIGALRM);
ctlio_reply (io, 200, "Component started");
}
}
}
diff --git a/src/piesctl-cl.opt b/src/piesctl-cl.opt
index 04ff051..a83616e 100644
--- a/src/piesctl-cl.opt
+++ b/src/piesctl-cl.opt
@@ -1,8 +1,8 @@
/* This file is part of GNU Pies. -*- c -*-
- Copyright (C) 2008-2014 Sergey Poznyakoff
+ Copyright (C) 2008-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -49,12 +49,18 @@ END
OPTION(verbose,v,,
[<verbose diagnostics>])
BEGIN
++verbose;
END
+OPTION(dump,d,,
+ [<dump obtained responsed verbatim>])
+BEGIN
+ ++dump;
+END
+
OPTION(url,u,URL,
[<connect to this socket>])
BEGIN
if (pies_url_create (&url, optarg))
{
grecs_error (NULL, 0, _("%s: cannot create URL: %s"),
diff --git a/src/piesctl.c b/src/piesctl.c
index 0618caa..9c5ef8b 100644
--- a/src/piesctl.c
+++ b/src/piesctl.c
@@ -1,8 +1,8 @@
/* This file is part of GNU Pies.
- Copyright (C) 2015 Sergey Poznyakoff
+ Copyright (C) 2015, 2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -32,20 +32,22 @@
#include <sysexits.h>
#include <termios.h>
#include "base64.h"
#include "progname.h"
#include "libpies.h"
#include "grecsasrt.h"
+#include "fprintftime.h"
struct pies_url *default_url; /* Control socket URL */
struct pies_url *url;
char const *instance = "pies";
char *config_file;
char default_config_file[] = SYSCONFDIR "/piesctl.conf";
int preprocess_only;
int verbose;
+int dump;
static void config_help (void);
#include "piesctl-cl.h"
static struct grecs_keyword instance_keywords[] = {
@@ -791,40 +793,48 @@ shttp_get_reply (struct shttp_connection *conn)
}
}
}
}
static void
-stderr_writer (void *closure, char const *text, size_t len)
+fp_writer (void *closure, char const *text, size_t len)
{
- fwrite (text, len, 1, stderr);
+ fwrite (text, len, 1, (FILE*) closure);
}
static void
-shttp_format_result (struct shttp_connection *conn)
+print_json (FILE *fp, struct json_value *v)
{
struct json_format fmt = {
.indent = 2,
.precision = 0,
- .write = stderr_writer,
+ .write = fp_writer,
+ .data = fp
};
+ json_format_value (v, &fmt);
+ fputc ('\n', fp);
+}
+
+static void
+shttp_format_result (struct shttp_connection *conn, FILE *fp)
+{
fprintf (stderr, "%s: raw JSON reply follows:\n", program_name);
- json_format_value (conn->result, &fmt);
+ print_json (fp, conn->result);
}
static void
shttp_fatal (struct shttp_connection *conn)
{
struct json_value *jv;
if (conn->result && (jv = json_value_lookup (conn->result, "error_message")))
{
if (jv->type == json_string)
grecs_error (NULL, 0, "%s", jv->v.s);
else
- shttp_format_result (conn);
+ shttp_format_result (conn, stderr);
}
else
grecs_error (NULL, 0, "%s", conn->status_line[2]);
exit (1);
}
@@ -924,60 +934,360 @@ static void
shttp_process (struct shttp_connection *conn, int method, char const *uri)
{
for (;;)
{
shttp_request_send (conn, method, uri);
shttp_get_reply (conn);
+ if (dump && conn->result)
+ shttp_format_result (conn, stdout);
if (conn->resp.code / 100 == 2)
return;
if (conn->resp.code == 401 && isatty (fileno (stdin)))
shttp_get_credentials (conn);
else
shttp_fatal (conn);
}
}
+static struct json_value *
+shttp_getval (struct shttp_connection *conn, char const *name,
+ enum json_value_type type)
+{
+ struct json_value *p = NULL;
+
+ switch (json_object_get (conn->result, name, &p))
+ {
+ case 0:
+ if (p->type != type)
+ {
+ grecs_error (NULL, 0, _("\"%s\" has wrong type"), name);
+ p = NULL;
+ }
+ break;
+
+ case 1:
+ grecs_error (NULL, 0, _("no \"%s\" member"), name);
+ break;
+
+ default:
+ grecs_error (NULL, errno, _("can't get value of \"%s\""), name);
+ }
+ return p;
+}
+
+struct kwtrans
+{
+ char const *name;
+ int c;
+};
+
+struct kwtrans mode_trans[] = {
+ { "exec", 'C' },
+ { "accept", 'A' },
+ { "inetd", 'I' },
+ { "pass_fd", 'P' },
+ { "wait", 'W' },
+ { "once", 'c' },
+ { "boot", 'B' },
+ { "bootwait", 'w' },
+ { "powerfail", 'F' },
+ { "powerwait", 'f' },
+ { "powerokwait", 'o' },
+ { "ctrlaltdel", '3' },
+ { "ondemand", 'D' },
+ { "sysinit", 'i' },
+ { "powerfailnow", 'n' },
+ { "kbrequest", 'k' },
+ { NULL }
+};
+
+struct kwtrans status_trans[] = {
+ { "enabled", 'R' },
+ { "disabled", 'D' },
+ { "listener", 'L' },
+ { "sleeping", 's' },
+ { "stopping", 'S' },
+ { "finished", 'f' },
+ { NULL }
+};
+
+static int
+kwtoc (char const *s, struct kwtrans const *trans)
+{
+ for (; trans->name; trans++)
+ {
+ if (strcmp (trans->name, s) == 0)
+ return trans->c;
+ }
+ return '-';
+}
+
+static struct json_value *
+getval (struct json_value *v, char const *name, enum json_value_type type,
+ int optional)
+{
+ struct json_value *p = NULL;
+
+ switch (json_object_get (v, name, &p))
+ {
+ case 0:
+ if (p->type != type)
+ {
+ grecs_error (NULL, 0, _("\"%s\" has wrong type"), name);
+ p = NULL;
+ }
+ break;
+
+ case 1:
+ if (!optional)
+ grecs_error (NULL, 0, _("no \"%s\" member"), name);
+ break;
+
+ default:
+ grecs_error (NULL, errno, _("can't get value of \"%s\""), name);
+ }
+ return p;
+}
+
+static void
+print_comp (FILE *fp, struct json_value *v, size_t n)
+{
+ struct json_value *p;
+ char const *type;
+ char fbuf[5];
+ int fidx = 0;
+ int status = -1;
+
+ if (v->type != json_object)
+ {
+ grecs_error (NULL, 0, _("%lu: unexpected value type"),
+ (unsigned long) n);
+ print_json (fp, v);
+ return;
+ }
+
+ p = getval (v, "type", json_string, 0);
+ if (!p)
+ {
+ print_json (fp, v);
+ return;
+ }
+ type = p->v.s;
+
+ p = getval (v, "tag", json_string, 0);
+ if (!p)
+ {
+ print_json (fp, v);
+ return;
+ }
+
+ fprintf (fp, "%-16s ", p->v.s);
+
+ if (strcmp (type, "component") == 0)
+ {
+ p = getval (v, "mode", json_string, 0);
+ if (v)
+ fbuf[fidx++] = kwtoc (p->v.s, mode_trans);
+ else
+ fbuf[fidx++] = '-';
+ p = getval (v, "status", json_string, 0);
+ if (p)
+ fbuf[fidx++] = status = kwtoc (p->v.s, status_trans);
+ else
+ fbuf[fidx++] = '-';
+ }
+ else if (strcmp (type, "redirector") == 0)
+ {
+ fbuf[fidx++] = 'R';
+ }
+ else if (strcmp (type, "command") == 0)
+ {
+ fbuf[fidx++] = 'E';
+ }
+ else
+ {
+ fbuf[fidx++] = '-';
+ }
+
+ fbuf[fidx++] = 0;
+ fprintf (fp, "%-8.8s ", fbuf);
+
+ if (strcmp (type, "component") == 0)
+ {
+ p = getval (v, "PID", json_number, 1);
+ if (p)
+ fprintf (fp, "%10.0f ", p->v.n);
+ else if (status == 'L' /* listener */
+ && (p = getval (v, "URL", json_string, 1)))
+ fprintf (fp, "%-10s ", p->v.s);
+ else
+ fprintf (fp, "%-10s ", "N/A");
+
+ if (status == 's') /* sleeping */
+ {
+ p = getval (v, "wakeup-time", json_number, 0);
+ if (p)
+ {
+ time_t t = (time_t) p->v.n;
+ fprintftime (fp, "%H:%M:%S", localtime (&t), 0, 0);
+ }
+ }
+
+ p = getval (v, "argv", json_arr, 0);
+ if (p)
+ {
+ size_t i, n = json_array_size (p);
+
+ for (i = 0; i < n; i++)
+ {
+ struct json_value *elt;
+ if (json_array_get (p, i, &elt) == 0)
+ fprintf (fp, " %s", elt->v.s);
+ }
+ }
+ }
+ else if (strcmp (type, "redirector") == 0)
+ {
+ p = getval (v, "PID", json_number, 0);
+ if (p)
+ fprintf (fp, "%10.0f ", p->v.n);
+ }
+ else if (strcmp (type, "command") == 0)
+ {
+ p = getval (v, "command", json_string, 0);
+ if (p)
+ fprintf (fp, "%s", p->v.s);
+ }
+ fputc ('\n', fp);
+}
+
static int
com_list (struct shttp_connection *conn, int argc, char **argv)
{
shttp_process (conn, METH_GET, "/programs");
+ if (!dump && conn->result && conn->result->type == json_arr)
+ {
+ size_t i, n = json_array_size (conn->result);
+
+ for (i = 0; i < n; i++)
+ {
+ struct json_value *v;
+
+ if (json_array_get (conn->result, i, &v) == 0)
+ print_comp (stdout, v, i);
+ }
+ }
return 0;
}
static int
com_stop (struct shttp_connection *conn, int argc, char **argv)
{
- abort ();
+ char *buf = NULL;
+ size_t len = 0;
+ size_t i;
+
+ for (i = 1; i < argc; i++)
+ {
+ struct json_value *v;
+ grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_process (conn, METH_DELETE, buf);
+ v = shttp_getval (conn, "error_message", json_string);
+ if (v)
+ printf ("%s: %s\n", argv[i], v->v.s);
+ }
+ free (buf);
return 0;
}
static int
com_start (struct shttp_connection *conn, int argc, char **argv)
{
- abort ();
+ char *buf = NULL;
+ size_t len = 0;
+ size_t i;
+
+ for (i = 1; i < argc; i++)
+ {
+ struct json_value *v;
+ grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_process (conn, METH_PUT, buf);
+ v = shttp_getval (conn, "error_message", json_string);
+ if (v)
+ printf ("%s: %s\n", argv[i], v->v.s);
+ }
+ free (buf);
return 0;
}
static int
com_restart (struct shttp_connection *conn, int argc, char **argv)
{
abort ();
return 0;
}
static int
+com_id (struct shttp_connection *conn, int argc, char **argv)
+{
+ struct json_value *v;
+
+ if (argc == 1)
+ {
+ size_t i;
+ static char *keywords[] = {
+ "package",
+ "version",
+ "instance",
+ "binary",
+ };
+
+ shttp_process (conn, METH_GET, "/instance");
+
+ for (i = 0; i < sizeof (keywords)/ sizeof (keywords[0]); i++)
+ {
+ v = shttp_getval (conn, keywords[i], json_string);
+ if (v)
+ printf ("%s: %s\n", keywords[i], v->v.s);
+ }
+ v = shttp_getval (conn, "PID", json_number);
+ if (v)
+ printf ("PID: %.0f\n", v->v.n);
+ }
+ else
+ {
+ char *buf = NULL;
+ size_t size = 0;
+ size_t i;
+
+ for (i = 1; i < argc; i++)
+ {
+ grecs_asprintf (&buf, &size, "/instance/%s", argv[i]);
+ shttp_process (conn, METH_GET, buf);
+ if (json_object_get (conn->result, argv[i], &v) == 0)
+ {
+ printf ("%s: ", argv[i]);
+ print_json (stdout, v);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
com_shutdown (struct shttp_connection *conn, int argc, char **argv)
{
- abort ();
+ shttp_process (conn, METH_DELETE, "/instance/PID");
return 0;
}
static int
com_reboot (struct shttp_connection *conn, int argc, char **argv)
{
- abort ();
+ shttp_process (conn, METH_PUT, "/instance/PID");
return 0;
}
typedef int (*ctlcom_t) (struct shttp_connection *, int, char **);
struct comtab
@@ -988,12 +1298,13 @@ struct comtab
static struct comtab comtab[] = {
{ "list", com_list },
{ "stop", com_stop },
{ "start", com_start },
{ "restart", com_restart },
+ { "id", com_id },
{ "shutdown", com_shutdown },
{ "reboot", com_reboot },
{ NULL }
};
static struct comtab *
@@ -1049,12 +1360,17 @@ main (int argc, char **argv)
#endif
grecs_print_diag_fun = piesctl_diag;
parse_options (argc, argv, &i);
argc -= i;
argv += i;
+ if (argc == 0)
+ {
+ grecs_error (NULL, 0, _("not enough arguments"));
+ exit (EX_USAGE);
+ }
parse_config ();
conn = shttp_connect (url);
if (!conn)
return EX_UNAVAILABLE;

Return to:

Send suggestions and report system problems to the System administrator.