The Assimilation Project  based on Assimilation version 1.1.7.1474836767
resourcelsb.c
Go to the documentation of this file.
1 
22 #include <projectcommon.h>
23 #include <string.h>
24 #define RESOURCECMD_SUBCLASS
25 #include <resourcecmd.h>
26 #include <resourcelsb.h>
27 
29 
34 
39 FSTATIC void _resourcelsb_child_notify(ChildProcess*, enum HowDied, int, int, gboolean);
40 
41 
42 static void (*_resourcelsb_save_finalize)(AssimObj*) = NULL;
43 
47 
50  guint structsize
51 , ConfigContext* request
52 , gpointer user_data
53 , ResourceCmdCallback callback)
54 {
55  ResourceCmd* cself;
56  ResourceLSB* self;
57  const char * restype;
58  char * lsbpath;
59 
61  restype = request->getstring(request, CONFIGNAME_TYPE);
62  if (NULL == restype) {
63  g_warning("%s.%d: No "CONFIGNAME_TYPE" field in LSB agent request."
64  , __FUNCTION__, __LINE__);
65  return NULL;
66  }
67  if (strchr(restype, '/') != NULL) {
68  g_warning("%s.%d: "CONFIGNAME_TYPE" field in LSB agent contains a slash."
69  , __FUNCTION__, __LINE__);
70  return NULL;
71  }
72 
73  lsbpath = g_build_filename(LSB_ROOT, restype, NULL);
74  if ( !g_file_test(lsbpath, G_FILE_TEST_IS_REGULAR)
75  || !g_file_test(lsbpath, G_FILE_TEST_IS_EXECUTABLE)) {
76  g_warning("%s.%d: No LSB Resource agent [%s]", __FUNCTION__, __LINE__
77  , lsbpath);
78  g_free(lsbpath); lsbpath = NULL;
79  return NULL;
80  }
81 
82  if (structsize < sizeof(ResourceLSB)) {
83  structsize = sizeof(ResourceLSB);
84  }
85  cself = resourcecmd_constructor(structsize, request, user_data, callback);
86  if (NULL == cself) {
87  return NULL;
88  }
89  if (!_resourcelsb_save_finalize) {
90  _resourcelsb_save_finalize = cself->baseclass._finalize;
91  }
94  self = NEWSUBCLASS(ResourceLSB, cself);
95  self->lsbpath = lsbpath;
96  self->baseclass.loggingname = g_strdup_printf("%s:%s: "
97  , self->baseclass.resourcename, self->baseclass.operation);
98  self->argv[0] = g_strdup(self->lsbpath);
99  if (strcmp(self->baseclass.operation, MONITOROP) == 0) {
100  self->argv[1] = g_strdup(STATUSOP);
101  }else{
102  self->argv[1] = g_strdup(self->baseclass.operation);
103  }
104  self->argv[2] = 0;
105  self->child = NULL;
106  return cself;
107 }
108 
110 void
112 {
113  ResourceLSB* self = CASTTOCLASS(ResourceLSB, aself);
114  guint j;
115 
116  DEBUGMSG2("Finalizing ResourceLSB @ %p: %s", self, self->baseclass.loggingname);
117  if (self->lsbpath) {
118  g_free(self->lsbpath);
119  self->lsbpath = NULL;
120  }
121  for (j=0; j < 3; ++j) {
122  g_free(self->argv[j]);
123  self->argv[j] = NULL;
124  }
125  if (self->child) {
126  DEBUGMSG5("%s.%d: UNREF child: (self=%p %s)", __FUNCTION__,__LINE__
127  , self->child, self->baseclass.loggingname);
128  UNREF(self->child);
129  }else{
130  DEBUGMSG5("%s.%d: NO CHILD TO UNREF (self=%p %s)", __FUNCTION__,__LINE__,self
131  , self->baseclass.loggingname);
132  }
133  if (self->baseclass.loggingname) {
134  g_free(self->baseclass.loggingname);
135  self->baseclass.loggingname = NULL;
136  }
137  _resourcelsb_save_finalize(aself);
138 }
139 
140 
142 FSTATIC void
144 {
145  ResourceLSB* self = CASTTOCLASS(ResourceLSB, cmdself);
146  enum ChildErrLogMode logmode;
147  gboolean save_stdout;
148 
149  DEBUGMSG3("%s.%d Executing(%s:%s)", __FUNCTION__, __LINE__
150  , self->baseclass.resourcename, self->baseclass.operation);
151  if (self->baseclass.is_running) {
152  g_warning("%s.%d: %s:%s is currently running. New request ignored."
153  , __FUNCTION__, __LINE__
154  , self->baseclass.resourcename, self->baseclass.operation);
155  return;
156  }
157  if (self->child) {
158  // Oh... A repeating operation
159  UNREF(self->child);
160  }
161  if (strcmp(self->baseclass.operation, METADATAOP) == 0) {
162  _resourcelsb_metadata(self);
163  return;
164  }
165  if (strcmp(self->baseclass.operation, VALIDATEOP) == 0) {
167  return;
168  }
169  save_stdout = (strcmp(self->baseclass.operation, MONITOROP) == 0);
170  logmode = (self->baseclass.callback ? CHILD_NOLOG : CHILD_LOGALL);
171 
172  self->baseclass.starttime = g_get_monotonic_time();
173 
174  self->child = childprocess_new
175  ( 0
176  , self->argv
177  , NULL
178  , NULL
179  , NULL
182  , save_stdout
183  , NULL
184  , self->baseclass.loggingname
185  , G_LOG_LEVEL_INFO
186  , self->baseclass.timeout_secs
187  , self
188  , logmode
189  , self->baseclass.loggingname
190  );
191  if (self->child) {
192  self->baseclass.is_running = TRUE;
193  REF2(self); // We can't go away while we're running no matter what...
194  // (this is undone after calling our callback function).
195  DEBUGMSG5("%s.%d: REF resourcelsb: %p", __FUNCTION__,__LINE__,self);
196  DEBUGMSG("%s.%d: spawned child: %p", __FUNCTION__,__LINE__,self->child);
197  }else{
198  DEBUGMSG("%s.%d: child spawning FAILED: %s:%s", __FUNCTION__,__LINE__
199  , self->baseclass.resourcename, self->baseclass.operation);
200  }
201 }
202 
206 FSTATIC void
208 {
209  char * metadata;
210  const char * restype = self->baseclass.request->getstring(self->baseclass.request
211  , CONFIGNAME_TYPE);
212 
213  metadata = g_strdup_printf(
214  "<?xml version=\"1.0\"?>\n"
215  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
216  "<resource-agent name=\"%s\" version=\"1.0\">\n"
217  " <version>1.0</version>\n"
218  " <longdesc lang=\"en\">%s LSB init script found at %s</longdesc>\n"
219  " <shortdesc lang=\"en\">%s</shortdesc>\n"
220  " <parameters/>\n"
221  " <actions>\n"
222  "\t<action name=\"start\" timeout=\"120\"/>\n"
223  "\t<action name=\"stop\" timeout=\"120\"/>\n"
224  "\t<action name=\"meta-data\" timeout=\"120\"/>\n"
225  "\t<action name=\"restart\" timeout=\"120\"/>\n"
226  "\t<action name=\"validate-all\" timeout=\"120\"/>\n"
227  " </actions>\n"
228  "</resource-agent>\n"
229  , restype
230  , restype, self->lsbpath
231  , restype);
232 
233  if (self->baseclass.callback) {
234  DEBUGMSG2("%s.%d: Calling callback - exittype: EXITED_ZERO", __FUNCTION__,__LINE__);
235  self->baseclass.callback(self->baseclass.request
236  , self->baseclass.user_data
237  , EXITED_ZERO // exittype
238  , 0 // rc
239  , 0 // signal
240  , FALSE // core_dumped
241  , metadata); // string returned
242  }
243  g_free(metadata); metadata = NULL;
244 }
245 
247 FSTATIC void
249 {
250  if (self->baseclass.callback) {
251  DEBUGMSG2("%s.%d: Calling callback - exittype: EXITED_ZERO", __FUNCTION__,__LINE__);
252  self->baseclass.callback(self->baseclass.request
253  , self->baseclass.user_data
254  , EXITED_ZERO // exittype
255  , 0 // rc
256  , 0 // signal
257  , FALSE // core_dumped
258  , NULL); // string returned
259  }
260 }
261 
262 //http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
263 static int status_rc_map[] = {
264  0, // 0
265  7, // 1 program is dead and /var/run exists => program is not running
266  7, // 2 program is dead and /var/lock exists => program is not running
267  7, // 3 program not running => program is not running
268  1, // 4 status is unknown => generic or unspecified error
269 };
270 
273 FSTATIC void
275 , enum HowDied exittype
276 , int rc
277 , int signal
278 , gboolean core_dumped)
279 {
280  ResourceLSB* self = CASTTOCLASS(ResourceLSB, child->user_data);
281  char * outread = NULL;
282 
283  self->baseclass.endtime = g_get_monotonic_time();
284  if (self->child->stdout_src->textread
285  && self->child->stdout_src->textread->str) {
286  outread = self->child->stdout_src->textread->str;
287  }else{
288  outread = NULL;
289  }
290 
291  DEBUGMSG2("%s.%d: Exit happened exittype:%d, rc:%d", __FUNCTION__, __LINE__, exittype, rc);
292  // status exit codes are weird...
293  if (exittype == EXITED_NONZERO && rc < (int)DIMOF(status_rc_map)
294  && strcmp(self->baseclass.operation, MONITOROP) == 0) {
295  rc = status_rc_map[rc];
296  DEBUGMSG2("%s.%d: Exit happened exittype:%d, MAPPED rc:%d "
297  , __FUNCTION__, __LINE__, exittype, rc);
298  }
299  if (exittype != EXITED_ZERO && strcmp(self->baseclass.operation, MONITOROP) == 0
300  && outread) {
301  g_warning("%s: %s", self->baseclass.loggingname, outread);
302  }
303 
304  if (self->baseclass.callback) {
305  DEBUGMSG2("%s.%d: Calling callback - exittype:%d", __FUNCTION__,__LINE__,exittype);
306  self->baseclass.callback(self->baseclass.request
307  , self->baseclass.user_data
308  , exittype
309  , rc
310  , signal
311  , core_dumped
312  , outread);
313  }
314 
315  self->baseclass.is_running = FALSE;
316  DEBUGMSG5("%s.%d: UNREF resourcelsb: %p", __FUNCTION__,__LINE__,self);
317  UNREF2(self); // Undo the ref we did before executing
318 }
void(* ResourceCmdCallback)(ConfigContext *request, gpointer user_data, enum HowDied reason, int rc, int signal, gboolean core_dumped, const char *stringresult)
Definition: resourcecmd.h:44
Log all exits - normal or abnormal.
Definition: childprocess.h:49
#define REF2(obj)
Definition: assimobj.h:40
#define CONFIGNAME_TYPE
Type of resource or discovery.
WINEXPORT ChildProcess * childprocess_new(gsize cpsize, char **argv, const char **envp, ConfigContext *envmod, const char *curdir, void(*notify)(ChildProcess *, enum HowDied, int rc, int signal, gboolean core_dumped), gboolean save_stdout, const char *logdomain, const char *logprefix, GLogLevelFlags loglevel, guint32 timeout_seconds, gpointer user_data, enum ChildErrLogMode logmode, const char *logname)
ChildProcess class. constructor.
Definition: childprocess.c:85
#define DEBUGMSG(...)
Definition: proj_classes.h:87
FSTATIC void _resourcelsb_finalize(AssimObj *aself)
Finalize function for ResourceLSB objects.
Definition: resourcelsb.c:111
#define DEBUGMSG5(...)
Definition: proj_classes.h:93
FSTATIC void _resourcelsb_metadata(ResourceLSB *self)
Return overly-simplified faked-up metadata for an LSB resource.
Definition: resourcelsb.c:207
const char *(* getstring)(const ConfigContext *, const char *name)
Get String value.
Definition: configcontext.h:86
#define LSB_ROOT
Definition: resourcelsb.h:52
void(* execute)(ResourceCmd *self)
Execute this resource command.
Definition: resourcecmd.h:58
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
gpointer user_data
User data given to us when the object was created.
Definition: childprocess.h:69
int signal
Definition: childprocess.c:238
ResourceCmd * resourcecmd_constructor(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor (_new function) for ResourceCmd "abstract" class.
Definition: resourcecmd.c:113
#define BINDDEBUG(Cclass)
BINDDEBUG is for telling the class system where the debug variable for this class is - put it in the ...
Definition: proj_classes.h:82
struct _ResourceLSB ResourceLSB
Definition: resourcelsb.h:43
#define __FUNCTION__
WINEXPORT gint64 g_get_monotonic_time(void)
Local replacement for g_get_monotonic_time() - for old releases of glib.
FSTATIC void _resourcelsb_execute(ResourceCmd *self)
Do the deed, dude!
Definition: resourcelsb.c:143
#define METADATAOP
Definition: resourcecmd.h:84
FSTATIC void _resourcelsb_validate_all(ResourceLSB *self)
Fake validate-all action - just return success...
Definition: resourcelsb.c:248
ResourceCmd * resourcelsb_new(guint structsize, ConfigContext *request, gpointer user_data, ResourceCmdCallback callback)
Constructor for ResourceLSB class.
Definition: resourcelsb.c:49
Project common header file.
#define DIMOF(a)
Definition: lldp_min.c:30
Don&#39;t log anything when it quits.
Definition: childprocess.h:46
AssimObj baseclass
Base object: implements ref, unref, toString.
Definition: resourcecmd.h:51
#define MONITOROP
Definition: resourcecmd.h:83
FSTATIC void _resourcelsb_child_notify(ChildProcess *, enum HowDied, int, int, gboolean)
We get called when our child exits, times out and is killed, or times out and can&#39;t be killed...
Definition: resourcelsb.c:274
HowDied
Definition: childprocess.h:35
Exited with nonzero return code.
Definition: childprocess.h:38
#define STATUSOP
Definition: resourcelsb.h:53
Implements the LSB (Linux Standard Base aka SysV Init script) resource class.
Exited with zero return code.
Definition: childprocess.h:37
ChildErrLogMode
Definition: childprocess.h:45
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
Implements the resource command abstract class.
#define DEBUGMSG2(...)
Definition: proj_classes.h:90
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
#define UNREF2(obj)
Definition: assimobj.h:36
#define CASTTOCLASS(Cclass, obj)
Safely cast &#39;obj&#39; to C-class &#39;class&#39; - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
#define VALIDATEOP
Definition: resourcelsb.h:54
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67