Changeset 5807

Show
Ignore:
Timestamp:
03/13/10 14:58:03 (3 years ago)
Author:
Cyrus
Message:

upsd: Add extension hooks, Implement builtin start-stop-daemon utility,
Make runlevel API more straight-forward, Add a lock for interactive processes

Location:
luci2/upsd
Files:
2 added
1 removed
13 modified

Legend:

Unmodified
Added
Removed
  • luci2/upsd/action.c

    r5714 r5807  
    2525#include "service.h" 
    2626#include "action.h" 
     27#include "hook.h" 
    2728 
    2829/* Create a list wrapper */ 
    29 static upsd_initlist_t* _libupsd_action_enlist 
     30UPSD_MALLOC static upsd_initlist_t* _libupsd_action_enlist 
    3031(upsd_init_t *init, upsd_initlist_t *next) { 
    3132    upsd_initlist_t *list = malloc(sizeof(upsd_initlist_t)); 
     
    141142    upsd_report_t *report; 
    142143    int status; 
    143     int legacy = 1; 
     144    int legacy = 1, interactive = 1; 
    144145    int done = 0; 
    145146    int waiting = 0; 
     
    156157            continue;   /* Don't process legacy elements in parallel */ 
    157158        } 
     159        if (!interactive && (init->flags & UPSD_INIT_INTERACTIVE)) { 
     160            prev = &list->next; 
     161            continue;   /* Don't process interacitve elements in parallel */ 
     162        } 
    158163        if (inst->flags & UPSD_FLAG_SIMULATE) { 
    159164            UPSD_LOG_WARN("Simulating action %u on '%s'", (unsigned)action, 
    160165                    init->provides[0]); 
    161166        } 
     167        if (init->hndl.status != UPSD_EAGAIN) { 
     168            _libupsd_hook_call(state, init, action, UPSD_HOOK_BEFORE); 
     169        } 
    162170 
    163171        status = ((inst->flags & UPSD_FLAG_SIMULATE) || (!init->worker)) ? 
     
    165173 
    166174        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                } 
    171181            } 
    172182            if (init->flags & UPSD_INIT_LEGACY) { 
    173183                legacy = 0; /* Stop processing legacy elements for this turn */ 
    174184            } 
    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; 
    177191        if (status != UPSD_EAGAIN) { 
    178             init->hndl.status = status; 
    179192            if (init->worker) { 
    180193                init->worker(init, UPSD_ACTION_INTERNAL_CLEAN); 
     
    198211                        (!status || (inst->flags & UPSD_FLAG_SKIPFAILED))); 
    199212            } 
     213            _libupsd_hook_call(state, init, action, UPSD_HOOK_AFTER); 
    200214 
    201215            inst->lasterror = (status) ? status : inst->lasterror; 
     
    339353 
    340354    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)))) { 
    342356            return UPSD_ENOMEM; 
    343357        } 
     
    383397 
    384398    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)))) { 
    386400            return UPSD_ENOMEM; 
    387401        } 
     
    419433 
    420434    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)))) { 
    422436            return UPSD_ENOMEM; 
    423437        } 
  • luci2/upsd/cbi2/datatypes.h

    r5714 r5807  
    88#if __GNUC__ >= 4 
    99    #define CBI2_LOCAL  __attribute__ ((visibility("hidden"))) 
     10    #define CBI2_MALLOC __attribute__ ((malloc)) 
    1011#else 
    1112    #define CBI2_LOCAL 
     13    #define CBI2_MALLOC 
    1214#endif 
    1315 
  • luci2/upsd/cbi2/hmap.c

    r5714 r5807  
    3636 
    3737 
    38 CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint) { 
     38CBI2_MALLOC CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint) { 
    3939    cbi2_hmap_t* map = calloc(1, sizeof(cbi2_hmap_t)); 
    4040    if (!map) { 
     
    125125} 
    126126 
     127#ifdef CBI2_HMAP_UNSET 
    127128CBI2_LOCAL int cbi2_hmap_unset 
    128129(cbi2_hmap_t *map, const void *key, uint16_t len) { 
     
    162163    return CBI2_OK; 
    163164} 
     165#endif 
    164166 
    165167CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_next 
     
    194196} 
    195197 
     198#ifdef CBI2_HMAP_REFCOUNT 
    196199CBI2_LOCAL void cbi2_hmap_reference(cbi2_hmap_t *map) { 
    197200    map->refcount++; 
     
    205208    } 
    206209} 
     210#endif 
    207211 
    208212 
     
    307311            break; 
    308312        case CBI2_TYPE_HASHMAP: 
     313#ifdef CBI2_HMAP_REFCOUNT 
    309314            cbi2_hmap_unreference(bucket->data.buffer.pointer); 
    310             break; 
     315#else 
     316            cbi2_hmap_destroy(bucket->data.buffer.pointer); 
    311317#endif 
    312     } 
    313 } 
     318            break; 
     319#endif 
     320    } 
     321} 
  • luci2/upsd/cbi2/hmap.h

    r5714 r5807  
    3838 
    3939 
    40 CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint); 
     40CBI2_MALLOC CBI2_LOCAL cbi2_hmap_t* cbi2_hmap_create(cbi2_size_t hint); 
    4141CBI2_LOCAL int cbi2_hmap_resize(cbi2_hmap_t *map, cbi2_size_t payload); 
    4242CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_rawget(cbi2_hmap_t *map, 
     
    4444CBI2_LOCAL int cbi2_hmap_get (cbi2_hmap_t *map, const void *key, uint16_t len, 
    4545cbi2_hmap_data_t **value); 
     46 
     47#ifdef CBI2_HMAP_UNSET 
    4648CBI2_LOCAL int cbi2_hmap_unset(cbi2_hmap_t *map, const void *key, uint16_t len); 
     49#endif 
     50 
    4751CBI2_LOCAL cbi2_hmap_bucket_t* cbi2_hmap_next 
    4852(cbi2_hmap_t *map, cbi2_hmap_iter_t *iter); 
     
    5155CBI2_LOCAL void cbi2_hmap_clear(cbi2_hmap_t *map); 
    5256CBI2_LOCAL void cbi2_hmap_destroy(cbi2_hmap_t *map); 
     57 
     58#ifdef CBI2_HMAP_REFCOUNT 
    5359CBI2_LOCAL void cbi2_hmap_reference(cbi2_hmap_t *map); 
    5460CBI2_LOCAL void cbi2_hmap_unreference(cbi2_hmap_t *map); 
     61#endif 
    5562 
    5663#endif /* CBI2_HMAP_H_ */ 
  • luci2/upsd/cbi2/hmap_config.h

    r5714 r5807  
    2626#define CBI2_HMAP_CAPACITY_MIN  16 
    2727 
     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 
    2843 
    2944typedef cbi2_blob_t cbi2_hmap_blob_t; 
  • luci2/upsd/core.h

    r5795 r5807  
    2525typedef struct upsd_initlist upsd_initlist_t; 
    2626typedef struct upsd_handler upsd_handler_t; 
     27typedef struct upsd_extension upsd_extension_t; 
    2728typedef union upsd_handle upsd_handle_t; 
    2829 
     
    5152    char **options; 
    5253    char **provides; 
    53     upsd_worker_t worker; 
     54    upsd_worker_t *worker; 
    5455    upsd_handler_t hndl; 
    5556}; 
     
    8889}; 
    8990 
     91struct 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 
    9099 
    91100#include "cbi2/hmap.h" 
     
    93102struct upsd_state { 
    94103    cbi2_hmap_t *events; 
     104    upsd_extension_t *extensions; 
    95105    upsd_report_t *report; 
    96106    size_t reportidx; 
     
    98108}; 
    99109 
    100  
    101110#define UPSD_INIT_LEGACY            0x01 
    102111#define UPSD_INIT_INTERNAL          0x02 
     112#define UPSD_INIT_INTERACTIVE       0x04 
     113 
    103114 
    104115#if UPSD_LOGGING >= 4 
  • luci2/upsd/libupsd.c

    r5795 r5807  
    2626#include "service.h" 
    2727#include "action.h" 
     28#include "hook.h" 
    2829 
    2930upsd_state_t* libupsd_create() { 
     
    4647} 
    4748 
     49int libupsd_hook_register(upsd_state_t *state, upsd_hook_t *hook, 
     50void *context, upsd_action_t action, uint16_t flags) { 
     51    return _libupsd_hook_register(state, hook, context, action, flags); 
     52} 
     53 
    4854int libupsd_dependency_add(upsd_state_t *state, const char *issuer, 
    4955const char *receiver, upsd_action_t action, uint16_t flags) { 
     
    5157} 
    5258 
    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  
    5859int libupsd_service_register(upsd_state_t *state, 
    59 const char **facilities, upsd_worker_t worker, void *identifier) { 
    60     return _libupsd_service_register(state, facilities, 
     60const char **services, upsd_worker_t worker, void *identifier) { 
     61    return _libupsd_service_register(state, services, 
    6162            worker, identifier, 0, NULL); 
    6263} 
     
    102103} 
    103104 
    104 int libupsd_runlevel_control 
    105 (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); 
     105int 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); 
    109110    } 
    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; 
    111117} 
    112118 
     
    121127    _libupsd_action_cleanup(state); 
    122128    _libupsd_service_clear(state); 
    123     cbi2_hmap_unreference(state->events); 
     129    _libupsd_hook_clear(state); 
     130    cbi2_hmap_destroy(state->events); 
    124131    free(state); 
    125132} 
  • luci2/upsd/service.c

    r5795 r5807  
    3131 
    3232#include "service.h" 
    33 #include "worker.h" 
    3433 
    3534/* Get the init object designated for the specified service entry, if any */ 
     
    8887 
    8988    if (!(emitter_e->emitting++ % UPSD_SYS_EVENT_STEP)) { 
    90         emitter_e->emitters = realloc(emitter_e->emitters, sizeof 
     89        upsd_listener_t **tmp = realloc(emitter_e->emitters, sizeof 
    9190            (upsd_listener_t*) * (emitter_e->emitting + UPSD_SYS_EVENT_STEP - 1)); 
    92         if (!emitter_e->emitters) { 
     91        if (!tmp) { 
    9392            return UPSD_ENOMEM; 
    9493        } 
     94        emitter_e->emitters = tmp; 
    9595    } 
    9696    emitter_e->emitters[emitter_e->emitting - 1] = listener; 
     
    102102 
    103103    if (!(receiver_e->receiving++ % UPSD_SYS_EVENT_STEP)) { 
    104         receiver_e->receivers = realloc(receiver_e->receivers, sizeof 
     104        upsd_listener_t **tmp = realloc(receiver_e->receivers, sizeof 
    105105        (upsd_listener_t*) * (receiver_e->receiving + UPSD_SYS_EVENT_STEP - 1)); 
    106         if (!receiver_e->receivers) { 
     106        if (!tmp) { 
    107107            return UPSD_ENOMEM; 
    108108        } 
     109        receiver_e->receivers = tmp; 
    109110    } 
    110111    receiver_e->receivers[receiver_e->receiving - 1] = listener; 
     
    177178    for (char **c = init->options; *c; c++, i++); 
    178179    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) { 
    181182        return UPSD_ENOMEM; 
    182183    } 
     184    init->options = tmp; 
    183185    for (const char **c = options; *c; c++, j++) { 
    184186        init->options[i++] = strdup(*c); 
     
    221223    } 
    222224    init->identifier = rpath; 
    223     init->worker = _libupsd_worker_exec; 
     225    init->worker = libupsd_worker_exec; 
    224226    if (_libupsd_service_designate(state, name, init)) { 
    225227        UPSD_LOG_INFO("Designated name %s is occupied.", name); 
     
    329331                } 
    330332            } 
     333        } else if (!memcmp(buffer, UPSD_LITERAL_PTRSIZE("# X-Interactive:"))) { 
     334            init->flags |= UPSD_INIT_INTERACTIVE; 
    331335        } 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            } 
    332343            if (++options == opts) { 
    333344                opts += 4; 
    334                 if (!(init->options = realloc(init->options, 
     345                if (!(entries = realloc(init->options, 
    335346                        (opts + 1)  * sizeof(char*)))) { 
    336347                    break; 
    337348                } 
     349                init->options = entries; 
    338350            } 
    339351            init->options[options] = strdup(buffer + 2); 
     
    350362/* Create a dummy services that is treated as provided */ 
    351363UPSD_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, 
    353365void *identifier, uint16_t flags, upsd_init_t **handle) { 
    354366    upsd_init_t *init = calloc(1, sizeof(upsd_init_t)); 
     
    456468        size_t baselen = strlen(entry->d_name); 
    457469        ((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)) { 
    463471            _libupsd_service_parse(state, cpath, NULL); 
    464472        } 
  • luci2/upsd/service.h

    r5795 r5807  
    1111UPSD_LOCAL int _libupsd_service_init(upsd_state_t *state); 
    1212UPSD_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, 
    1414void *identifier, uint16_t flags, upsd_init_t **handle); 
    1515UPSD_LOCAL upsd_init_t* _libupsd_service_next 
  • luci2/upsd/ups-cli/ups.c

    r5714 r5807  
    6868        "   status          Returns the status of a service\n\n" 
    6969        "   enter           Enter a runlevel\n" 
    70         "   leave           Leave a runlevel\n" 
    7170        "\n\nOptions:\n" 
    7271        "   -a fac1[,fac2,...]  Automatically provide facilities\n" 
     
    153152        action = UPSD_ACTION_STATUS; 
    154153    } 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; 
    159155        func = UPS_FUNC_RUNLEVEL; 
    160156    } else { 
     
    182178    } else if (func == UPS_FUNC_RUNLEVEL) { 
    183179        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); 
    185181    } 
    186182 
  • luci2/upsd/upsd.h

    r5795 r5807  
    2222#ifndef UPSD_H_ 
    2323#define UPSD_H_ 
     24 
     25#if __GNUC__ >= 4 
     26    #define UPSD_MALLOC __attribute__ ((malloc)) 
     27#else 
     28    #define UPSD_MALLOC 
     29#endif 
    2430 
    2531#include <stdint.h> 
     
    6773#define UPSD_ACTION_STATUS          6 
    6874 
    69 /* Known runlevel actions */ 
    70 #define UPSD_ACTION_ENTER           UPSD_ACTION_START 
    71 #define UPSD_ACTION_LEAVE           UPSD_ACTION_STOP 
    72  
    7375/* Known rc actions */ 
    7476#define UPSD_RC_INSTALL             1 
     
    8688 
    8789/* 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 
    8996 
    9097 
     
    93100typedef struct upsd_state upsd_state_t; 
    94101typedef struct upsd_init upsd_init_t; 
    95 typedef int(*upsd_worker_t)(upsd_init_t *init, upsd_action_t action); 
     102typedef int(upsd_worker_t)(upsd_init_t *init, upsd_action_t action); 
     103typedef int(upsd_hook_t) 
     104(void *context, upsd_init_t *init, upsd_action_t action, uint16_t flags); 
    96105typedef struct upsd_report { 
    97106    upsd_action_t action; 
     
    100109} upsd_report_t; 
    101110 
     111 
     112/* Builtin workers */ 
     113int libupsd_worker_exec(upsd_init_t *init, upsd_action_t action); 
     114int libupsd_worker_daemon(upsd_init_t *init, upsd_action_t action); 
     115 
     116 
    102117/** 
    103118 * libupsd_create() - Create a new ups.d state. 
     
    144159 */ 
    145160int 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 */ 
     180int libupsd_hook_register(upsd_state_t *state, upsd_hook_t *hook, 
     181void *context, upsd_action_t action, uint16_t flags); 
    146182 
    147183/** 
     
    168204 
    169205/** 
    170  * libupsd_options_add() - Add user-defined options to a service. 
    171  * @state:      ups.d state 
    172  * @service:    Target service 
    173  * @options:    Options added to the service 
    174  * 
    175  * Adds user-defined options to a given service. Options to be added should 
    176  * begin with an X- marking them as custom. Standardized LSB-Options 
    177  * (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 /** 
    188206 * libupsd_service_register() - Register a user-defined service. 
    189207 * @state:      ups.d state 
    190  * @facilities: Facilities provided by the new service 
     208 * @services:   Facilities provided by the new service 
    191209 * @worker:     Associated worker for performing tasks (optional) 
    192210 * @identifier: Service-specific identifier, e.g. pathname (optional) 
     
    208226 * Returns an ups.d status code. 
    209227 */ 
    210 int libupsd_service_register(upsd_state_t *state, const char **facilities, 
     228int libupsd_service_register(upsd_state_t *state, const char **services, 
    211229        upsd_worker_t worker, void *identifier); 
    212230 
     
    261279 
    262280/** 
    263  * libupsd_runlevel_control() - Perform an action on a runlevel. 
     281 * libupsd_runlevel_enter() - Enter a runlevel. 
    264282 * @state:      ups.d state 
    265283 * @runlevel:   ASCII-Char describing the runlevel 
    266  * @action:     Runlevel action to perform 
    267284 * @flags:      Flags controlling the action 
    268285 * 
     
    276293 * values (usually a runlevel of 'X' translates to /etc/rcX.d). 
    277294 * 
    278  * Action can be any runlevel action, for now only UPSD_ACTION_ENTER and 
    279  * UPSD_ACTION_LEAVE are defined which will start / stop associated services. 
    280295 * 
    281296 * NOTE: Legacy init scripts (without LSB-style dependency comments) are also 
     
    285300 * failed or UPSD_OK if all actions could be completed successfully. 
    286301 */ 
    287 int libupsd_runlevel_control(upsd_state_t *state, char runlevel, 
    288         upsd_action_t action, uint16_t flags); 
     302int libupsd_runlevel_enter(upsd_state_t *state, char runlevel, uint16_t flags); 
    289303 
    290304/** 
  • luci2/upsd/upsd_config.h

    r5795 r5807  
    1515 */ 
    1616#ifndef UPSD_SYS_EVENT_STEP 
    17 #define UPSD_SYS_EVENT_STEP 8 
     17#define UPSD_SYS_EVENT_STEP 7 
    1818#endif 
    1919 
  • luci2/upsd/worker.c

    r5714 r5807  
    2222#include <sys/types.h> 
    2323#include <sys/wait.h> 
     24#include <sys/stat.h> 
    2425#include <unistd.h> 
    2526#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" 
    2735 
    2836static char* const _libupsd_worker_cmds[] = {"start", "stop", "restart", 
    2937        "force-reload", "reload", "status"}; 
    3038 
    31 UPSD_LOCAL int _libupsd_worker_exec(upsd_init_t *init, upsd_action_t action) { 
     39int libupsd_worker_exec(upsd_init_t *init, upsd_action_t action) { 
    3240    pid_t pid = init->hndl.handle.pid; 
    3341    if (action == UPSD_ACTION_INTERNAL_CLEAN) { 
     
    6674} 
    6775 
     76int 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}