~ampelbein/ubuntu/oneiric/heartbeat/lp-770743

« back to all changes in this revision

Viewing changes to lib/plugins/lrm/raexecocf.c

  • Committer: Bazaar Package Importer
  • Author(s): Ante Karamatic
  • Date: 2010-02-17 21:59:18 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20100217215918-06paxph5do4saw8v
Tags: 3.0.2-0ubuntu1
* New upstream release
* Drop hard dep on pacemaker for heartbet; moved to Recommends
* debian/heartbeat.install:
  - follow upstream changes
* debian/control:
  - added docbook-xsl and xsltproc to build depends

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
 * This program is free software; you can redistribute it and/or
3
 
 * modify it under the terms of the GNU General Public
4
 
 * License as published by the Free Software Foundation; either
5
 
 * version 2.1 of the License, or (at your option) any later version.
6
 
 * 
7
 
 * This software is distributed in the hope that it will be useful,
8
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
 
 * General Public License for more details.
11
 
 * 
12
 
 * You should have received a copy of the GNU General Public
13
 
 * License along with this library; if not, write to the Free Software
14
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15
 
 *
16
 
 * File: raexecocf.c
17
 
 * Author: Sun Jiang Dong <sunjd@cn.ibm.com>
18
 
 * Copyright (c) 2004 International Business Machines
19
 
 *
20
 
 * This code implements the Resource Agent Plugin Module for LSB style.
21
 
 * It's a part of Local Resource Manager. Currently it's used by lrmd only.
22
 
 */
23
 
 
24
 
#include <lha_internal.h>
25
 
#include <stdio.h>              
26
 
#include <string.h>
27
 
#include <unistd.h>
28
 
#include <stdlib.h>
29
 
#include <libgen.h>
30
 
#include <sys/types.h>
31
 
#include <sys/wait.h>
32
 
#include <sys/stat.h>
33
 
#include <errno.h>
34
 
#include <glib.h>
35
 
#include <clplumbing/cl_log.h>
36
 
#include <clplumbing/realtime.h>
37
 
#include <pils/plugin.h>
38
 
#include <dirent.h>
39
 
#include <libgen.h>  /* Add it for compiling on OSX */
40
 
#ifdef HAVE_TIME_H
41
 
#include <time.h>
42
 
#endif
43
 
 
44
 
#include <lrm/raexec.h>
45
 
 
46
 
# define PIL_PLUGINTYPE         RA_EXEC_TYPE
47
 
# define PIL_PLUGINTYPE_S       "RAExec"
48
 
# define PIL_PLUGINLICENSE      LICENSE_PUBDOM
49
 
# define PIL_PLUGINLICENSEURL   URL_PUBDOM
50
 
 
51
 
# define PIL_PLUGIN             ocf
52
 
# define PIL_PLUGIN_S           "ocf"
53
 
/* 
54
 
 * Are there multiple paths? Now according to OCF spec, the answer is 'no'.
55
 
 * But actually or for future?
56
 
 */
57
 
static const char * RA_PATH = OCF_RA_DIR;
58
 
 
59
 
/* The begin of exported function list */
60
 
static int execra(const char * rsc_id,
61
 
                  const char * rsc_type,
62
 
                  const char * provider,
63
 
                  const char * op_type,
64
 
                  const int    timeout,
65
 
                  GHashTable * params);
66
 
static uniform_ret_execra_t map_ra_retvalue(int ret_execra, 
67
 
           const char * op_type, const char * std_output);
68
 
static int get_resource_list(GList ** rsc_info);
69
 
static char* get_resource_meta(const char* rsc_type,  const char* provider);
70
 
static int get_provider_list(const char* ra_type, GList ** providers);
71
 
 
72
 
/* The end of exported function list */
73
 
 
74
 
/* The begin of internal used function & data list */
75
 
#define HADEBUGVAL      "HA_debug"
76
 
 
77
 
static void add_OCF_prefix(GHashTable * params, GHashTable * new_params);
78
 
static void add_OCF_env_vars(GHashTable * env, const char * rsc_id,
79
 
                             const char * rsc_type, const char * provider);
80
 
static void add_prefix_foreach(gpointer key, gpointer value,
81
 
                                   gpointer user_data);
82
 
 
83
 
static void hash_to_str(GHashTable * , GString *);
84
 
static void hash_to_str_foreach(gpointer key, gpointer value,
85
 
                                   gpointer user_data);
86
 
 
87
 
