Changeset 5807
- Timestamp:
- 03/13/10 14:58:03 (3 years ago)
- Location:
- luci2/upsd
- Files:
-
- 2 added
- 1 removed
- 13 modified
-
action.c (modified) (8 diffs)
-
cbi2/datatypes.h (modified) (1 diff)
-
cbi2/hmap.c (modified) (6 diffs)
-
cbi2/hmap.h (modified) (3 diffs)
-
cbi2/hmap_config.h (modified) (1 diff)
-
core.h (modified) (5 diffs)
-
hook.c (added)
-
hook.h (added)
-
libupsd.c (modified) (5 diffs)
-
service.c (modified) (8 diffs)
-
service.h (modified) (1 diff)
-
ups-cli/ups.c (modified) (3 diffs)
-
upsd.h (modified) (11 diffs)
-
upsd_config.h (modified) (1 diff)
-
worker.c (modified) (2 diffs)
-
worker.h (deleted)
Legend:
- Unmodified
- Added
- Removed
-
luci2/upsd/action.c
r5714 r5807 25 25 #include "service.h" 26 26 #include "action.h" 27 #include "hook.h" 27 28 28 29 /* Create a list wrapper */ 29 static upsd_initlist_t* _libupsd_action_enlist30 UPSD_MALLOC static upsd_initlist_t* _libupsd_action_enlist 30 31 (upsd_init_t *init, upsd_initlist_t *next) { 31 32 upsd_initlist_t *list = malloc(sizeof(upsd_initlist_t)); … … 141 142 upsd_report_t *report; 142 143 int status; 143 int legacy = 1 ;144 int legacy = 1, interactive = 1; 144 145 int done = 0; 145 146 int waiting = 0; … … 156 157 continue; /* Don't process legacy elements in parallel */ 157 158 } 159 if (!interactive && (init->flags & UPSD_INIT_INTERACTIVE)) { 160 prev = &list->next; 161 continue; /* Don't process interacitve elements in parallel */ 162 } 158 163 if (inst->flags & UPSD_FLAG_SIMULATE) { 159 164 UPSD_LOG_WARN("Simulating action %u on '%s'", (unsigned)action, 160 165 init->provides[0]); 161 166 } 167 if (init->hndl.status != UPSD_EAGAIN) { 168 _libupsd_hook_call(state, init, action, UPSD_HOOK_BEFORE); 169 } 162 170 163 171 status = ((inst->flags & UPSD_FLAG_SIMULATE) || (!init->worker)) ? … … 165 173 166 174 if (status == UPSD_EAGAIN) { 167 if (!init->hndl.timeout) { 168 init->hndl.timeout = inst->time + UPSD_INIT_TIMEOUT; 169 } else if (inst->time > init->hndl.timeout) { 170 status = UPSD_ETIMEDOUT; 175 if (!(init->flags & UPSD_INIT_INTERACTIVE)) { 176 if (!init->hndl.timeout) { 177 init->hndl.timeout = inst->time + UPSD_INIT_TIMEOUT; 178 } else if (inst->time > init->hndl.timeout) { 179 status = UPSD_ETIMEDOUT; 180 } 171 181 } 172 182 if (init->flags & UPSD_INIT_LEGACY) { 173 183 legacy = 0; /* Stop processing legacy elements for this turn */ 174 184 } 175 } 176 185 if (init->flags & UPSD_INIT_INTERACTIVE) { 186 interactive = 0;/* Stop processing interactives for this turn */ 187 } 188 } 189 190 init->hndl.status = status; 177 191 if (status != UPSD_EAGAIN) { 178 init->hndl.status = status;179 192 if (init->worker) { 180 193 init->worker(init, UPSD_ACTION_INTERNAL_CLEAN); … … 198 211 (!status || (inst->flags & UPSD_FLAG_SKIPFAILED))); 199 212 } 213 _libupsd_hook_call(state, init, action, UPSD_HOOK_AFTER); 200 214 201 215 inst->lasterror = (status) ? status : inst->lasterror; … … 339 353 340 354 if (flags & UPSD_FLAG_REPORT) { 341 if (!(state->report = calloc(count + 1,sizeof(upsd_report_t)))) {355 if (!(state->report = malloc((count + 1) * sizeof(upsd_report_t)))) { 342 356 return UPSD_ENOMEM; 343 357 } … … 383 397 384 398 if (flags & UPSD_FLAG_REPORT) { 385 if (!(state->report = calloc(count + 1,sizeof(upsd_report_t)))) {399 if (!(state->report = malloc((count + 1) * sizeof(upsd_report_t)))) { 386 400 return UPSD_ENOMEM; 387 401 } … … 419 433 420 434 if (flags & UPSD_FLAG_REPORT) { 421 if (!(state->report = calloc(count + 1,sizeof(upsd_report_t)))) {435 if (!(state->report = malloc((count + 1) * sizeof(upsd_report_t)))) { 422 436 return UPSD_ENOMEM; 423 437 } -
luci2/upsd/cbi2/datatypes.h
r5714 r5807 8 8 #if __GNUC__ >= 4 9 9 #define CBI2_LOCAL __attribute__ ((visibility("hidden"))) 10 #define CBI2_MALLOC __attribute__ ((malloc)) 10 11 #else 11 12 #define CBI2_LOCAL 13 #define CBI2_MALLOC 12 14 #endif 13 15 -
luci2/upsd/cbi2/hmap.c
r5714 r5807 36 36 37 37 38 CBI2_ LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint) {38 CBI2_MALLOC CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint) { 39 39 cbi2_hmap_t* map = calloc(1, sizeof(cbi2_hmap_t)); 40 40 if (!map) { … … 125 125 } 126 126 127 #ifdef CBI2_HMAP_UNSET 127 128 CBI2_LOCAL int cbi2_hmap_unset 128 129 (cbi2_hmap_t *map, const void *key, uint16_t len) { … … 162 163 return CBI2_OK; 163 164 } 165 #endif 164 166 165 167 CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_next … … 194 196 } 195 197 198 #ifdef CBI2_HMAP_REFCOUNT 196 199 CBI2_LOCAL void cbi2_hmap_reference(cbi2_hmap_t *map) { 197 200 map->refcount++; … … 205 208 } 206 209 } 210 #endif 207 211 208 212 … … 307 311 break; 308 312 case CBI2_TYPE_HASHMAP: 313 #ifdef CBI2_HMAP_REFCOUNT 309 314 cbi2_hmap_unreference(bucket->data.buffer.pointer); 310 break; 315 #else 316 cbi2_hmap_destroy(bucket->data.buffer.pointer); 311 317 #endif 312 } 313 } 318 break; 319 #endif 320 } 321 } -
luci2/upsd/cbi2/hmap.h
r5714 r5807 38 38 39 39 40 CBI2_ LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint);40 CBI2_MALLOC CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint); 41 41 CBI2_LOCAL int cbi2_hmap_resize(cbi2_hmap_t *map, cbi2_size_t payload); 42 42 CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_rawget(cbi2_hmap_t *map, … … 44 44 CBI2_LOCAL int cbi2_hmap_get (cbi2_hmap_t *map, const void *key, uint16_t len, 45 45 cbi2_hmap_data_t **value); 46 47 #ifdef CBI2_HMAP_UNSET 46 48 CBI2_LOCAL int cbi2_hmap_unset(cbi2_hmap_t *map, const void *key, uint16_t len); 49 #endif 50 47 51 CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_next 48 52 (cbi2_hmap_t *map, cbi2_hmap_iter_t *iter); … … 51 55 CBI2_LOCAL void cbi2_hmap_clear(cbi2_hmap_t *map); 52 56 CBI2_LOCAL void cbi2_hmap_destroy(cbi2_hmap_t *map); 57 58 #ifdef CBI2_HMAP_REFCOUNT 53 59 CBI2_LOCAL void cbi2_hmap_reference(cbi2_hmap_t *map); 54 60 CBI2_LOCAL void cbi2_hmap_unreference(cbi2_hmap_t *map); 61 #endif 55 62 56 63 #endif /* CBI2_HMAP_H_ */ -
luci2/upsd/cbi2/hmap_config.h
r5714 r5807 26 26 #define CBI2_HMAP_CAPACITY_MIN 16 27 27 28 /* 29 * Enable unset function 30 */ 31 /* #define CBI2_HMAP_UNSET */ 32 33 /* 34 * Enable refcounting 35 */ 36 /* #define CBI2_HMAP_REFCOUNT */ 37 38 /* 39 * Enable managed buffer datatype 40 */ 41 /* #define CBI2_HMAP_MANAGED */ 42 28 43 29 44 typedef cbi2_blob_t cbi2_hmap_blob_t; -
luci2/upsd/core.h
r5795 r5807 25 25 typedef struct upsd_initlist upsd_initlist_t; 26 26 typedef struct upsd_handler upsd_handler_t; 27 typedef struct upsd_extension upsd_extension_t; 27 28 typedef union upsd_handle upsd_handle_t; 28 29 … … 51 52 char **options; 52 53 char **provides; 53 upsd_worker_t worker;54 upsd_worker_t *worker; 54 55 upsd_handler_t hndl; 55 56 }; … … 88 89 }; 89 90 91 struct upsd_extension { 92 upsd_extension_t *next; 93 uint16_t flags; 94 upsd_action_t action; 95 upsd_hook_t *hook; 96 void *context; 97 }; 98 90 99 91 100 #include "cbi2/hmap.h" … … 93 102 struct upsd_state { 94 103 cbi2_hmap_t *events; 104 upsd_extension_t *extensions; 95 105 upsd_report_t *report; 96 106 size_t reportidx; … … 98 108 }; 99 109 100 101 110 #define UPSD_INIT_LEGACY 0x01 102 111 #define UPSD_INIT_INTERNAL 0x02 112 #define UPSD_INIT_INTERACTIVE 0x04 113 103 114 104 115 #if UPSD_LOGGING >= 4 -
luci2/upsd/libupsd.c
r5795 r5807 26 26 #include "service.h" 27 27 #include "action.h" 28 #include "hook.h" 28 29 29 30 upsd_state_t* libupsd_create() { … … 46 47 } 47 48 49 int libupsd_hook_register(upsd_state_t *state, upsd_hook_t *hook, 50 void *context, upsd_action_t action, uint16_t flags) { 51 return _libupsd_hook_register(state, hook, context, action, flags); 52 } 53 48 54 int libupsd_dependency_add(upsd_state_t *state, const char *issuer, 49 55 const char *receiver, upsd_action_t action, uint16_t flags) { … … 51 57 } 52 58 53 int libupsd_options_add(upsd_state_t *state, const char *service,54 const char **options) {55 return _libupsd_service_option_add(state, service, options);56 }57 58 59 int libupsd_service_register(upsd_state_t *state, 59 const char ** facilities, upsd_worker_t worker, void *identifier) {60 return _libupsd_service_register(state, facilities,60 const char **services, upsd_worker_t worker, void *identifier) { 61 return _libupsd_service_register(state, services, 61 62 worker, identifier, 0, NULL); 62 63 } … … 102 103 } 103 104 104 int libupsd_runlevel_ control105 (upsd_state_t *state, char runlevel, upsd_action_t action, uint16_t flags) { 106 int ret = _libupsd_action_by_runlevel(state, runlevel, action, flags);107 if (!ret ) {108 ret = _libupsd_action_perform(state, action);105 int libupsd_runlevel_enter(upsd_state_t *state, char runlevel, uint16_t flags) { 106 int ret1 = _libupsd_action_by_runlevel 107 (state, runlevel, UPSD_ACTION_STOP, flags); 108 if (!ret1) { 109 ret1 = _libupsd_action_perform(state, UPSD_ACTION_STOP); 109 110 } 110 return ret; 111 int ret2 = _libupsd_action_by_runlevel 112 (state, runlevel, UPSD_ACTION_START, flags); 113 if (!ret2) { 114 ret2 = _libupsd_action_perform(state, UPSD_ACTION_START); 115 } 116 return (ret1 && !ret2) ? ret1 : ret2; 111 117 } 112 118 … … 121 127 _libupsd_action_cleanup(state); 122 128 _libupsd_service_clear(state); 123 cbi2_hmap_unreference(state->events); 129 _libupsd_hook_clear(state); 130 cbi2_hmap_destroy(state->events); 124 131 free(state); 125 132 } -
luci2/upsd/service.c
r5795 r5807 31 31 32 32 #include "service.h" 33 #include "worker.h"34 33 35 34 /* Get the init object designated for the specified service entry, if any */ … … 88 87 89 88 if (!(emitter_e->emitting++ % UPSD_SYS_EVENT_STEP)) { 90 emitter_e->emitters= realloc(emitter_e->emitters, sizeof89 upsd_listener_t **tmp = realloc(emitter_e->emitters, sizeof 91 90 (upsd_listener_t*) * (emitter_e->emitting + UPSD_SYS_EVENT_STEP - 1)); 92 if (! emitter_e->emitters) {91 if (!tmp) { 93 92 return UPSD_ENOMEM; 94 93 } 94 emitter_e->emitters = tmp; 95 95 } 96 96 emitter_e->emitters[emitter_e->emitting - 1] = listener; … … 102 102 103 103 if (!(receiver_e->receiving++ % UPSD_SYS_EVENT_STEP)) { 104 receiver_e->receivers= realloc(receiver_e->receivers, sizeof104 upsd_listener_t **tmp = realloc(receiver_e->receivers, sizeof 105 105 (upsd_listener_t*) * (receiver_e->receiving + UPSD_SYS_EVENT_STEP - 1)); 106 if (! receiver_e->receivers) {106 if (!tmp) { 107 107 return UPSD_ENOMEM; 108 108 } 109 receiver_e->receivers = tmp; 109 110 } 110 111 receiver_e->receivers[receiver_e->receiving - 1] = listener; … … 177 178 for (char **c = init->options; *c; c++, i++); 178 179 for (const char **c = options; *c; c++, j++); 179 init->options= realloc(init->options, (i + j + 1) * sizeof(char*));180 if (! init->options) {180 char **tmp = realloc(init->options, (i + j + 1) * sizeof(char*)); 181 if (!tmp) { 181 182 return UPSD_ENOMEM; 182 183 } 184 init->options = tmp; 183 185 for (const char **c = options; *c; c++, j++) { 184 186 init->options[i++] = strdup(*c); … … 221 223 } 222 224 init->identifier = rpath; 223 init->worker = _libupsd_worker_exec;225 init->worker = libupsd_worker_exec; 224 226 if (_libupsd_service_designate(state, name, init)) { 225 227 UPSD_LOG_INFO("Designated name %s is occupied.", name); … … 329 331 } 330 332 } 333 } else if (!memcmp(buffer, UPSD_LITERAL_PTRSIZE("# X-Interactive:"))) { 334 init->flags |= UPSD_INIT_INTERACTIVE; 331 335 } else if (!memcmp(buffer, UPSD_LITERAL_PTRSIZE("# X-"))) { 336 if (!memcmp(buffer, UPSD_LITERAL_PTRSIZE("# X-Daemon-Command:"))) { 337 init->worker = libupsd_worker_daemon; 338 } 339 char *c = buffer + strlen(buffer) - 1; 340 while (isspace(*c)) { 341 *c-- = 0; 342 } 332 343 if (++options == opts) { 333 344 opts += 4; 334 if (!( init->options = realloc(init->options,345 if (!(entries = realloc(init->options, 335 346 (opts + 1) * sizeof(char*)))) { 336 347 break; 337 348 } 349 init->options = entries; 338 350 } 339 351 init->options[options] = strdup(buffer + 2); … … 350 362 /* Create a dummy services that is treated as provided */ 351 363 UPSD_LOCAL int _libupsd_service_register 352 (upsd_state_t *state, const char **services, upsd_worker_t worker,364 (upsd_state_t *state, const char **services, upsd_worker_t *worker, 353 365 void *identifier, uint16_t flags, upsd_init_t **handle) { 354 366 upsd_init_t *init = calloc(1, sizeof(upsd_init_t)); … … 456 468 size_t baselen = strlen(entry->d_name); 457 469 ((char*)memcpy(cpath + cpathlen, entry->d_name, baselen))[baselen] = 0; 458 if (!memcmp(".lua", cpath - 4 + cpathlen + baselen, 4)) { 459 UPSD_LOG_ERROR("Lua support not implemented!"); 460 /** SCAN LUA */ 461 _libupsd_service_parse(state, cpath, NULL); 462 } else if (!access(cpath, X_OK)) { 470 if (!access(cpath, X_OK)) { 463 471 _libupsd_service_parse(state, cpath, NULL); 464 472 } -
luci2/upsd/service.h
r5795 r5807 11 11 UPSD_LOCAL int _libupsd_service_init(upsd_state_t *state); 12 12 UPSD_LOCAL int _libupsd_service_register 13 (upsd_state_t *state, const char **services, upsd_worker_t worker,13 (upsd_state_t *state, const char **services, upsd_worker_t *worker, 14 14 void *identifier, uint16_t flags, upsd_init_t **handle); 15 15 UPSD_LOCAL upsd_init_t* _libupsd_service_next -
luci2/upsd/ups-cli/ups.c
r5714 r5807 68 68 " status Returns the status of a service\n\n" 69 69 " enter Enter a runlevel\n" 70 " leave Leave a runlevel\n"71 70 "\n\nOptions:\n" 72 71 " -a fac1[,fac2,...] Automatically provide facilities\n" … … 153 152 action = UPSD_ACTION_STATUS; 154 153 } else if (!strcmp(cmd, "enter")) { 155 action = UPSD_ACTION_ENTER; 156 func = UPS_FUNC_RUNLEVEL; 157 } else if (!strcmp(cmd, "leave")) { 158 action = UPSD_ACTION_LEAVE; 154 action = UPSD_ACTION_START; 159 155 func = UPS_FUNC_RUNLEVEL; 160 156 } else { … … 182 178 } else if (func == UPS_FUNC_RUNLEVEL) { 183 179 char runlvl = (argc > optind) ? argv[optind][0] : UPSD_RUNLEVEL_DEFAULT; 184 stat = libupsd_runlevel_ control(state, runlvl, action, flags);180 stat = libupsd_runlevel_enter(state, runlvl, flags); 185 181 } 186 182 -
luci2/upsd/upsd.h
r5795 r5807 22 22 #ifndef UPSD_H_ 23 23 #define UPSD_H_ 24 25 #if __GNUC__ >= 4 26 #define UPSD_MALLOC __attribute__ ((malloc)) 27 #else 28 #define UPSD_MALLOC 29 #endif 24 30 25 31 #include <stdint.h> … … 67 73 #define UPSD_ACTION_STATUS 6 68 74 69 /* Known runlevel actions */70 #define UPSD_ACTION_ENTER UPSD_ACTION_START71 #define UPSD_ACTION_LEAVE UPSD_ACTION_STOP72 73 75 /* Known rc actions */ 74 76 #define UPSD_RC_INSTALL 1 … … 86 88 87 89 /* Worker */ 88 #define UPSD_WORKER_PROVIDE ((upsd_worker_t)NULL) 90 #define UPSD_WORKER_PROVIDE ((upsd_worker_t*)NULL) 91 92 /* Hook flags */ 93 #define UPSD_HOOK_BEFORE 0x01 94 #define UPSD_HOOK_AFTER 0x02 95 89 96 90 97 … … 93 100 typedef struct upsd_state upsd_state_t; 94 101 typedef struct upsd_init upsd_init_t; 95 typedef int(*upsd_worker_t)(upsd_init_t *init, upsd_action_t action); 102 typedef int(upsd_worker_t)(upsd_init_t *init, upsd_action_t action); 103 typedef int(upsd_hook_t) 104 (void *context, upsd_init_t *init, upsd_action_t action, uint16_t flags); 96 105 typedef struct upsd_report { 97 106 upsd_action_t action; … … 100 109 } upsd_report_t; 101 110 111 112 /* Builtin workers */ 113 int libupsd_worker_exec(upsd_init_t *init, upsd_action_t action); 114 int libupsd_worker_daemon(upsd_init_t *init, upsd_action_t action); 115 116 102 117 /** 103 118 * libupsd_create() - Create a new ups.d state. … … 144 159 */ 145 160 int libupsd_scan_initdir(upsd_state_t *state, const char *initdir); 161 162 /** 163 * libupsd_hook_register() - Register an extension hook. 164 * @state: ups.d state 165 * @hook: Hook callback function 166 * @context: Hook context (optional) 167 * @action: Action to hook (optional) 168 * @flags: Hooking flags 169 * 170 * Registers an extension hook callback that will be called whenever an action 171 * on a service will be performed. 172 * 173 * Context is a pointer passed to the hook-function as a first argument. 174 * Action is the specific action to hook or 0 to hook all. 175 * Flags can be UPSD_HOOK_BEFORE, UPSD_HOOK_AFTER or 0 for hooking before or 176 * after the action is performed or both. 177 * 178 * Returns an ups.d status code. 179 */ 180 int libupsd_hook_register(upsd_state_t *state, upsd_hook_t *hook, 181 void *context, upsd_action_t action, uint16_t flags); 146 182 147 183 /** … … 168 204 169 205 /** 170 * libupsd_options_add() - Add user-defined options to a service.171 * @state: ups.d state172 * @service: Target service173 * @options: Options added to the service174 *175 * Adds user-defined options to a given service. Options to be added should176 * begin with an X- marking them as custom. Standardized LSB-Options177 * (like Required-Start) are silently ignored.178 *179 * Options is a NULL-terminated list of strings containing the options.180 * Each option string is in LSB-format: KEYWORD: VALUE1 VALUE2 VALUE3.181 *182 * Returns an ups.d status code.183 */184 int libupsd_options_add(upsd_state_t *state, const char *service,185 const char **options);186 187 /**188 206 * libupsd_service_register() - Register a user-defined service. 189 207 * @state: ups.d state 190 * @ facilities: Facilities provided by the new service208 * @services: Facilities provided by the new service 191 209 * @worker: Associated worker for performing tasks (optional) 192 210 * @identifier: Service-specific identifier, e.g. pathname (optional) … … 208 226 * Returns an ups.d status code. 209 227 */ 210 int libupsd_service_register(upsd_state_t *state, const char ** facilities,228 int libupsd_service_register(upsd_state_t *state, const char **services, 211 229 upsd_worker_t worker, void *identifier); 212 230 … … 261 279 262 280 /** 263 * libupsd_runlevel_ control() - Perform an action ona runlevel.281 * libupsd_runlevel_enter() - Enter a runlevel. 264 282 * @state: ups.d state 265 283 * @runlevel: ASCII-Char describing the runlevel 266 * @action: Runlevel action to perform267 284 * @flags: Flags controlling the action 268 285 * … … 276 293 * values (usually a runlevel of 'X' translates to /etc/rcX.d). 277 294 * 278 * Action can be any runlevel action, for now only UPSD_ACTION_ENTER and279 * UPSD_ACTION_LEAVE are defined which will start / stop associated services.280 295 * 281 296 * NOTE: Legacy init scripts (without LSB-style dependency comments) are also … … 285 300 * failed or UPSD_OK if all actions could be completed successfully. 286 301 */ 287 int libupsd_runlevel_control(upsd_state_t *state, char runlevel, 288 upsd_action_t action, uint16_t flags); 302 int libupsd_runlevel_enter(upsd_state_t *state, char runlevel, uint16_t flags); 289 303 290 304 /** -
luci2/upsd/upsd_config.h
r5795 r5807 15 15 */ 16 16 #ifndef UPSD_SYS_EVENT_STEP 17 #define UPSD_SYS_EVENT_STEP 817 #define UPSD_SYS_EVENT_STEP 7 18 18 #endif 19 19 -
luci2/upsd/worker.c
r5714 r5807 22 22 #include <sys/types.h> 23 23 #include <sys/wait.h> 24 #include <sys/stat.h> 24 25 #include <unistd.h> 25 26 #include <signal.h> 26 #include "worker.h" 27 #include <string.h> 28 #include <stdio.h> 29 #include <fcntl.h> 30 #include <errno.h> 31 #include <ctype.h> 32 #include <pwd.h> 33 #include <grp.h> 34 #include "core.h" 27 35 28 36 static char* const _libupsd_worker_cmds[] = {"start", "stop", "restart", 29 37 "force-reload", "reload", "status"}; 30 38 31 UPSD_LOCAL int _libupsd_worker_exec(upsd_init_t *init, upsd_action_t action) {39 int libupsd_worker_exec(upsd_init_t *init, upsd_action_t action) { 32 40 pid_t pid = init->hndl.handle.pid; 33 41 if (action == UPSD_ACTION_INTERNAL_CLEAN) { … … 66 74 } 67 75 76 int libupsd_worker_daemon(upsd_init_t *init, upsd_action_t action) { 77 const char *pidfile = NULL, *command = NULL, *options = NULL; 78 int background = 0, user = 0, group = 0, reloadsig = 0; 79 char name[256], buffer[1024]; 80 FILE *fp; 81 pid_t pid = init->hndl.handle.pid; 82 83 if (pid) { /* Waiting for launcher process to complete */ 84 if (action == UPSD_ACTION_INTERNAL_CLEAN) { 85 if (pid) { 86 UPSD_LOG_WARN("Service '%s' seems to hang, killing...", 87 init->provides[0]); 88 kill(pid, SIGKILL); 89 } 90 return UPSD_OK; 91 } 92 int status; 93 if ((pid = waitpid(pid, &status, WNOHANG)) == init->hndl.handle.pid) { 94 init->hndl.handle.pid = (pid_t)0; 95 return (WIFEXITED(status)) ? WEXITSTATUS(status) : UPSD_EEXEC; 96 } else { 97 return (!pid) ? UPSD_EAGAIN : UPSD_EEXEC; 98 } 99 } 100 101 for (char **c = init->options; *c; c++) { /* Parsing daemon options */ 102 if (!strncmp(*c, "X-Daemon-Pidfile:", 17)) { 103 pidfile = *c + 17; 104 while (isspace(*pidfile)) { 105 pidfile++; 106 } 107 } else if (!strncmp(*c, "X-Daemon-Command:", 17)) { 108 command = *c + 17; 109 while (isspace(*command)) { 110 command++; 111 } 112 } else if (!strncmp(*c, "X-Daemon-Options:", 17)) { 113 options = *c + 17; 114 while (isspace(*options)) { 115 options++; 116 } 117 } 118 } 119 if (options) { 120 if (strstr(options, "reload=sighup")) { 121 reloadsig = SIGHUP; 122 } 123 background = !!strstr(options, "background"); 124 } 125 if (!command || !pidfile || strlen(command) >= sizeof(buffer)) { 126 UPSD_LOG_ERROR("'%s' has invalid command or pidfile", *init->provides); 127 return UPSD_EIO; 128 } 129 if (!reloadsig) { /* If reload is not defined, use fallback if possible */ 130 if (action == UPSD_ACTION_RELOAD) { 131 return UPSD_COMMAND_UNSUPPORTED; 132 } else if (action == UPSD_ACTION_FORCERELOAD) { 133 action = UPSD_ACTION_RESTART; 134 } 135 } else if (action == UPSD_ACTION_FORCERELOAD) { 136 action = UPSD_ACTION_RELOAD; 137 } 138 139 if ((fp = fopen(pidfile, "r"))) { /* Get PID from pidfile */ 140 buffer[0] = 0; 141 fgets(buffer, sizeof(buffer), fp); 142 fclose(fp); 143 pid = atoi(buffer); 144 } 145 146 if (!pid || kill(pid, 0) == -1) { /* Process not active */ 147 if (action == UPSD_ACTION_STATUS) { 148 return (!fp) ? UPSD_STATUS_STOPPED : UPSD_STATUS_DEAD_RUN; 149 } else if (action == UPSD_ACTION_STOP) { 150 unlink(pidfile); 151 return UPSD_OK; 152 } 153 } else { /* Process still active */ 154 if (action == UPSD_ACTION_STATUS || action == UPSD_ACTION_START) { 155 return UPSD_STATUS_OK; 156 } 157 kill(pid, (action == UPSD_ACTION_RELOAD) ? reloadsig : SIGTERM); 158 if (action != UPSD_ACTION_RELOAD) { 159 unlink(pidfile); 160 } 161 if (action == UPSD_ACTION_RELOAD || action == UPSD_ACTION_STOP) { 162 return UPSD_OK; 163 } 164 } 165 166 pid = fork(); 167 if (pid == -1) { 168 return UPSD_COMMAND_EXECFAILED; 169 } else if (pid > 0) { 170 if (!background) { 171 init->hndl.handle.pid = pid; 172 return UPSD_EAGAIN; 173 } else { 174 if (!(fp = fopen(pidfile, "w"))) { 175 UPSD_LOG_WARN("Unable to write pidfile '%s'", pidfile); 176 } else { 177 fprintf(fp, "%i\n", (int)pid); 178 fclose(fp); 179 } 180 return UPSD_OK; 181 } 182 } 183 184 /* Execute service */ 185 186 if (options) { 187 struct passwd pwd, *pwdp; 188 struct group grp, *grpp; 189 const char *lname; 190 int i; 191 192 if ((lname = strstr(options, "user="))) { 193 lname += 5; 194 for (i = 0; isgraph(*lname); lname++) { 195 name[i++] = *lname; 196 } 197 name[i] = 0; 198 getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp); 199 if (!pwdp) { 200 UPSD_LOG_ERROR("Unable to resolve user '%s'", name); 201 return UPSD_COMMAND_ERROR; 202 } 203 user = pwd.pw_uid; 204 } 205 206 if ((lname = strstr(options, "group="))) { 207 lname += 6; 208 for (i = 0; isgraph(*lname); lname++) { 209 name[i++] = *lname; 210 } 211 name[i] = 0; 212 getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp); 213 if (!grpp) { 214 UPSD_LOG_ERROR("Unable to resolve group '%s'", name); 215 return UPSD_COMMAND_ERROR; 216 } 217 group = grp.gr_gid; 218 } 219 } 220 221 222 char *p = buffer, **argv; 223 int args = 0; 224 strcpy(buffer, command); 225 for (;;) { 226 for (; isblank(*p); p++) { 227 *p = 0; 228 } 229 if (isgraph(*p)) { 230 args++; 231 for (; isgraph(*p); p++); 232 *p = 0; 233 } else { 234 break; 235 } 236 } 237 argv = malloc((args + 1) * sizeof(char*)); 238 239 p = buffer; 240 for (int i = 0; i < args; i++) { 241 for (; !(*p); p++); 242 argv[i] = p; 243 for (; *p; p++); 244 } 245 argv[args] = NULL; 246 247 if (background) { 248 setsid(); 249 chdir("/"); 250 int devnull = open("/dev/null", O_RDWR); 251 dup2(devnull, STDIN_FILENO); 252 dup2(devnull, STDOUT_FILENO); 253 dup2(devnull, STDERR_FILENO); 254 close(devnull); 255 } 256 257 if (group) { 258 setgid(group); 259 } 260 261 if (user) { 262 setuid(user); 263 } 264 265 execv(argv[0], argv); 266 free(argv); 267 _exit(UPSD_COMMAND_EXECFAILED); 268 }
