[Initng-svn] r3189 - initng/trunk/plugins/ngcs
svn at initng.thinktux.net
svn at initng.thinktux.net
Sat Mar 4 03:11:37 CET 2006
Author: makomk
Date: Sat Mar 4 03:11:37 2006
New Revision: 3189
Added:
initng/trunk/plugins/ngcs/initng_ngcs_cmds.h
Modified:
initng/trunk/plugins/ngcs/Makefile.am
initng/trunk/plugins/ngcs/idef.py
initng/trunk/plugins/ngcs/initng_ngcs.c
initng/trunk/plugins/ngcs/initng_ngcs.h
initng/trunk/plugins/ngcs/initng_ngcs_cmds.c
initng/trunk/plugins/ngcs/ngcs.py
initng/trunk/plugins/ngcs/ngcs_common.c
initng/trunk/plugins/ngcs/ngcs_common.h
Log:
Various ngcs improvements - in particular, "ngcs.py -u service-name" can now be used
to start a service
Modified: initng/trunk/plugins/ngcs/Makefile.am
==============================================================================
--- initng/trunk/plugins/ngcs/Makefile.am (original)
+++ initng/trunk/plugins/ngcs/Makefile.am Sat Mar 4 03:11:37 2006
@@ -6,7 +6,9 @@
initng_ngcs.c \
initng_ngcs.h \
ngcs_common.c \
+ ngcs_common.h \
initng_ngcs_cmds.c \
+ initng_ngcs_cmds.h \
ngcs_marshal.c
libngcs_la_CFLAGS = $(AM_CFLAGS)
@@ -15,14 +17,16 @@
BUILT_SOURCES = ngcs_marshal.h
+EXTRA_DIST = ngcs_marshal.ngci idef.py ngcs.py
+
# ngcs_SOURCES = ngcs.c ngcs_common.c
# ngdcs_SOURCES = ngcs.c ngcs_common.c
install-data-hook:
rm -f $(DESTDIR)$(plugindir)/$(plugin_LTLIBRARIES)
-ngcs_marshal.c: ngcs_marshal.ngci
+ngcs_marshal.c: ngcs_marshal.ngci idef.py
./idef.py ngcs_marshal
-ngcs_marshal.h: ngcs_marshal.ngci
+ngcs_marshal.h: ngcs_marshal.ngci idef.py
./idef.py ngcs_marshal
Modified: initng/trunk/plugins/ngcs/idef.py
==============================================================================
--- initng/trunk/plugins/ngcs/idef.py (original)
+++ initng/trunk/plugins/ngcs/idef.py Sat Mar 4 03:11:37 2006
@@ -1,4 +1,23 @@
#!/usr/bin/python
+
+# Initng, a next generation sysvinit replacement.
+# Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
import re,sys
def mkmarshaler(name, members,sname=None):
@@ -80,13 +99,18 @@
if(s->@m[1]@)
{
#endif
+ @sp at if(buf) *(int*)buf = NGCS_TYPE_STRUCT;
#if isptr
@sp at n = ngcs_marshal_ at typename@(s->@m[1]@, (buf?buf+2*sizeof(int):NULL));
#else
@sp at n = ngcs_marshal_ at typename@(&s->@m[1]@, (buf?buf+2*sizeof(int):NULL));
#endif
@sp at if(n < 0) return n;
- @sp at if(buf) buf += 2*sizeof(int) + n;
+ @sp at if(buf)
+ @sp@{
+ @sp@ *(int*)(buf+sizeof(int)) = n;
+ @sp@ buf += 2*sizeof(int) + n;
+ @sp@}
@sp at len += 2*sizeof(int) + n;
#if isptr
}
Modified: initng/trunk/plugins/ngcs/initng_ngcs.c
==============================================================================
--- initng/trunk/plugins/ngcs/initng_ngcs.c (original)
+++ initng/trunk/plugins/ngcs/initng_ngcs.c Sat Mar 4 03:11:37 2006
@@ -2,6 +2,7 @@
/* Initng, a next generation sysvinit replacement.
* Copyright (C) 2005 neuron <neuron at hollowtube.mine.nu>
* Copyright (C) 2005 Jimmy Wennlund <jimmy.wennlund at gmail.com>
+ * Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -175,7 +176,7 @@
return;
}
-void data_ready(f_module_h * from) /* TODO */
+void data_ready(f_module_h * from)
{
int sock = from->fds;
int chanid, len, type, cnt;
@@ -193,7 +194,7 @@
closeconn(conn);
return;
}
- if (chanid == 0) /* channel 0 is the command channel */
+ if (chanid == 0) /* channel 0 is the command channel */
{
/* sanity checks on message */
if (len < 0)
@@ -280,7 +281,7 @@
ngcs_free_unpack(cnt, udata);
return;
}
- else /* other channels are handled by whoever opened them */
+ else /* other channels are handled by whoever opened them */
{
while_ngcs_chans(chan, conn) if (chan->id == chanid)
{
@@ -409,6 +410,12 @@
list_add(&cmd->list, &ngcs_cmds.list);
}
+void ngcs_unreg_cmd(ngcs_cmd* cmd)
+{
+ assert(cmd); assert(cmd->list.prev); assert(cmd->list.next);
+ list_del(&cmd->list);
+}
+
#if 0
/* Send a ping to ourselves to check if we're 100% ok. */
static int sendping()
Modified: initng/trunk/plugins/ngcs/initng_ngcs.h
==============================================================================
--- initng/trunk/plugins/ngcs/initng_ngcs.h (original)
+++ initng/trunk/plugins/ngcs/initng_ngcs.h Sat Mar 4 03:11:37 2006
@@ -18,6 +18,9 @@
* Boston, MA 02110-1301, USA.
*/
+#ifndef INITNG_NGCS_H
+#define INITNG_NGCS_H
+
#include "../../src/initng_active_db.h"
#include "../../src/initng_system_states.h"
#include "../../src/initng_list.h"
@@ -36,8 +39,33 @@
int service_status(active_db_h * service);
void is_system_halt(h_sys_state state);
+/*! \brief Close the specified channel
+ * Called to close a channel. Sends a message with length -1 on the channel to
+ * notify the client (if the connection is still open) and frees the ngcs_channel
+ * structure, calling the ngcs_channel.free callback first if there is one
+ *
+ * \param chan the channel to be closed
+ */
void ngcs_close_channel(ngcs_channel * chan);
+
+/* \brief Register an ngcs command
+ * Registers an ngcs command. ngcs clients can then call it by sending a
+ * suitably-structured message on channel 0, specifying the command name. If
+ * more than one registered command has the same name, the results are undefined.
+ *
+ * \param cmd structure describing the command - must not be freed, modified
+ * or passed to ngcs_reg_cmd again until ngcs_unreg_cmd(cmd) has been called
+ * \sa ngcs_unreg_cmd() ngcs_cmd
+ */
void ngcs_reg_cmd(ngcs_cmd * cmd);
+
+/* \brief Unregister an ngcs command
+ * Unregisters a command registered with ngcs_reg_cmd.
+ *
+ * \param cmd the ngcs_cmd structure passed to ngcs_reg_cmd
+ * \sa ngcs_reg_cmd()
+ */
+void ngcs_unreg_cmd(ngcs_cmd* cmd);
int ngcs_channel_send(ngcs_channel * chan, int type, int len, char *data);
ngcs_channel *ngcs_open_channel(ngcs_conn * conn,
void (*gotdata) (ngcs_channel *, int, int,
@@ -45,10 +73,27 @@
void (*chanfree) (ngcs_channel *));
int ngcs_send_response(ngcs_request * req, int type, int len, char *data);
+/*! \brief Ngcs command handler
+ *
+ * Represents an ngcs command handler. Ngcs commands are sent on channel 0 of
+ * a connection and are identified by a (case-sensitive) string, their name
+ *
+ * \sa ngcs_reg_cmd() ngcs_unreg_cmd()
+ */
struct ngcs_cmd_s
{
+ /*! \brief Name of the command */
const char *name;
+
+ /*! \brief Callback function to handle the request
+ *
+ * The callback function to handle the request. It should call ngcs_send_response
+ * exactly once to send a response to the request.
+ * \sa ngcs_send_response()
+ */
void (*func) (ngcs_request * req);
+
+ /* \brief List head - internal use */
struct list_head list;
};
@@ -95,3 +140,5 @@
#define while_ngcs_cmds(current) list_for_each_entry_prev(current, &ngcs_cmds.list, list)
#define while_ngcs_cmds_safe(current, safe) list_for_each_entry_prev_safe(current, safe, &ngcs_cmds.list, list)
+
+#endif /* !INITNG_NGCS_H */
Modified: initng/trunk/plugins/ngcs/initng_ngcs_cmds.c
==============================================================================
--- initng/trunk/plugins/ngcs/initng_ngcs_cmds.c (original)
+++ initng/trunk/plugins/ngcs/initng_ngcs_cmds.c Sat Mar 4 03:11:37 2006
@@ -1,3 +1,24 @@
+/* Initng, a next generation sysvinit replacement.
+ * Copyright (C) 2005 Jimmy Wennlund <jimmy.wennlund at gmail.com>
+ * Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
#include "../../src/initng.h"
#include <stdio.h>
@@ -34,6 +55,15 @@
#include "../../initng-paths.h"
#include "initng_ngcs.h"
#include "ngcs_marshal.h"
+#include "initng_ngcs_cmds.h"
+
+typedef struct ngcs_watch_s
+{
+ ngcs_channel *chan;
+ char *name;
+ int flags;
+ struct list_head list;
+} ngcs_watch;
void register_ngcs_cmds(void);
void unregister_ngcs_cmds(void);
@@ -42,7 +72,10 @@
static int service_status_watch(active_db_h * service);
static void ngcs_cmd_watch(ngcs_request * req);
static void ngcs_free_watch(ngcs_channel * chan);
-static int service_output_watch(active_db_h * service, process_h * x);
+static int service_output_watch(active_db_h * service, process_h * x, char *buffer_pos);
+static ngcs_watch* ngcs_add_watch(ngcs_conn* conn, char* svcname, int flags);
+static void ngcs_cmd_start(ngcs_request * req);
+static int ngcs_watch_initial(ngcs_watch *watch);
ngcs_cmd ngcs_halt_cmd = {
"halt",
@@ -51,27 +84,27 @@
};
ngcs_cmd ngcs_reboot_cmd = {
- "halt",
+ "reboot",
ngcs_cmd_reboot,
{0, 0}
};
+ngcs_cmd ngcs_start_cmd = {
+ "start",
+ ngcs_cmd_start,
+ {0, 0}
+};
+
ngcs_cmd ngcs_watch_cmd = {
"watch",
ngcs_cmd_watch,
{0, 0}
};
-typedef struct ngcs_watch_s
-{
- ngcs_channel *chan;
- char *name;
- struct list_head list;
-} ngcs_watch;
ngcs_watch watches;
-int service_status_watch(active_db_h * service)
+static int service_status_watch(active_db_h * service)
{
ngcs_watch *watch, *nextwatch;
int len = 0;
@@ -93,14 +126,52 @@
return TRUE;
}
}
- ngcs_channel_send(watch->chan, NGCS_TYPE_STRUCT, len, buf);
- }
+ if(ngcs_channel_send(watch->chan, NGCS_TYPE_STRUCT, len, buf))
+ {
+ free(buf); return TRUE;
+ };
+ }
}
if (buf)
free(buf);
return TRUE;
}
+static int ngcs_watch_initial(ngcs_watch *watch)
+{
+ if(watch->flags & NGCS_CURRENT_STATUS)
+ {
+ active_db_h* current;
+ current = NULL;
+ while_active_db(current)
+ {
+ if(watch->name == NULL || strcmp(watch->name, current->name) == 0)
+ {
+ int len = 0; char *buf = NULL;
+ len = ngcs_marshal_active_db_h(current, NULL);
+ buf = i_calloc(1, len);
+ len = ngcs_marshal_active_db_h(current, buf);
+ if (len < 0)
+ {
+ F_("ngcs_marshal_active_db_h() failed!\n");
+ free(buf);
+ return 1;
+ }
+ if(ngcs_channel_send(watch->chan, NGCS_TYPE_STRUCT, len, buf))
+ {
+ free(buf); return 1;
+ };
+ free(buf);
+ }
+ }
+ }
+
+ if(ngcs_channel_send(watch->chan, NGCS_TYPE_NULL, 0, NULL))
+ return 1;
+
+ return 0;
+}
+
static int service_output_watch(active_db_h * service, process_h * x, char *buffer_pos)
{
ngcs_watch *watch, *nextwatch;
@@ -123,10 +194,13 @@
len = ngcs_pack(dat, 2, NULL);
assert(len >= 0);
buf = i_calloc(1, len);
- len = ngcs_pack(dat, 2, NULL);
+ len = ngcs_pack(dat, 2, buf);
assert(len >= 0);
}
- ngcs_channel_send(watch->chan, NGCS_TYPE_STRUCT, len, buf);
+ if(ngcs_channel_send(watch->chan, NGCS_TYPE_STRUCT, len, buf))
+ {
+ free(buf); return FALSE;
+ };
}
}
if (buf)
@@ -134,36 +208,137 @@
return FALSE;
}
-void ngcs_cmd_watch(ngcs_request * req)
+static void ngcs_cmd_start(ngcs_request * req)
+{
+ int i = 0; ngcs_watch* watch;
+ active_db_h *serv = NULL; char* svcname = NULL;
+ if(req->type != NGCS_TYPE_STRING || req->data == NULL || req->len <= 0)
+ {
+ F_("Bad call to ngcs command 'start'\n");
+ ngcs_send_response(req, NGCS_TYPE_STRING, 8, (char*)"BAD_CALL");
+ return;
+ }
+
+ svcname = i_calloc(1, req->len+1);
+ memcpy(svcname, req->data, req->len);
+
+ serv = initng_active_db_find_in_name(svcname);
+ if (serv)
+ {
+ watch = ngcs_add_watch(req->conn, serv->name, NGCS_WATCH_STATUS | NGCS_WATCH_OUTPUT |
+ NGCS_CURRENT_STATUS);
+ if(watch) i = watch->chan->id;
+ ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ ngcs_watch_initial(watch);
+ if (!IS_UP(serv))
+ initng_handler_start_service(serv);
+ free(svcname); return;
+ }
+
+ serv = initng_handler_start_new_service_named(svcname);
+ if (!serv)
+ {
+ ngcs_send_response(req, NGCS_TYPE_STRING, 9, (char*)"NOT_FOUND");
+ free(svcname); return;
+ }
+
+ watch = ngcs_add_watch(req->conn, serv->name, NGCS_WATCH_STATUS | NGCS_WATCH_OUTPUT);
+ if(watch) i = watch->chan->id;
+ ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ ngcs_watch_initial(watch); free(svcname); return;
+}
+
+ngcs_watch* ngcs_add_watch(ngcs_conn* conn, char* svcname, int flags)
{
+ assert(conn);
ngcs_channel *chan;
ngcs_watch *watch;
- int i = 0;
-
- chan = ngcs_open_channel(req->conn, NULL, ngcs_free_watch);
- if (!chan)
- return;
watch = i_calloc(1, sizeof(ngcs_watch));
- watch->chan = chan;
- if (req->type != NGCS_TYPE_STRING || req->len <= 0)
- {
- watch->name = NULL;
- }
- else
+ chan = ngcs_open_channel(conn, NULL, ngcs_free_watch);
+ if (!chan)
{
- watch->name = i_calloc(1, req->len + 1);
- memcpy(watch->name, req->data, req->len);
+ F_("ngcs_open_channel failed!\n");
+ free(watch); return 0;
}
+ if(svcname)
+ watch->name = i_strdup(svcname);
+ else watch->name = NULL;
+ watch->flags = flags;
+ watch->chan = chan;
watch->list.prev = 0;
watch->list.next = 0;
list_add(&watch->list, &watches.list);
chan->user_data = watch;
- i = chan->id;
+ return watch;
+}
+
+static void ngcs_cmd_watch(ngcs_request * req)
+{
+ int i = 0, cnt;
+ ngcs_data* data; ngcs_watch *watch;
+ char* name = NULL; int flags;
+
+ if(req->type == NGCS_TYPE_STRING)
+ {
+ W_("Use of watch(STRING) depreciated - please update client code\n");
+ if(req->len <= 0 || !req->data)
+ {
+ name = NULL;
+ }
+ else
+ {
+ name = i_calloc(1, req->len + 1);
+ memcpy(name, req->data, req->len);
+ }
+ flags = NGCS_WATCH_STATUS | NGCS_WATCH_OUTPUT;
+ }
+ else if(req->type == NGCS_TYPE_STRUCT)
+ {
+ cnt = ngcs_unpack(req->data, req->len, &data);
+ if(cnt < 0)
+ {
+ F_("Bad watch command\n");
+ ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ return;
+ }
+ if(cnt != 2 || data[1].type != NGCS_TYPE_INT)
+ {
+ F_("Bad watch command\n"); free(data);
+ ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ return;
+ }
+ flags = data[1].d.i;
+ if(data[0].type == NGCS_TYPE_NULL || (data[0].type = NGCS_TYPE_STRING &&
+ data[0].len <= 0))
+ {
+ name = NULL;
+ }
+ else if(data[0].type == NGCS_TYPE_STRING)
+ {
+ name = i_strdup(data[0].d.s);
+ }
+ }
+ else if(req->type == NGCS_TYPE_NULL)
+ {
+ W_("Use of watch(NULL) depreciated - please update client code\n");
+ name = NULL;
+ flags = NGCS_WATCH_STATUS | NGCS_WATCH_OUTPUT;
+ }
+ else
+ {
+ F_("Bad watch command\n");
+ ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ return;
+ }
+ watch = ngcs_add_watch(req->conn, name, flags);
+ if(watch) i = watch->chan->id;
ngcs_send_response(req, NGCS_TYPE_INT, sizeof(int), (char *) &i);
+ if(name) free(name);
+ ngcs_watch_initial(watch);
}
-void ngcs_free_watch(ngcs_channel * chan)
+static void ngcs_free_watch(ngcs_channel * chan)
{
ngcs_watch *watch = chan->user_data;
@@ -179,6 +354,7 @@
void register_ngcs_cmds(void)
{
ngcs_reg_cmd(&ngcs_halt_cmd);
+ ngcs_reg_cmd(&ngcs_start_cmd);
ngcs_reg_cmd(&ngcs_reboot_cmd);
ngcs_reg_cmd(&ngcs_watch_cmd);
initng_plugin_hook_add(&g.ASTATUS_CHANGE, 50, &service_status_watch);
@@ -190,7 +366,11 @@
{
initng_plugin_hook_del(&g.ASTATUS_CHANGE, &service_status_watch);
initng_plugin_hook_del(&g.PIPEWATCHERS, &service_output_watch);
- /* TODO */
+ ngcs_unreg_cmd(&ngcs_halt_cmd);
+ ngcs_unreg_cmd(&ngcs_start_cmd);
+ ngcs_unreg_cmd(&ngcs_reboot_cmd);
+ ngcs_unreg_cmd(&ngcs_watch_cmd);
+ /* TODO - need to free watches */
}
static void ngcs_cmd_halt(ngcs_request * req)
Modified: initng/trunk/plugins/ngcs/ngcs.py
==============================================================================
--- initng/trunk/plugins/ngcs/ngcs.py (original)
+++ initng/trunk/plugins/ngcs/ngcs.py Sat Mar 4 03:11:37 2006
@@ -1,5 +1,27 @@
+#!/usr/bin/python
+
+# Initng, a next generation sysvinit replacement.
+# Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
import socket,sys,struct
+from select import select, poll
from types import *
+from errno import EAGAIN, EWOULDBLOCK
NGCS_TYPE_NONE = 0
NGCS_TYPE_INT = 1
@@ -10,6 +32,15 @@
SIZEOF_INT = struct.calcsize("@i")
+IS_UNKNOWN = 0
+IS_UP = 1
+IS_DOWN = 2
+IS_FAILED = 3
+IS_STARTING = 4
+IS_STOPPING = 5
+IS_WAITING = 6
+
+
sock = 0;
class NgcsData:
@@ -23,7 +54,192 @@
def __init__(self,i):
self.val = i
def __repr__(self):
- return "NgcsError("+repr(self.val)+")"
+ return "NgcsEOF("+repr(self.val)+")"
+
+class AsyncConnect:
+ def __init__(self):
+ self.sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
+ self.sock.connect("/dev/initng/initng.ngcs")
+ self.sock.setblocking(0)
+ self._recvbuf = ""
+ self._sendbuf = ""
+ self._head = None
+ self._chans = { }
+ self.reg_channel(0, self._chan_0)
+ self._pending_req = [ ]
+
+ def close(self):
+ self.sock.close()
+ self.sock = None
+
+ def _chan_0(self, conn, chan, data):
+ if len(self._pending_req) == 0:
+ sys.stderr.write("Unexpected response on channel 0\n")
+ return
+ self._pending_req.pop(0)(data)
+
+ def send_cmd(self, cmd, callback):
+ self._pending_req.append(callback)
+ self.send(0, cmd)
+
+ def send(self, chan, msg):
+ msg = ngcs_pack(msg)
+ self._sendbuf += struct.pack("@iii",chan,msg.typecode,len(msg.data)) + msg.data
+ self.try_send()
+
+ def try_send(self):
+ try:
+ ret = self.sock.send(self._sendbuf)
+ self._sendbuf = self._sendbuf[ret:]
+ except socket.error, e:
+ if e[0] != EAGAIN and e[0] != EWOULDBLOCK:
+ raise
+
+ def unhandled_data_hook(self, chan, data):
+ pass
+
+ def reg_channel(self, chan, hook):
+ self._chans[chan] = hook
+
+ def unreg_channel(self, chan):
+ del self._chans[chan]
+
+ def try_recv(self):
+ while True:
+ try:
+ ret = self.sock.recv(4096)
+ except socket.error, e:
+ if e[0] == EAGAIN:
+ break
+ else:
+ raise
+ if len(ret) == 0: break
+ self._recvbuf += ret
+
+ while True:
+ if self._head == None:
+ if len(self._recvbuf) < 3*SIZEOF_INT: break
+ self._head = struct.unpack("@iii",self._recvbuf[:3*SIZEOF_INT])
+ self._recvbuf = self._recvbuf[3*SIZEOF_INT:]
+ else:
+ if len(self._recvbuf) < self._head[2]: break
+ (chan, type, l) = self._head; self._head = None
+ if l < 0:
+ data = NgcsEOF(l)
+ else:
+ data = NgcsData(type, self._recvbuf[:l])
+ self._recvbuf = self._recvbuf[l:]
+ if(self._chans.has_key(chan)):
+ self._chans[chan](self, chan, data)
+ else:
+ self.unhandled_data_hook(chan, data)
+
+class _NgcsCmds:
+ def __init__(self, conn):
+ self.conn = conn
+ self.cmds = [ ]
+ self.success = True
+
+ def add(self, cmd):
+ self.cmds.append(cmd)
+
+ def rem(self, cmd):
+ self.cmds.remove(cmd)
+
+ def fail(self):
+ self.success = False
+
+ def mainloop(self):
+ while len(self.cmds) > 0:
+ res = select((self.conn.sock,),(self.conn.sock,),(self.conn.sock,))
+ if self.conn.sock in res[0]:
+ self.conn.try_recv()
+ if self.conn.sock in res[1]:
+ self.conn.try_send()
+ if self.conn.sock in res[2]:
+ return False
+ return self.success
+
+class _NgcsCmd:
+ def __init__(self, cmds, cmd, txt):
+ if not isinstance(cmds, _NgcsCmds): raise TypeError
+ self._cmds = cmds
+ self._txt = txt
+ cmds.add(self)
+ cmds.conn.send_cmd(cmd, self._resp_cb)
+
+ def _resp_cb(self, resp):
+ self._cmds.rem(self)
+ if isinstance(resp, NgcsEOF):
+ sys.stderr.write("FAILED " + self._txt + ": unknown server error\n")
+ self._cmds.fail(); return
+ resp = ngcs_unpack(resp)
+ if resp == None:
+ sys.stderr.write("FAILED " + self._txt + ": couldn't run command\n")
+ self._cmds.fail(); return
+ elif isinstance(resp, StringType):
+ sys.stderr.write("FAILED " + self._txt + ": " + resp + "\n")
+ self._cmds.fail(); return
+ elif isinstance(resp, IntType):
+ sys.stderr.write("SUCCESS " + self._txt + "\n")
+ return
+ else:
+ sys.stderr.write("FAILED " + self._txt + ": unknown response\n")
+ self._cmds.fail(); return
+
+class _NgcsStartStopCmd (_NgcsCmd):
+ def __init__(self, cmds, cmd, svc):
+ _NgcsCmd.__init__(self, cmds, (cmd,svc), cmd + " " + svc)
+ self._svc = svc
+ self._cmd = cmd
+ self._rtmark = False
+
+ def _resp_cb(self, resp):
+ resp = ngcs_unpack(resp)
+ if isinstance(resp, IntType):
+ if resp == 0:
+ sys.stderr.write("FAILED " + self._txt + ": didn't get channel\n")
+ self._cmds.fail(); return
+ self._chan = resp
+ self._cmds.conn.reg_channel(resp, self._chan_cb)
+ else:
+ return _NgcsCmd._resp_cb(self, resp)
+
+ def _state_check(self, state):
+ pass
+
+ def _chan_cb(self, conn, chan, data):
+ data = ngcs_unpack(data)
+ if data == None:
+ self._rtmark = True
+ if not isinstance(data, TupleType) or len(data) < 2 or not isinstance(data[0], str):
+ return
+ self._svc = data[0]
+ self._text = "start %s" % data[0]
+ if isinstance(data[1], str):
+ sys.stderr.write(self._svc + " output:\n" + data[1])
+ elif isinstance(data[1], tuple):
+ state = data[2]
+ if self._rtmark:
+ sys.stderr.write("%s: %s\n" % (self._svc, state[0]));
+ self._state_check(state)
+
+ def _done(self):
+ self._cmds.rem(self); self._cmds.conn.unreg_channel(self._chan);
+
+class _NgcsStartCmd(_NgcsStartStopCmd):
+ def __init__(self, cmds, svc):
+ _NgcsStartStopCmd.__init__(self, cmds, "start", svc)
+
+ def _state_check(self, state):
+ if state[1] == IS_STARTING:
+ pass
+ elif state[1] in (IS_UP, IS_WAITING):
+ sys.stderr.write("Service %s started succesfully (%s)\n" % (self._svc, state[0]))
+ self._done()
+ elif self._rtmark:
+ sys.stderr.write("Service %s failed to start (%s)\n" % (self._svc, state[0]))
+ self._done(); self._cmds.fail()
def connect():
global sock;
@@ -38,7 +254,9 @@
sock.sendall(msg.data)
def ngcs_pack(datum):
- if isinstance(datum, IntType):
+ if isinstance(datum, NoneType):
+ return NgcsData(NGCS_TYPE_NONE,"");
+ elif isinstance(datum, IntType):
return NgcsData(NGCS_TYPE_INT,struct.pack("@i",datum));
elif isinstance(datum, StringType):
return NgcsData(NGCS_TYPE_STRING,datum);
@@ -56,6 +274,8 @@
def ngcs_unpack(data):
if not isinstance(data, NgcsData):
return data
+ elif data.typecode == NGCS_TYPE_NONE:
+ return None
elif data.typecode == NGCS_TYPE_INT:
return struct.unpack("@i", data.data)[0]
elif data.typecode == NGCS_TYPE_LONG:
@@ -109,6 +329,51 @@
elif chan != 0 and msg[0] == chan and isinstance(msg[1],NgcsEOF):
print "---End---"; break
+_simple_cmds = { "-6": ("reboot", False, "initiate reboot"), "-0": ("halt", False, "initiate shutdown") }
+_simple_cmds["--halt"] = _simple_cmds["-0"]
+_simple_cmds["--reboot"] = _simple_cmds["-6"]
+
+
+
+def _main():
+ cmd = None; cmdlist = []; cmdargs = []; success = True
+ for a in sys.argv[1:]:
+ if len(a) < 1: continue
+ if a[0] == '-':
+ if cmd != None:
+ cmdlist.append((cmd, cmdargs))
+ cmd = a; cmdargs = []
+ else:
+ cmdargs.append(a)
+ if cmd != None:
+ cmdlist.append((cmd, cmdargs))
+
+ conn = AsyncConnect()
+ wcmds = _NgcsCmds(conn)
+ for c in cmdlist:
+ if _simple_cmds.has_key(c[0]):
+ cd = _simple_cmds[c[0]]
+ if len(c[1]) > 0 and not cd[1]:
+ sys.stderr.write("Error: " + c[0] + " takes no options\n")
+ success = False
+ if cd[1]:
+ for arg in c[1]:
+ _NgcsCmd(wcmds, (cd[0],arg), cd[2])
+ else:
+ _NgcsCmd(wcmds, (cd[0],), cd[2])
+ elif cmd in ("-u","--start"):
+ for arg in c[1]:
+ _NgcsStartCmd(wcmds,arg)
+ else:
+ sys.stderr.write("Error: unknown command "+c[0]+"\n")
+
+ success = False
+ if not wcmds.mainloop(): success = False
+ conn.close()
+ if success:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
if __name__=='__main__':
- connect()
- ez_cmd("watch","daemon/agetty/5")
+ _main()
Modified: initng/trunk/plugins/ngcs/ngcs_common.c
==============================================================================
--- initng/trunk/plugins/ngcs/ngcs_common.c (original)
+++ initng/trunk/plugins/ngcs/ngcs_common.c Sat Mar 4 03:11:37 2006
@@ -1,3 +1,22 @@
+/* Initng, a next generation sysvinit replacement.
+ * Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
#include <stdlib.h>
#include "ngcs_common.h"
#include <sys/socket.h>
@@ -16,7 +35,7 @@
* \param chan the channel number the message is marked with
* \param type the data type of the message (typically one of the NGCS_TYPE
* constants)
- * \param len the length of the message (in bytes)
+ * \param len the length of the message body (in bytes)
* \param data the message body
* \return Zero on success, non-zero on failure
* \sa ngcs_recvmsg(), ngcs_pack()
@@ -50,9 +69,9 @@
* should be stored
* \param type a pointer to a location where the data type of the message
* should be stored
- * \param len a pointer to a location where the length of the message should be
- * stored. On return, *len may be less than zero, in which case *data is
- * set to NULL
+ * \param len a pointer to a location where the length of the message body (in bytes)
+ * should be stored. On return, *len may be less than zero, in which case
+ * *data is set to NULL
* \param data a location where a pointer to the message body is stored. *data is
* valid on return if ngcs_recvmsg() succeeded with *len>=0, and in this case
* must be free()d by the caller after use.
@@ -85,10 +104,29 @@
return 0;
}
+
+/*! \brief Pack an ngcs stucture for transmission
+ *
+ * This function packs a sequence of items into a buffer, which can be transmitted
+ * down a socket or otherwise transferred, then unpacked by ngcs_unpack()
+ * The resulting packed data strcuture should be transmitted marked as type
+ * NGCS_TYPE_STRUCT.
+ *
+ * Since the caller must ensure that the buffer is large enough, your code should
+ * call ngcs_pack with buf=NULL to get the required size, then allocate a buffer
+ * and call it again with the same data an the newly-allocated buffer
+ *
+ * \param data an array of structures describing the items of data to pack
+ * \param cnt the number of items to pack (the length of data[])
+ * \param buf the buffer into which to pack the data. May be null, in which case
+ * the required buffer size is returned
+ *
+ * \return the total packed length of the data, in bytes
+ */
int ngcs_pack(ngcs_data * data, int cnt, char *buf)
{
int n;
- int outcnt;
+ int outcnt = 0;
for (n = 0; n < cnt; n++)
{
@@ -147,9 +185,26 @@
break;
}
}
- return 0;
+ return outcnt;
}
+/*! /brief Unpack a received structure
+ *
+ * This is the reverse of ngcs_pack() - given packed data representing a
+ * structure, it creates an array of ngcs_data structures representing the
+ * contents of the structure. If you receive data marked as type
+ * NGCS_TYPE_STRUCT, you should be able to unpack it using this function.
+ *
+ * Note that this function allocates memory, which you must call
+ * ngcs_free_unpack(*res) to free once you're done. However, you must *not*
+ * do so if ngcs_unpack() fails (ie. if return value is < 0).
+ *
+ * /param data the packed data representing the structure
+ * /param len the length of data, in bytes
+ * /param res a location where a pointer to an array of ngcs_data structures,
+ * representing the result of unpacking the data, is returned.
+ * /return the number of items unpacked, or -1 on error
+ */
int ngcs_unpack(const char *data, int len, ngcs_data ** res)
{
const char *d = data;
@@ -238,6 +293,15 @@
return cnt;
}
+
+/*! \brief Frees the memory allocated by ngcs_unpack()
+ *
+ * Once you're done with the results of ngcs_unpack(), you should
+ * call this method to free the memory allocated by it.
+ *
+ * /param len the number of data items unpacked (that is, the return value of ngcs_unpack())
+ * /param res the array of ngcs_data structures returned by ngcs_unpack in its *res parameter
+ */
void ngcs_free_unpack(int len, ngcs_data * res)
{
int n;
Modified: initng/trunk/plugins/ngcs/ngcs_common.h
==============================================================================
--- initng/trunk/plugins/ngcs/ngcs_common.h (original)
+++ initng/trunk/plugins/ngcs/ngcs_common.h Sat Mar 4 03:11:37 2006
@@ -1,3 +1,22 @@
+/* Initng, a next generation sysvinit replacement.
+ * Copyright (C) 2005-6 Aidan Thornton <makomk at lycos.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
#ifndef NGCS_COMMON_H
#define NGCS_COMMON_H
#include "../../initng-paths.h"
More information about the Initng-svn
mailing list