static int raexec_setenv(GHashTable * env_params);
88
 
static void set_env(gpointer key, gpointer value, gpointer user_data);
89
 
                                   
90
 
static gboolean let_remove_eachitem(gpointer key, gpointer value,
91
 
                                    gpointer user_data);
92
 
static int get_providers(const char* class_path, const char* op_type,
93
 
                         GList ** providers);
94
 
static void merge_string_list(GList** old, GList* new);
95
 
static gint compare_str(gconstpointer a, gconstpointer b);
96
 
 
97
 
/* The end of internal function & data list */
98
 
 
99
 
/* Rource agent execution plugin operations */
100
 
static struct RAExecOps raops =
101
 
{       execra,
102
 
        map_ra_retvalue,
103
 
        get_resource_list,
104
 
        get_provider_list,
105
 
        get_resource_meta
106
 
};
107
 
 
108
 
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
109
 
 
110
 
static const PILPluginImports*  PluginImports;
111
 
static PILPlugin*               OurPlugin;
112
 
static PILInterface*            OurInterface;
113
 
static void*                    OurImports;
114
 
static void*                    interfprivate;
115
 
 
116
 
/*
117
 
 * Our plugin initialization and registration function
118
 
 * It gets called when the plugin gets loaded.
119
 
 */
120
 
PIL_rc
121
 
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports);
122
 
 
123
 
PIL_rc
124
 
PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports)
125
 
{
126
 
        /* Force the compiler to do a little type checking */
127
 
        (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
128
 
 
129
 
        PluginImports = imports;
130
 
        OurPlugin = us;
131
 
 
132
 
        /* Register ourself as a plugin */
133
 
        imports->register_plugin(us, &OurPIExports);
134
 
 
135
 
        /*  Register our interfaces */
136
 
        return imports->register_interface(us, PIL_PLUGINTYPE_S,  PIL_PLUGIN_S,
137
 
                &raops, NULL, &OurInterface, &OurImports,
138
 
                interfprivate);
139
 
}
140
 
 
141
 
/*
142
 
 * The function to execute a RA.
143
 
 */
144
 
static int
145
 
execra(const char * rsc_id, const char * rsc_type, const char * provider,
146
 
       const char * op_type, const int timeout, GHashTable * params)
147
 
{
148
 
        uniform_ret_execra_t exit_value;
149
 
        char ra_pathname[RA_MAX_NAME_LENGTH];
150
 
        GHashTable * tmp_for_setenv;
151
 
        GString * params_gstring;
152
 
        char * inherit_debuglevel = NULL;
153
 
 
154
 
        get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname);
155
 
 
156
 
        /* Setup environment correctly */
157
 
        tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal);
158
 
        add_OCF_prefix(params, tmp_for_setenv);
159
 
        add_OCF_env_vars(tmp_for_setenv, rsc_id, rsc_type, provider);
160
 
        raexec_setenv(tmp_for_setenv);
161
 
        g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL);
162
 
        g_hash_table_destroy(tmp_for_setenv);
163
 
 
164
 
        /* let this log show only high loglevel. */
165
 
        inherit_debuglevel = getenv(HADEBUGVAL);
166
 
        if ((inherit_debuglevel != NULL) && (atoi(inherit_debuglevel) > 1)) {
167
 
                params_gstring = g_string_new("");
168
 
                hash_to_str(params, params_gstring);
169
 
                cl_log(LOG_DEBUG, "RA instance %s executing: OCF::%s %s. Parameters: "
170
 
                        "{%s}", rsc_id, rsc_type, op_type, params_gstring->str);
171
 
                g_string_free(params_gstring, TRUE);
172
 
        }
173
 
 
174
 
        closefiles(); /* don't leak open files */
175
 
        /* execute the RA */
176
 
        execl(ra_pathname, ra_pathname, op_type, (const char *)NULL);
177
 
        cl_perror("(%s:%s:%d) execl failed for %s" 
178
 
                  , __FILE__, __FUNCTION__, __LINE__, ra_pathname);
179
 
 
180
 
        switch (errno) { /* see execve(2) */
181
 
                case E2BIG:   /* env to large */
182
 
                case EACCES:   /* permission denied (various errors) */
183
 
                case EFAULT:  /* address space issue */
184
 
                case EINVAL:  /* bad format */
185
 
                case EMFILE:  /* too many files open */
186
 
                case EIO:  /* I/O error */
187
 
                case ELOOP:  /* Too  many  symbolic links */
188
 
                case ENAMETOOLONG:  /* */
189
 
                case ENOMEM:  /* */
190
 
                case EPERM:  /* */
191
 
                        exit_value = EXECRA_EXEC_UNKNOWN_ERROR;
192
 
                        break;
193
 
 
194
 
                default:
195
 
                        exit_value = EXECRA_NOT_INSTALLED;
196
 
                        break;
197
 
        }
198
 
 
199
 
        exit(exit_value);
200
 
}
201
 
 
202
 
static uniform_ret_execra_t
203
 
map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output)
204
 
{
205
 
        /* Because the UNIFORM_RET_EXECRA is compatible with OCF standard,
206
 
         * no actual mapping except validating, which ensure the return code
207
 
         * will be in the range 0 to 7. Too strict?
208
 
         */
209
 
        if (ret_execra < 0 || ret_execra > 9) {
210
 
                cl_log(LOG_WARNING, "mapped the invalid return code %d."
211
 
                        , ret_execra);
212
 
                ret_execra = EXECRA_UNKNOWN_ERROR;
213
 
        }
214
 
        return ret_execra;
215
 
}
216
 
 
217
 
static gint
218
 
compare_str(gconstpointer a, gconstpointer b)
219
 
{
220
 
        return strncmp(a,b,RA_MAX_NAME_LENGTH);
221
 
}
222
 
 
223
 
static int
224
 
get_resource_list(GList ** rsc_info)
225
 
{
226
 
        struct dirent **namelist;
227
 
        GList* item;
228
 
        int file_num;
229
 
        char subdir[FILENAME_MAX+1];
230
 
 
231
 
        if ( rsc_info == NULL ) {
232
 
                cl_log(LOG_ERR, "Parameter error: get_resource_list");
233
 
                return -2;
234
 
        }
235
 
 
236
 
        if ( *rsc_info != NULL ) {
237
 
                cl_log(LOG_ERR, "Parameter error: get_resource_list."\
238
 
                        "will cause memory leak.");
239
 
                *rsc_info = NULL;
240
 
        }
241
 
        file_num = scandir(RA_PATH, &namelist, NULL, alphasort);
242
 
        if (file_num < 0) {
243
 
                return -2;
244
 
        }
245
 
        while (file_num--) {
246
 
                GList* ra_subdir = NULL;
247
 
                struct stat prop;
248
 
                if ('.' == namelist[file_num]->d_name[0]) {
249
 
                        free(namelist[file_num]);
250
 
                        continue;
251
 
                }
252
 
                
253
 
                stat(namelist[file_num]->d_name, &prop);
254
 
                if (S_ISDIR(prop.st_mode)) {
255
 
                        free(namelist[file_num]);
256
 
                        continue;
257
 
                }
258
 
 
259
 
                snprintf(subdir,FILENAME_MAX,"%s/%s",
260
 
                         RA_PATH, namelist[file_num]->d_name);
261
 
                         
262
 
                get_runnable_list(subdir,&ra_subdir);
263
 
 
264
 
                merge_string_list(rsc_info,ra_subdir);
265
 
 
266
 
                while (NULL != (item = g_list_first(ra_subdir))) {
267
 
                        ra_subdir = g_list_remove_link(ra_subdir, item);
268
 
                        g_free(item->data);
269
 
                        g_list_free_1(item);
270
 
                }
271
 
 
272
 
                free(namelist[file_num]);
273
 
        }
274
 
        free(namelist);
275
 
                        
276
 
        return 0;
277
 
}
278
 
 
279
 
static void
280
 
merge_string_list(GList** old, GList* new)
281
 
{
282
 
        GList* item = NULL;
283
 
        char* newitem;
284
 
        for( item=g_list_first(new); NULL!=item; item=g_list_next(item)){
285
 
                if (!g_list_find_custom(*old, item->data,compare_str)){
286
 
                        newitem = g_strndup(item->data,RA_MAX_NAME_LENGTH);
287
 
                        *old = g_list_append(*old, newitem);
288
 
                }
289
 
        }
290
 
}
291
 
 
292
 
static int
293
 
get_provider_list(const char* ra_type, GList ** providers)
294
 
{
295
 
        int ret;
296
 
        ret = get_providers(RA_PATH, ra_type, providers);
297
 
        if (0>ret) {
298
 
                cl_log(LOG_ERR, "scandir failed in OCF RA plugin");
299
 
        }
300
 
        return ret;
301
 
}
302
 
 
303
 
static char*
304
 
get_resource_meta(const char* rsc_type, const char* provider)
305
 
{
306
 
        const int BUFF_LEN=4096;
307
 
        int read_len = 0;
308
 
        char buff[BUFF_LEN];
309
 
        char* data = NULL;
310
 
        GString* g_str_tmp = NULL;
311
 
        char ra_pathname[RA_MAX_NAME_LENGTH];
312
 
        FILE* file = NULL;
313
 
        GHashTable * tmp_for_setenv;
314
 
        struct timespec short_sleep = {0,200000000L}; /*20ms*/
315
 
 
316
 
        get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname);
317
 
 
318
 
        strncat(ra_pathname, " meta-data",RA_MAX_NAME_LENGTH-strlen(ra_pathname)-1);
319
 
        tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal);
320
 
        add_OCF_env_vars(tmp_for_setenv, "DUMMY_INSTANCE", rsc_type, provider);
321
 
        raexec_setenv(tmp_for_setenv);
322
 
        g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL);
323
 
        g_hash_table_destroy(tmp_for_setenv);
324
 
 
325
 
        file = popen(ra_pathname, "r");
326
 
        if (NULL==file) {
327
 
                cl_log(LOG_ERR, "%s: popen failed: %s", __FUNCTION__, strerror(errno));
328
 
                return NULL;
329
 
        }
330
 
 
331
 
        g_str_tmp = g_string_new("");
332
 
        while(!feof(file)) {
333
 
                read_len = fread(buff, 1, BUFF_LEN - 1, file);
334
 
                if (0<read_len) {
335
 
                        *(buff+read_len) = '\0';
336
 
                        g_string_append(g_str_tmp, buff);
337
 
                }
338
 
                else {
339
 
                        nanosleep(&short_sleep,NULL);
340
 
                }
341
 
        }
342
 
        if( pclose(file) ) {
343
 
                cl_log(LOG_ERR, "%s: pclose failed: %s", __FUNCTION__, strerror(errno));
344
 
        }
345
 
        if (0 == g_str_tmp->len) {
346
 
                g_string_free(g_str_tmp, TRUE);
347
 
                return NULL;
348
 
        }
349
 
        data = (char*)g_new(char, g_str_tmp->len+1);
350
 
        data[0] = data[g_str_tmp->len] = 0;
351
 
        strncpy(data, g_str_tmp->str, g_str_tmp->len);
352
 
 
353
 
        g_string_free(g_str_tmp, TRUE);
354
 
        
355
 
        return data;
356
 
}
357
 
 
358
 
static void 
359
 
add_OCF_prefix(GHashTable * env_params, GHashTable * new_env_params)
360
 
{
361
 
        if (env_params) {
362
 
                g_hash_table_foreach(env_params, add_prefix_foreach,
363
 
                                     new_env_params);
364
 
        }
365
 
}
366
 
 
367
 
static void
368
 
add_prefix_foreach(gpointer key, gpointer value, gpointer user_data)
369
 
{
370
 
        const int MAX_LENGTH_OF_ENV = 50;
371
 
        int prefix = STRLEN_CONST("OCF_RESKEY_");
372
 
        GHashTable * new_hashtable = (GHashTable *) user_data;
373
 
        char * newkey;
374
 
        int keylen = strnlen((char*)key, MAX_LENGTH_OF_ENV-prefix)+prefix+1;
375
 
        
376
 
        newkey = g_new(gchar, keylen);
377
 
        strncpy(newkey, "OCF_RESKEY_", keylen);
378
 
        strncat(newkey, key, keylen-strlen(newkey)-1);
379
 
        g_hash_table_insert(new_hashtable, (gpointer)newkey, g_strdup(value));
380
 
}
381
 
 
382
 
static void 
383
 
hash_to_str(GHashTable * params , GString * str)
384
 
{
385
 
        if (params) {
386
 
                g_hash_table_foreach(params, hash_to_str_foreach, str);
387
 
        }
388
 
}
389
 
 
390
 
static void
391
 
hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data)
392
 
{
393
 
        char buffer_tmp[60];
394
 
        GString * str = (GString *)user_data;
395
 
 
396
 
        snprintf(buffer_tmp, 60, "%s=%s ", (char *)key, (char *)value);
397
 
        str = g_string_append(str, buffer_tmp);
398
 
}
399
 
 
400
 
static gboolean
401
 
let_remove_eachitem(gpointer key, gpointer value, gpointer user_data)
402
 
{
403
 
        g_free(key);
404
 
        g_free(value);
405
 
        return TRUE;
406
 
}
407
 
 
408
 
static int
409
 
raexec_setenv(GHashTable * env_params)
410
 
{
411
 
        if (env_params) {
412
 
                g_hash_table_foreach(env_params, set_env, NULL);
413
 
        }
414
 
        return 0;
415
 
}
416
 
 
417
 
static void
418
 
set_env(gpointer key, gpointer value, gpointer user_data)
419
 
{
420
 
       if (setenv(key, value, 1) != 0) {
421
 
                cl_log(LOG_ERR, "setenv failed in raexecocf.");
422
 
        }
423
 
}
424
 
 
425
 
static int
426
 
get_providers(const char* class_path, const char* ra_type, GList ** providers)
427
 
{
428
 
        struct dirent **namelist;
429
 
        int file_num;
430
 
 
431
 
        if ( providers == NULL ) {
432
 
                cl_log(LOG_ERR, "Parameter error: get_providers");
433
 
                return -2;
434
 
        }
435
 
 
436
 
        if ( *providers != NULL ) {
437
 
                cl_log(LOG_ERR, "Parameter error: get_providers."\
438
 
                        "will cause memory leak.");
439
 
                *providers = NULL;
440
 
        }
441
 
 
442
 
        file_num = scandir(class_path, &namelist, 0, alphasort);
443
 
        if (file_num < 0) {
444
 
                return -2;
445
 
        }else{
446
 
                char tmp_buffer[FILENAME_MAX+1];
447
 
                struct stat prop;
448
 
 
449
 
                while (file_num--) {
450
 
                        if ('.' == namelist[file_num]->d_name[0]) {
451
 
                                free(namelist[file_num]);
452
 
                                continue;
453
 
                        }
454
 
                        snprintf(tmp_buffer,FILENAME_MAX,"%s/%s",
455
 
                                 class_path, namelist[file_num]->d_name);
456
 
                        stat(tmp_buffer, &prop);
457
 
                        if (!S_ISDIR(prop.st_mode)) {
458
 
                                free(namelist[file_num]);
459
 
                                continue;
460
 
                        }
461
 
 
462
 
                        snprintf(tmp_buffer,FILENAME_MAX,"%s/%s/%s",
463
 
                                 class_path, namelist[file_num]->d_name, ra_type);
464
 
 
465
 
                        if ( filtered(tmp_buffer) == TRUE ) {
466
 
                                *providers = g_list_append(*providers,
467
 
                                        g_strdup(namelist[file_num]->d_name));
468
 
                        }
469
 
                        free(namelist[file_num]);
470
 
                }
471
 
                free(namelist);
472
 
        }
473
 
        return g_list_length(*providers);
474
 
}
475
 
 
476
 
static void
477
 
add_OCF_env_vars(GHashTable * env, const char * rsc_id,
478
 
                 const char * rsc_type, const char * provider)
479
 
{
480
 
        if ( env == NULL ) {
481
 
                cl_log(LOG_WARNING, "env should not be a NULL pointer.");
482
 
                return;
483
 
        }
484
 
        
485
 
        g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MAJOR"), 
486
 
                            g_strdup("1"));
487
 
        g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MINOR"), 
488
 
                            g_strdup("0"));
489
 
        g_hash_table_insert(env, g_strdup("OCF_ROOT"), 
490
 
                            g_strdup(OCF_ROOT_DIR));
491
 
 
492
 
        if ( rsc_id != NULL ) {
493
 
                g_hash_table_insert(env, g_strdup("OCF_RESOURCE_INSTANCE"),
494
 
                                    g_strdup(rsc_id));
495
 
        }
496
 
 
497
 
        /* Currently the rsc_type=="the filename of the RA script/executable",
498
 
         * It seems always correct even in the furture. ;-)
499
 
         */
500
 
        if ( rsc_type != NULL ) {
501
 
                g_hash_table_insert(env, g_strdup("OCF_RESOURCE_TYPE"), 
502
 
                                    g_strdup(rsc_type));
503
 
        }
504
 
 
505
 
        /* Notes: this is not added to specification yet. Sept 10,2004 */
506
 
        if ( provider != NULL ) {
507
 
                g_hash_table_insert(env, g_strdup("OCF_RESOURCE_PROVIDER"),
508
 
                                    g_strdup(provider));
509
 
        }
510
 
}
511