コード例 #1
0
ファイル: module.c プロジェクト: BackupTheBerlios/einit-svn
uint16_t service_usage_query_group (enum einit_usage_query task, const struct lmodule *module, const char *service) {
 uint16_t ret = 0;
 struct stree *ha;

 if (!service) return 0;

 emutex_lock (&service_usage_mutex);
 if (task & service_add_group_provider) {
  if (!module || !module->module) {
   emutex_unlock (&service_usage_mutex);

   return 0;
  }

  if (!service_usage || !(ha = streefind (service_usage, service, tree_find_first))) {
   struct service_usage_item nitem;
   memset (&nitem, 0, sizeof (struct service_usage_item));
   nitem.provider = (struct lmodule **)setadd ((void **)nitem.provider, (void *)module, SET_NOALLOC);
   service_usage = streeadd (service_usage, service, &nitem, sizeof (struct service_usage_item), NULL);
  } else {
   struct service_usage_item *citem = (struct service_usage_item *)ha->value;

   if (citem) {
    if (!inset ((const void **)citem->provider, (void *)module, SET_NOALLOC)) {
     citem->provider = (struct lmodule **)setadd ((void **)citem->provider, (void *)module, SET_NOALLOC);
    }
   }
  }
 }
 if (task & service_set_group_providers) {
  if (!service_usage || !(ha = streefind (service_usage, service, tree_find_first))) {
   struct service_usage_item nitem;
   memset (&nitem, 0, sizeof (struct service_usage_item));
   nitem.provider = (struct lmodule **)setdup ((const void **)module, SET_NOALLOC);
   service_usage = streeadd (service_usage, service, &nitem, sizeof (struct service_usage_item), NULL);
  } else {
   struct service_usage_item *citem = (struct service_usage_item *)ha->value;

   if (citem) {
    free (citem->provider);
    citem->provider = (struct lmodule **)setdup ((const void **)module, SET_NOALLOC);
   }
  }
 }

 emutex_unlock (&service_usage_mutex);
 return ret;
}
コード例 #2
0
void fbsplash_queue_comand (const char *command) {
 emutex_lock (&fbsplash_commandQ_mutex);
 fbsplash_commandQ = (char **)setadd ((void **)fbsplash_commandQ, command, SET_TYPE_STRING);
 emutex_unlock (&fbsplash_commandQ_mutex);

 pthread_cond_broadcast (&fbsplash_commandQ_cond);
}
コード例 #3
0
ファイル: event.c プロジェクト: BackupTheBerlios/einit-svn
void *event_emit (struct einit_event *event, enum einit_event_emit_flags flags) {
 pthread_t **threads = NULL;
 if (!event || !event->type) return NULL;

 event_do_wakeup_calls (event->type);

 if (flags & einit_event_flag_spawn_thread) {
  struct einit_event *ev = evdup(event);
  if (!ev) return NULL;

  ethread_spawn_detached_run ((void *(*)(void *))event_subthread, (void *)ev);

  return NULL;
 }

 uint32_t subsystem = event->type & EVENT_SUBSYSTEM_MASK;

/* initialise sequence id and timestamp of the event */
  event->seqid = cseqid++;
  event->timestamp = time(NULL);

  struct event_function *cur = event_functions;
  while (cur) {
   if (((cur->type == subsystem) || (cur->type == einit_event_subsystem_any)) && cur->handler) {
    if (flags & einit_event_flag_spawn_thread_multi_wait) {
     pthread_t *threadid = emalloc (sizeof (pthread_t));
     struct evt_wrapper_data *d = emalloc (sizeof (struct evt_wrapper_data));

     d->event = evdup(event);
     d->handler = cur->handler;

     ethread_create (threadid, NULL, (void *(*)(void *))event_thread_wrapper, d);
     threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
    } else
     cur->handler (event);
   }
   cur = cur->next;
  }

 if (event->chain_type) {
  event->type = event->chain_type;
  event->chain_type = 0;
  event_emit (event, flags);
 }

 if ((flags & einit_event_flag_spawn_thread_multi_wait) && threads) {
  int i = 0;

  for (; threads[i]; i++) {
   pthread_join (*(threads[i]), NULL);

   free (threads[i]);
  }

  free (threads);
 }

 return NULL;
}
コード例 #4
0
ファイル: db_objects.c プロジェクト: welterde/NuMOO
void
db_set_object_flag(Objid oid, db_object_flag f)
{
    objects[oid]->flags |= (1 << f);
    if (f == FLAG_USER) {
	Var v;

	v.type = TYPE_OBJ;
	v.v.obj = oid;
	all_users = setadd(all_users, v);
    }
}
コード例 #5
0
ファイル: process.c プロジェクト: BackupTheBerlios/einit-svn
pid_t *filter_processes_cwd (struct pc_conditional * cond, pid_t * ret, struct process_status ** stat) {
 uint32_t i = 0;
 if (stat && cond && cond->para)
  for (; stat[i]; i++) {
   if (stat[i]->cwd && strmatch ((char *)cond->para, stat[i]->cwd)) {
    uintptr_t tmp = (stat[i]->pid);
    ret = (pid_t *)setadd ((void **)ret, (void *)tmp, SET_NOALLOC);
   }
  }

 return ret;
}
コード例 #6
0
void linux_static_dev_hotplug_handle (char **v) {
    if (v && v[0]) {
        int i = 0;
        char **args = NULL;
        struct einit_event ev = evstaticinit(einit_hotplug_generic);

        if (strstr (v[0], "add@") == v[0]) {
            ev.type = einit_hotplug_add;
        } else if (strstr (v[0], "remove@") == v[0]) {
            ev.type = einit_hotplug_remove;
        } else if (strstr (v[0], "change@") == v[0]) {
            ev.type = einit_hotplug_change;
        } else if (strstr (v[0], "online@") == v[0]) {
            ev.type = einit_hotplug_online;
        } else if (strstr (v[0], "offline@") == v[0]) {
            ev.type = einit_hotplug_offline;
        } else if (strstr (v[0], "move@") == v[0]) {
            ev.type = einit_hotplug_move;
        }

        for (i = 1; v[i]; i++) {
            char *n = strchr (v[i], '=');
            if (n) {
                *n = 0;
                n++;

                args = (char **)setadd ((void **)args, v[i], SET_TYPE_STRING);
                args = (char **)setadd ((void **)args, n, SET_TYPE_STRING);
            }
        }

        ev.stringset = args;

        /* emit the event, waiting for it to be processed */
        event_emit (&ev, einit_event_flag_broadcast);
        evstaticdestroy (ev);

        if (args) free (args);
    }
}
コード例 #7
0
ファイル: listutils.c プロジェクト: bytenik/HybridCircle
/* Remove_Duplicates - from Access_Denied@LambdaMOO. */
static package
bf_remove_duplicates(Var arglist, Byte next, void *vdata, Objid progr)
{
    Var	r;
    int	i;

    r = new_list(0);
    for (i = 1; i <= arglist.v.list[1].v.list[0].v.num; i++)
        r = setadd(r, var_ref(arglist.v.list[1].v.list[i]));

    free_var(arglist);
    return make_var_pack(r);
}
コード例 #8
0
int linux_kernel_modules_load (char **modules) {
 if (!modules) return status_failed;
 pthread_t **threads = NULL;

 char *modprobe_command = cfg_getstring ("configuration-command-modprobe/with-env", 0);
 uint32_t i = 0;

 for (; modules[i]; i++) if (strcmp ("", modules[i])) {
  const char *tpldata[] = { "module", modules[i], NULL };
  char *applied = apply_variables (modprobe_command, tpldata);

  if (applied) {
   notice (4, "loading kernel module: %s", modules[i]);

   if (modules[i+1]) {
    pthread_t *threadid = emalloc (sizeof (pthread_t));

    if (ethread_create (threadid, NULL, (void *(*)(void *))linux_kernel_modules_load_exec, applied)) {
     linux_kernel_modules_load_exec (applied);
    } else {
     threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
    }
   } else {
    linux_kernel_modules_load_exec (applied);
   }
  }
 }

 free (modules);

 if (threads) {
  int i = 0;

  for (; threads[i]; i++) {
   pthread_join (*(threads[i]), NULL);

   free (threads[i]);
  }

  free (threads);
 }

 return status_ok;
}
コード例 #9
0
int main(int argc, char **argv, char **environ) {
#else
int main(int argc, char **argv) {
#endif
 int i, ret = EXIT_SUCCESS;
 pid_t pid = getpid(), wpid = 0;
 char **ipccommands = NULL;
 int pthread_errno;
 FILE *commandpipe_in, *commandpipe_out;
 int commandpipe[2];
 int debugsocket[2];
 char need_recovery = 0;
 char debug = 0;
 int debugme_pipe = 0;
 char crash_threshold = 5;
 char *einit_crash_data = NULL;

 boottime = time(NULL);

 uname (&osinfo);
 config_configure();

// initialise subsystems
 ipc_configure(NULL);

// is this the system's init-process?
 isinit = getpid() == 1;

 event_listen (einit_event_subsystem_core, core_einit_event_handler);
 event_listen (einit_event_subsystem_timer, core_timer_event_handler);

 if (argv) einit_argv = (char **)setdup ((const void **)argv, SET_TYPE_STRING);

/* check command line arguments */
 for (i = 1; i < argc; i++) {
  if (argv[i][0] == '-')
   switch (argv[i][1]) {
    case 'c':
     if ((++i) < argc)
      einit_default_startup_configuration_files[0] = argv[i];
     else
      return print_usage_info ();
     break;
    case 'h':
     return print_usage_info ();
     break;
    case 'v':
     eputs("eINIT " EINIT_VERSION_LITERAL "\n", stdout);
     return 0;
    case 'L':
     eputs("eINIT " EINIT_VERSION_LITERAL
          "\nThis Program is Free Software, released under the terms of this (BSD) License:\n"
          "--------------------------------------------------------------------------------\n"
          "Copyright (c) 2006, 2007, Magnus Deininger\n"
          BSDLICENSE "\n", stdout);
     return 0;
    case '-':
     if (strmatch(argv[i], "--check-configuration") || strmatch(argv[i], "--checkup") || strmatch(argv[i], "--wtf")) {
      ipccommands = (char **)setadd ((void **)ipccommands, "examine configuration", SET_TYPE_STRING);
     } else if (strmatch(argv[i], "--help"))
      return print_usage_info ();
     else if (strmatch(argv[i], "--ipc-command") && argv[i+1])
      ipccommands = (char **)setadd ((void **)ipccommands, (void *)argv[i+1], SET_TYPE_STRING);
     else if (strmatch(argv[i], "--override-init-check"))
      initoverride = 1;
     else if (strmatch(argv[i], "--sandbox")) {
      einit_default_startup_configuration_files[0] = "lib/einit/einit.xml";
      coremode = einit_mode_sandbox;
      need_recovery = 1;
     } else if (strmatch(argv[i], "--metadaemon")) {
      coremode = einit_mode_metadaemon;
     } else if (strmatch(argv[i], "--bootstrap-modules")) {
      bootstrapmodulepath = argv[i+1];
     } else if (strmatch(argv[i], "--debugme")) {
      debugme_pipe = parse_integer (argv[i+1]);
      i++;
      initoverride = 1;
     } else if (strmatch(argv[i], "--debug")) {
      debug = 1;
     }

     break;
   }
 }

/* check environment */
 if (environ) {
  uint32_t e = 0;
  for (e = 0; environ[e]; e++) {
   char *ed = estrdup (environ[e]);
   char *lp = strchr (ed, '=');

   *lp = 0;
   lp++;

   if (strmatch (ed, "softlevel")) {
    einit_startup_mode_switches = str2set (':', lp);
   } if (strmatch (ed, "mode")) {
/* override default mode-switches with the ones in the environment variable mode= */
    einit_startup_mode_switches = str2set (':', lp);
   } else if (strmatch (ed, "einit")) {
/* override default configuration files and/or mode-switches with the ones in the variable einit= */
    char **tmpstrset = str2set (',', lp);
    uint32_t rx = 0;

    for (rx = 0; tmpstrset[rx]; rx++) {
     char **atom = str2set (':', tmpstrset[rx]);

     if (strmatch (atom[0], "file")) {
/* specify configuration files */
      einit_startup_configuration_files = (char **)setdup ((const void **)atom, SET_TYPE_STRING);
      einit_startup_configuration_files = (char **)strsetdel (einit_startup_configuration_files, (void *)"file");
     } else if (strmatch (atom[0], "mode")) {
/* specify mode-switches */
      einit_startup_mode_switches = (char **)setdup ((const void **)atom, SET_TYPE_STRING);
      einit_startup_mode_switches = (char **)strsetdel (einit_startup_mode_switches, (void *)"mode");
     } else if (strmatch (atom[0], "stfu")) {
      einit_quietness = 3;
     } else if (strmatch (atom[0], "silent")) {
      einit_quietness = 2;
     } else if (strmatch (atom[0], "quiet")) {
      einit_quietness = 1;
     }

     free (atom);
    }

    free (tmpstrset);
   }

   free (ed);
  }

  einit_initial_environment = (char **)setdup ((const void **)environ, SET_TYPE_STRING);
 }

 if (!einit_startup_mode_switches) einit_startup_mode_switches = einit_default_startup_mode_switches;
 if (!einit_startup_configuration_files) einit_startup_configuration_files = einit_default_startup_configuration_files;

 respawn:

 pipe (commandpipe);

 fcntl (commandpipe[1], F_SETFD, FD_CLOEXEC);

 socketpair (AF_UNIX, SOCK_STREAM, 0, debugsocket);
 fcntl (debugsocket[0], F_SETFD, FD_CLOEXEC);
 fcntl (debugsocket[1], F_SETFD, FD_CLOEXEC);

 if (!debug) {
  fcntl (commandpipe[0], F_SETFD, FD_CLOEXEC);
  commandpipe_in = fdopen (commandpipe[0], "r");
 }
 commandpipe_out = fdopen (commandpipe[1], "w");

 if (!initoverride && ((pid == 1) || ((coremode & einit_mode_sandbox) && !ipccommands))) {
// if (pid == 1) {
  initoverride = 1;
#if 0
#ifdef LINUX
  if ((einit_sub = syscall(__NR_clone, CLONE_PTRACE | SIGCHLD, 0, NULL, NULL, NULL)) < 0) {
   bitch (bitch_stdio, errno, "Could not fork()");
   eputs (" !! Haven't been able to fork a secondary worker process. This is VERY bad, you will get a lot of zombie processes! (provided that things work at all)\n", stderr);
  }
#else
#endif
#endif
  if ((einit_sub = fork()) < 0) {
   bitch (bitch_stdio, errno, "Could not fork()");
   eputs (" !! Haven't been able to fork a secondary worker process. This is VERY bad, you will get a lot of zombie processes! (provided that things work at all)\n", stderr);
  }
 }

 if (einit_sub) {
/* PID==1 part */
  int rstatus;
  struct sigaction action;

/* signal handlers */
  action.sa_sigaction = einit_sigint;
  sigemptyset(&(action.sa_mask));
  action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
  if ( sigaction (SIGINT, &action, NULL) ) bitch (bitch_stdio, 0, "calling sigaction() failed.");

/* ignore sigpipe */
  action.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;

  if ( sigaction (SIGPIPE, &action, NULL) ) bitch (bitch_stdio, 0, "calling sigaction() failed.");

  close (debugsocket[1]);
  if (einit_crash_data) {
   free (einit_crash_data);
   einit_crash_data = NULL;
  }

  while (1) {
   wpid = waitpid(-1, &rstatus, 0); /* this ought to wait for ANY process */

   if (wpid == einit_sub) {
//    goto respawn; /* try to recover by re-booting */
    if (!debug) if (commandpipe_in) fclose (commandpipe_in);
    if (commandpipe_out) fclose (commandpipe_out);

    if (WIFEXITED(rstatus) && (WEXITSTATUS(rstatus) != einit_exit_status_die_respawn)) {
     fprintf (stderr, "eINIT has quit properly.\n");

     if (!(coremode & einit_mode_sandbox)) {
      if (WEXITSTATUS(rstatus) == einit_exit_status_last_rites_halt) {
       execl (EINIT_LIB_BASE "/bin/last-rites", EINIT_LIB_BASE "/bin/last-rites", "h", NULL);
      } else if (WEXITSTATUS(rstatus) == einit_exit_status_last_rites_reboot) {
       execl (EINIT_LIB_BASE "/bin/last-rites", EINIT_LIB_BASE "/bin/last-rites", "r", NULL);
      } else if (WEXITSTATUS(rstatus) == einit_exit_status_last_rites_kexec) {
       execl (EINIT_LIB_BASE "/bin/last-rites", EINIT_LIB_BASE "/bin/last-rites", "k", NULL);
      }
     }

     exit (EXIT_SUCCESS);
    }

    int n = 5;
    fprintf (stderr, "The secondary eINIT process has died, waiting a while before respawning.\n");
    if ((einit_crash_data = readfd (debugsocket[0]))) {
     fprintf (stderr, " > neat, received crash data\n");
    }
    while ((n = sleep (n)));
    fprintf (stderr, "Respawning secondary eINIT process.\n");

    if (crash_threshold) crash_threshold--;
    else debug = 1;
    need_recovery = 1;
    initoverride = 0;

    close (debugsocket[0]);

    goto respawn;
   } else {
    if (commandpipe_out) {
     if (WIFEXITED(rstatus)) {
      fprintf (commandpipe_out, "pid %i terminated\n\n", wpid);
     } else {
      fprintf (commandpipe_out, "pid %i died\n\n", wpid);
     }
     fflush (commandpipe_out);
    }
   }
  }
 } else {
  enable_core_dumps ();

  close (debugsocket[0]);
  sched_trace_target = debugsocket[1];

  if (debug) {
   char **xargv = (char **)setdup ((const void **)argv, SET_TYPE_STRING);
   char tbuffer[BUFFERSIZE];
   struct stat st;
   char have_valgrind = 0;
   char have_gdb = 0;

   fputs ("eINIT needs to be debugged, starting in debugger mode\n.", stderr);

   xargv = (char **)setadd ((void **)xargv, (void *)"--debugme", SET_TYPE_STRING);
   snprintf (tbuffer, BUFFERSIZE, "%i", commandpipe[0]);
   xargv = (char **)setadd ((void **)xargv, (void *)tbuffer, SET_TYPE_STRING);

   xargv = strsetdel (xargv, "--debug"); // don't keep the --debug flag

   if (!stat ("/usr/bin/valgrind", &st)) have_valgrind = 1;
   if (!stat ("/usr/bin/gdb", &st)) have_gdb = 1;

   if (have_valgrind) {
    char **nargv = NULL;
    uint32_t i = 1;

#ifdef LINUX
    if (!(coremode & einit_mode_sandbox)) {
     mount ("proc", "/proc", "proc", 0, NULL);
     mount ("sys", "/sys", "sysfs", 0, NULL);

     system ("mount / -o remount,rw");
    }
#endif

    nargv = (char **)setadd ((void **)nargv, "/usr/bin/valgrind", SET_TYPE_STRING);
    nargv = (char **)setadd ((void **)nargv, "--log-file=/einit.valgrind", SET_TYPE_STRING);
    nargv = (char **)setadd ((void **)nargv, (coremode & einit_mode_sandbox) ? "sbin/einit" : "/sbin/einit", SET_TYPE_STRING);

    for (; xargv[i]; i++) {
     nargv = (char **)setadd ((void **)nargv, xargv[i], SET_TYPE_STRING);
    }

    execv ("/usr/bin/valgrind", nargv);
   } else {
    execv ((coremode & einit_mode_sandbox) ? "sbin/einit" : "/sbin/einit", xargv);
   }
  }

  if (debugme_pipe) { // commandpipe[0]
   fcntl (commandpipe[0], F_SETFD, FD_CLOEXEC);
   commandpipe_in = fdopen (debugme_pipe, "r");
  }

/* actual system initialisation */
  struct einit_event cev = evstaticinit(einit_core_update_configuration);

  if (ipccommands && (coremode != einit_mode_sandbox)) {
   coremode = einit_mode_ipconly;
  }

  eprintf (stderr, "eINIT " EINIT_VERSION_LITERAL ": Initialising: %s\n", osinfo.sysname);

  if ((pthread_errno = pthread_attr_init (&thread_attribute_detached))) {
   bitch(bitch_epthreads, pthread_errno, "pthread_attr_init() failed.");

   if (einit_initial_environment) free (einit_initial_environment);
   return -1;
  } else {
   if ((pthread_errno = pthread_attr_setdetachstate (&thread_attribute_detached, PTHREAD_CREATE_DETACHED))) {
    bitch(bitch_epthreads, pthread_errno, "pthread_attr_setdetachstate() failed.");
   }
  }

  if ((pthread_errno = pthread_key_create(&einit_function_macro_key, NULL))) {
   bitch(bitch_epthreads, pthread_errno, "pthread_key_create(einit_function_macro_key) failed.");

   if (einit_initial_environment) free (einit_initial_environment);
   return -1;
  }

/* this should be a good place to initialise internal modules */
   if (coremodules) {
    uint32_t cp = 0;

    eputs (" >> initialising in-core modules:", stderr);

    for (; coremodules[cp]; cp++) {
     struct lmodule *lmm;
     eprintf (stderr, " [%s]", (*coremodules[cp])->rid);
     lmm = mod_add(NULL, (*coremodules[cp]));

     lmm->source = estrdup("core");
    }

    eputs (" OK\n", stderr);
   }

/* emit events to read configuration files */
  if (einit_startup_configuration_files) {
   uint32_t rx = 0;
   for (; einit_startup_configuration_files[rx]; rx++) {
    cev.string = einit_startup_configuration_files[rx];
    event_emit (&cev, einit_event_flag_broadcast);
   }

   if (einit_startup_configuration_files != einit_default_startup_configuration_files) {
    free (einit_startup_configuration_files);
   }
  }

  cev.string = NULL;
  cev.type = einit_core_configuration_update;

// make sure we keep updating until everything is sorted out
  while (cev.type == einit_core_configuration_update) {
//   notice (2, "stuff changed, updating configuration.");

   cev.type = einit_core_update_configuration;
   event_emit (&cev, einit_event_flag_broadcast);
  }
  evstaticdestroy(cev);

  if (ipccommands) {
   uint32_t rx = 0;
   for (; ipccommands[rx]; rx++) {
    ret = ipc_process (ipccommands[rx], stdout);
   }

//   if (gmode == EINIT_GMODE_SANDBOX)
//    cleanup ();

   free (ipccommands);
   if (einit_initial_environment) free (einit_initial_environment);
   return ret;
  } else if ((coremode == einit_mode_init) && !isinit && !initoverride) {
   eputs ("WARNING: eINIT is configured to run as init, but is not the init-process (pid=1) and the --override-init-check flag was not specified.\nexiting...\n\n", stderr);
   exit (EXIT_FAILURE);
  } else {
/* actual init code */
   uint32_t e = 0;

   nice (einit_core_niceness_increment);

   if (need_recovery) {
    notice (1, "need to recover from something...");

    struct einit_event eml = evstaticinit(einit_core_recover);
    event_emit (&eml, einit_event_flag_broadcast);
    evstaticdestroy(eml);
   }

   if (einit_crash_data) {
    notice (1, "submitting crash data...");

    struct einit_event eml = evstaticinit(einit_core_crash_data);
    eml.string = einit_crash_data;
    event_emit (&eml, einit_event_flag_broadcast);
    evstaticdestroy(eml);

    free (einit_crash_data);
    einit_crash_data = NULL;
   }

   {
    notice (3, "running early bootup code...");

    struct einit_event eml = evstaticinit(einit_boot_early);
    event_emit (&eml, einit_event_flag_broadcast | einit_event_flag_spawn_thread_multi_wait);
    evstaticdestroy(eml);
   }

   notice (2, "scheduling startup switches.\n");

   for (e = 0; einit_startup_mode_switches[e]; e++) {
    struct einit_event ee = evstaticinit(einit_core_switch_mode);

    ee.string = einit_startup_mode_switches[e];
    event_emit (&ee, einit_event_flag_broadcast | einit_event_flag_spawn_thread | einit_event_flag_duplicate);
    evstaticdestroy(ee);
   }

   struct einit_event eml = evstaticinit(einit_core_main_loop_reached);
   eml.file = commandpipe_in;
   event_emit (&eml, einit_event_flag_broadcast);
   evstaticdestroy(eml);
  }

  if (einit_initial_environment) free (einit_initial_environment);
  return ret;
 }

/* this should never be reached... */
 if (einit_initial_environment) free (einit_initial_environment);
 return 0;
}
コード例 #10
0
ファイル: module.c プロジェクト: BackupTheBerlios/einit-svn
uint16_t service_usage_query (enum einit_usage_query task, const struct lmodule *module, const char *service) {
 uint16_t ret = 0;
 struct stree *ha;
 char **t;
 uint32_t i;
 struct service_usage_item *item;

 if ((!module || !module->module) && !service) return 0;

 emutex_lock (&service_usage_mutex);

 if (task & service_not_in_use) {
  ret |= service_not_in_use;
  struct stree *ha = service_usage;

/* a service is "in use" if
  * it's the provider for something, and
  * it's the only provider for that for that specific service, and
  * all of the users of that service use the */

  while (ha) {
   if (((struct service_usage_item *)(ha->value))->users &&
       (((struct service_usage_item *)(ha->value))->provider) &&
       ((((struct service_usage_item *)(ha->value))->provider)[0]) &&
       (!((((struct service_usage_item *)(ha->value))->provider)[1])) &&
       inset ((const void **)(((struct service_usage_item *)(ha->value))->provider), module, -1)) {

/* this one might be a culprit */
    uint32_t i = 0, r = 0;

    for (; (((struct service_usage_item *)(ha->value))->users)[i]; i++) {
     if ((((struct service_usage_item *)(ha->value))->users)[i]->si &&
         (((struct service_usage_item *)(ha->value))->users)[i]->si->requires) {

      if (inset ((const void **)((((struct service_usage_item *)(ha->value))->users)[i]->si->requires), ha->key, SET_TYPE_STRING)) {
       r++;
      }

     }
    }

/* yep, really is in use */
    if (i == r) {
     ret ^= service_not_in_use;
     break;
    }
   }
   ha = streenext (ha);
  }
 } else if (task & service_requirements_met) {
  ret |= service_requirements_met;
  if (module->si && (t = module->si->requires)) {
   for (i = 0; t[i]; i++) {
    if (!service_usage || !(ha = streefind (service_usage, t[i], tree_find_first)) ||
        !((struct service_usage_item *)(ha->value))->provider) {
     ret ^= service_requirements_met;
     break;
    }
   }
  }
 } else if (task & service_update) {
  modules_last_change = time(NULL);

  if (module->status & status_enabled) {
   if (module->si && (t = module->si->requires)) {
    for (i = 0; t[i]; i++) {
     if (service_usage && (ha = streefind (service_usage, t[i], tree_find_first)) && (item = (struct service_usage_item *)ha->value)) {
      item->users = (struct lmodule **)setadd ((void **)item->users, (void *)module, SET_NOALLOC);
     }
    }
   }
   if (module->si && (t = module->si->provides)) {
    for (i = 0; t[i]; i++) {
     if (service_usage && (ha = streefind (service_usage, t[i], tree_find_first)) && (item = (struct service_usage_item *)ha->value)) {
      item->provider = (struct lmodule **)setadd ((void **)item->provider, (void *)module, SET_NOALLOC);
     } else {
      struct service_usage_item nitem;
      memset (&nitem, 0, sizeof (struct service_usage_item));
      nitem.provider = (struct lmodule **)setadd ((void **)nitem.provider, (void *)module, SET_NOALLOC);
      service_usage = streeadd (service_usage, t[i], &nitem, sizeof (struct service_usage_item), NULL);
     }
    }
   }
  }

/* more cleanup code */
  ha = service_usage;
  while (ha) {
   item = (struct service_usage_item *)ha->value;

   if (!(module->status & status_enabled)) {
     item->provider = (struct lmodule **)setdel ((void **)item->provider, (void *)module);
     item->users = (struct lmodule **)setdel ((void **)item->users, (void *)module);
   }

   if (!item->provider && !item->users) {
//    service_usage = streedel (service_usage, ha);
    service_usage = streedel (ha);
    ha = service_usage;
   } else
    ha = streenext (ha);
  }
 } else if (task & service_is_required) {
  if (service_usage && (ha = streefind (service_usage, service, tree_find_first)) && (item = (struct service_usage_item *)ha->value) && (item->users))
   ret |= service_is_required;
 } else if (task & service_is_provided) {
  if (service_usage && (ha = streefind (service_usage, service, tree_find_first)) && (item = (struct service_usage_item *)ha->value) && (item->provider))
   ret |= service_is_provided;
 }

 emutex_unlock (&service_usage_mutex);
 return ret;
}
コード例 #11
0
ファイル: module.c プロジェクト: BackupTheBerlios/einit-svn
int mod (enum einit_module_task task, struct lmodule *module, char *custom_command) {
 struct einit_event *fb;
 unsigned int ret;

 if (!module) return 0;

/* wait if the module is already being processed in a different thread */
 if (!(task & einit_module_ignore_mutex)) {
  if ((task & einit_module_suspend) || (task & einit_module_resume)) {
   if (pthread_mutex_trylock (&module->mutex))
    return status_failed;
  } else
   emutex_lock (&module->mutex);
 }

 if (task & einit_module_suspend) {
  int retval = mod_suspend (module);

  if (!(task & einit_module_ignore_mutex))
   emutex_unlock (&module->mutex);

  return retval;
 }

 if (task & einit_module_resume) {
  int retval = mod_resume (module);

  if (!(task & einit_module_ignore_mutex))
   emutex_unlock (&module->mutex);

  return retval;
 }

 if (module->status & status_suspended) {
  if (!(mod_resume (module) == status_ok)) {
   if (!(task & einit_module_ignore_mutex))
    emutex_unlock (&module->mutex);

   return status_failed;
  }
 }

 if (task & einit_module_custom) {
  if (!custom_command) {
   if (!(task & einit_module_ignore_mutex))
    emutex_unlock (&module->mutex);

   return status_failed;
  }

  goto skipdependencies;
 }

 if (task & einit_module_ignore_dependencies) {
  notice (2, "module: skipping dependency-checks");
  task ^= einit_module_ignore_dependencies;
  goto skipdependencies;
 }

 if (module->status & MOD_LOCKED) { // this means the module is locked. maybe we're shutting down just now.
  if (!(task & einit_module_ignore_mutex))
   emutex_unlock (&module->mutex);

  if (task & einit_module_enable)
   return status_failed;
  else if (task & einit_module_disable)
   return status_ok;
  else
   return status_ok;
 }

 module->status |= status_working;

/* check if the task requested has already been done (or if it can be done at all) */
 if ((task & einit_module_enable) && (!module->enable || (module->status & status_enabled))) {
  wontload:
  module->status ^= status_working;
  if (!(task & einit_module_ignore_mutex))
   emutex_unlock (&module->mutex);
  return status_idle;
 }
 if ((task & einit_module_disable) && (!module->disable || (module->status & status_disabled) || (module->status == status_idle)))
  goto wontload;

 if (task & einit_module_enable) {
  if (!service_usage_query(service_requirements_met, module, NULL))
   goto wontload;
 } else if (task & einit_module_disable) {
  if (!service_usage_query(service_not_in_use, module, NULL))
   goto wontload;
 }

 skipdependencies:

/* inform everyone about what's going to happen */
 {
  struct einit_event eem = evstaticinit (einit_core_module_update);

  modules_work_count++;

  eem.task = task;
  eem.status = status_working;
  eem.para = (void *)module;
  eem.string = (module->module && module->module->rid) ? module->module->rid : module->si->provides[0];
  event_emit (&eem, einit_event_flag_broadcast);
  evstaticdestroy (eem);

/* same for services */
  if (module->si && module->si->provides) {
   struct einit_event ees = evstaticinit (einit_core_service_update);
   ees.task = task;
   ees.status = status_working;
   ees.string = (module->module && module->module->rid) ? module->module->rid : module->si->provides[0];
   ees.set = (void **)module->si->provides;
   ees.para = (void *)module;
   event_emit (&ees, einit_event_flag_broadcast);
   evstaticdestroy (ees);
  }
 }

/* actual loading bit */
 {
  fb = evinit (einit_feedback_module_status);
  fb->para = (void *)module;
  fb->task = task | einit_module_feedback_show;
  fb->status = status_working;
  fb->flag = 0;
  fb->string = NULL;
  fb->stringset = (char **)setadd ((void **)NULL, (module->module && module->module->rid) ? module->module->rid : module->si->provides[0], SET_TYPE_STRING);
  fb->integer = module->fbseq+1;
  status_update (fb);

  if (task & einit_module_custom) {
   if (strmatch (custom_command, "zap")) {
    char zerror = module->status & status_failed ? 1 : 0;
    fb->string = "module ZAP'd.";
    module->status = status_idle;
    module->status = status_disabled;
    if (zerror)
     module->status |= status_failed;
   } else if (module->custom) {
    module->status = module->custom(module->param, custom_command, fb);
   } else {
    module->status = (module->status & (status_enabled | status_disabled)) | status_failed | status_command_not_implemented;
   }
  } else if (task & einit_module_enable) {
    ret = module->enable (module->param, fb);
    if (ret & status_ok) {
     module->status = status_ok | status_enabled;
    } else {
     module->status = status_failed | status_disabled;
    }
  } else if (task & einit_module_disable) {
    ret = module->disable (module->param, fb);
    if (ret & status_ok) {
     module->status = status_ok | status_disabled;
    } else {
     module->status = status_failed | status_enabled;
    }
  }

  fb->status = module->status;
  module->fbseq = fb->integer + 1;

  status_update (fb);
//  event_emit(fb, einit_event_flag_broadcast);
//  if (fb->task & einit_module_feedback_show) fb->task ^= einit_module_feedback_show; fb->string = NULL;

/* module status update */
  {
   struct einit_event eem = evstaticinit (einit_core_module_update);
   eem.task = task;
   eem.status = fb->status;
   eem.para = (void *)module;
   eem.string = (module->module && module->module->rid) ? module->module->rid : module->si->provides[0];
   event_emit (&eem, einit_event_flag_broadcast);
   evstaticdestroy (eem);

/* service status update */
   if (module->si && module->si->provides) {
    struct einit_event ees = evstaticinit (einit_core_service_update);
    ees.task = task;
    ees.status = fb->status;
    ees.string = (module->module && module->module->rid) ? module->module->rid : module->si->provides[0];
    ees.set = (void **)module->si->provides;
    ees.para = (void *)module;
    event_emit (&ees, einit_event_flag_broadcast);
    evstaticdestroy (ees);
   }
  }

  free (fb->stringset);
  evdestroy (fb);

  service_usage_query(service_update, module, NULL);
  modules_work_count--;
 }

 if (!(task & einit_module_ignore_mutex))
  emutex_unlock (&module->mutex);

 return module->status;
}
コード例 #12
0
void einit_feedback_visual_fbsplash_boot_event_handler(struct einit_event *ev) {
/* preinit */
 if ((ev->type == einit_boot_devices_available) && !(coremode & einit_mode_ipconly)) {
  if (einit_initial_environment) {
/* check for kernel params */
   uint32_t i = 0;
   char start_splash = 0, *ttypatch = NULL, *splashargs = NULL;

   for (; einit_initial_environment[i]; i++) {
    if (strstr (einit_initial_environment[i], "splash=") == einit_initial_environment[i]) {
     start_splash = 1;

     splashargs = einit_initial_environment[i]+7;

     if (!ttypatch)
      ttypatch = "tty1";
    } else if ((strstr (einit_initial_environment[i], "console=") == einit_initial_environment[i]) ||
               (strstr (einit_initial_environment[i], "einitty=") == einit_initial_environment[i])) {

     ttypatch = einit_initial_environment[i]+8;
    }
   }

   if (splashargs && *splashargs) {
    char *fbtheme = NULL/*, *fbmode = NULL*/;

    if (splashargs) {
     char **p = str2set (',', splashargs);
     if (p) {
      for (i = 0; p[i]; i++) {
       char *sep = strchr (p[i], ':');
       if (sep) {
        *sep = 0;
        sep++;
        if (strmatch (p[i], "theme")) {
         fbtheme = estrdup (sep);
        }
       }/* else {
        fbmode = estrdup(p[i]);
       }*/
      }
      free (p);
     }
    }

    if (fbtheme) {
     struct cfgnode *node = cfg_getnode ("configuration-feedback-visual-fbsplash-theme", NULL);

     if (node && node->arbattrs) {
      uint32_t u = 0;
      for (; node->arbattrs[u]; u+=2) {
       if (strmatch(node->arbattrs[u], "s")) {
        notice (4, "patching fbsplash theme to %s", fbtheme);

        node->arbattrs[u+1] = fbtheme;
        node->svalue = fbtheme;
       }
      }
     }
    }
/*    if (fbmode) {
    }*/
   } else
    fbsplash_disabled = 1;

   if (ttypatch && *ttypatch) {
    struct cfgnode *node = cfg_getnode ("configuration-feedback-visual-std-io", NULL);
    /* patch console */
    if (node && node->arbattrs) {
     uint32_t ri = 0;

     for (; node->arbattrs[ri]; ri+=2) {
      if (strmatch (node->arbattrs[ri], "stdio")) {
       char tx[BUFFERSIZE];

       if (ttypatch[0] == '/')
        esprintf (tx, BUFFERSIZE, "%s", ttypatch);
       else
        esprintf (tx, BUFFERSIZE, "/dev/%s", ttypatch);

       notice (4, "patching stdio output to go to %s", tx);

       node->arbattrs[ri+1] = estrdup(tx);
      } else if (strmatch (node->arbattrs[ri], "activate-vt")) {
       notice (4, "removing activate-vt= instruction");

       node->arbattrs = (char **)setdel ((void **)node->arbattrs, node->arbattrs[ri]);
       node->arbattrs = (char **)setdel ((void **)node->arbattrs, node->arbattrs[ri]);
      }
     }
    }
   }

   if (start_splash) {
    struct einit_event ee = evstaticinit(einit_core_change_service_status);

    ee.argv = (char **)setadd ((void **)ee.set, "splashd", SET_TYPE_STRING);
    ee.argv = (char **)setadd ((void **)ee.set, "enable", SET_TYPE_STRING);

    event_emit (&ee, einit_event_flag_broadcast);

    evstaticdestroy(ee);

    notice (4, "enabling feedack (fbsplash)");
    einit_feedback_visual_fbsplash_enable();
   }
  }
 }
}
コード例 #13
0
void *linux_static_dev_hotplug(void *ignored) {
    struct sockaddr_nl nls;
    int fd, pos = 0;
    char buffer[BUFFERSIZE];

redo:

    memset(&nls, 0, sizeof(struct sockaddr_nl));
    nls.nl_family = AF_NETLINK;
    nls.nl_pid = getpid();
    nls.nl_groups = -1;

    fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

    if (fd == -1) goto done;

    if (bind(fd, (void *)&nls, sizeof(struct sockaddr_nl))) goto done;

    errno = 0;

    char **v = NULL;

    int newlength = NETLINK_BUFFER;

    if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &newlength, sizeof (int))) {
        perror ("setsockopt: can't increase buffer size");
    }

    if (fcntl (fd, F_SETFD, FD_CLOEXEC)) {
        perror ("can't set close-on-exec flag");
    }

    while (!errno || (errno == EAGAIN) || (errno == ESPIPE) || (errno == EINTR)) {
        int rp = read (fd, buffer + pos, BUFFERSIZE - pos);
        int i = 0;
        char last = rp < (BUFFERSIZE - pos);

        if ((rp == -1) && !(!errno || (errno == EAGAIN) || (errno == ESPIPE) || (errno == EINTR))) {
            perror ("static_dev/read");

            continue;
        }

        pos += rp;
        buffer[rp] = 0;

        for (i = 0; (i < pos); i++) {
            if (((buffer[i] == 0)) && (i > 0)) {
                char lbuffer[BUFFERSIZE];
                int offset = 0;

                for (offset = 0; (offset < i) && !buffer[offset]; offset++) {
                    offset++;
                }

                memcpy (lbuffer, buffer + offset, i - offset +1);
                if ((strstr (lbuffer, "add@") == lbuffer) ||
                        (strstr (lbuffer, "remove@") == lbuffer) ||
                        (strstr (lbuffer, "change@") == lbuffer) ||
                        (strstr (lbuffer, "online@") == lbuffer) ||
                        (strstr (lbuffer, "offline@") == lbuffer) ||
                        (strstr (lbuffer, "move@") == lbuffer)) {

                    if (v) {
                        linux_static_dev_hotplug_handle(v);

                        free (v);
                        v = NULL;
                    }
                }

                v = (char **)setadd ((void **)v, lbuffer, SET_TYPE_STRING);

                i++;

                memmove (buffer, buffer + offset + i, pos - i);
                pos -= i;

                i = -1;
            }
        }

        /* we got less than we requested, assume that was a last message */
        if (last) {
            if (v) {
                linux_static_dev_hotplug_handle(v);

                free (v);
                v = NULL;
            }
        }

        errno = 0;
    }

    if (v) {
        linux_static_dev_hotplug_handle(v);

        free (v);
        v = NULL;
    }

    close (fd);

    if (errno) {
        perror ("static_dev");
    }

    sleep (1);
    goto redo;

done:

    notice (1, "hotplug thread exiting... respawning in 10 sec");

    sleep (10);
    return linux_static_dev_hotplug (NULL);
}
コード例 #14
0
ファイル: cron.c プロジェクト: BackupTheBerlios/einit-svn
struct einit_cron_job *einit_cron_parse_attrs_to_cron_job (char **attributes) {
 if (!attributes) return NULL;

 struct einit_cron_job *cj = emalloc (sizeof (struct einit_cron_job));
 uint32_t i = 0;
 memset (cj, 0, sizeof (struct einit_cron_job));

 for (; attributes[i]; i+=2) {
  if (strmatch (attributes[i], "command")) {
   cj->command = estrdup(attributes[i+1]);
  } else if (strmatch (attributes[i], "id")) {
   cj->id = estrdup(attributes[i+1]);
  } else if (strmatch (attributes[i], "years") || strmatch (attributes[i], "year")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->years = (uintptr_t *)setadd ((void **)cj->years, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "months") || strmatch (attributes[i], "month")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->months = (uintptr_t *)setadd ((void **)cj->months, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "days") || strmatch (attributes[i], "day")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->days = (uintptr_t *)setadd ((void **)cj->days, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "hours") || strmatch (attributes[i], "hour")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->hours = (uintptr_t *)setadd ((void **)cj->hours, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "minutes") || strmatch (attributes[i], "minute")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->minutes = (uintptr_t *)setadd ((void **)cj->minutes, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "seconds") || strmatch (attributes[i], "second")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    uintptr_t num = parse_integer (x[j]);

    if (num) {
     cj->seconds = (uintptr_t *)setadd ((void **)cj->seconds, (void *)num, SET_NOALLOC);
	}
   }

   free (x);
  } else if (strmatch (attributes[i], "weekdays") || strmatch (attributes[i], "weekday")) {
   char **x = str2set (':', attributes[i+1]);
   uint32_t j = 0;

   for (; x[j]; j++) {
    if (strmatch (x[j], "sunday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)0, SET_NOALLOC);
	} else if (strmatch (x[j], "monday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)1, SET_NOALLOC);
	} else if (strmatch (x[j], "tuesday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)2, SET_NOALLOC);
	} else if (strmatch (x[j], "wednesday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)3, SET_NOALLOC);
	} else if (strmatch (x[j], "thursday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)4, SET_NOALLOC);
	} else if (strmatch (x[j], "friday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)5, SET_NOALLOC);
	} else if (strmatch (x[j], "saturday")) {
     cj->weekdays = (uintptr_t *)setadd ((void **)cj->weekdays, (void *)6, SET_NOALLOC);
	}
   }

   free (x);
  }
 }

 return cj;
}
コード例 #15
0
char *linux_bootchart_update_ps (char *ps, char *uptime) {
    DIR *d;
    struct dirent *e;
    char **data = NULL;

    d = opendir ("/proc");
    if (d != NULL) {
        while ((e = readdir (d))) {
            char *t, *u, *da = NULL;
            if (strmatch (e->d_name, ".") || strmatch (e->d_name, "..")) {
                continue;
            }

            if ((t = joinpath ("/proc/", e->d_name))) {
                if ((u = joinpath (t, "stat"))) {
                    struct stat st;
                    if (!stat (u, &st)) {
                        da = readfile (u);
                    }

                    free (u);
                }

                /*    if ((u = joinpath (t, "cmdline"))) {
                     struct stat st;
                     if (!stat (u, &st)) {
                      char *ru = readfile (u);

                      if (strstr (ru, )) {
                       linux_bootchart_have_thread = 0;
                      }
                     }

                     free (u);
                    }*/

                free (t);
            }

            if (da) {
                data = (char **)setadd ((void **)data, da, SET_TYPE_STRING);
                free (da);
                da = NULL;
            }
        }

        closedir(d);
    }

    if (data) {
        char *t = set2str ('\n', (const char **)data);

        if (t) {
            size_t len = strlen (uptime) + strlen (t) + 4 + (ps ? strlen (ps) : 0);
            char *tx = emalloc (len);

            if (ps) {
                esprintf (tx, len, "%s\n%s\n%s\n", ps, uptime, t);
                free (ps);
            } else {
                esprintf (tx, len, "%s\n%s\n", uptime, t);
            }

            free (t);

            ps = tx;
        }

        free (data);
    }

    return ps;
}
コード例 #16
0
ファイル: Manager.cpp プロジェクト: rockycao0/employee
Manager::Manager(int money, string name, int time, int add, int level): Employee(money, name, time, level) 
{
	setadd(add);
}
コード例 #17
0
int linux_kernel_modules_run (enum lkm_run_code code) {
 pthread_t **threads = NULL;

 if (code == lkm_pre_dev) {
  char dwait;
  char **modules = linux_kernel_modules_get_by_subsystem ("storage", &dwait);

  if (modules) {
   pthread_t *threadid = emalloc (sizeof (pthread_t));

   if (ethread_create (threadid, NULL, (void *(*)(void *))linux_kernel_modules_load, modules)) {
    linux_kernel_modules_load (modules);
   } else {
    if (dwait)
     threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
   }
  }
 } else if (code == lkm_post_dev) {
  struct stree *linux_kernel_modules_nodes = cfg_prefix(MPREFIX);
  char have_generic = 0;
  char have_audio = 0;

  if (linux_kernel_modules_nodes) {
   struct stree *cur = linux_kernel_modules_nodes;

   while (cur) {
    char *subsystem = cur->key + sizeof (MPREFIX) -1;
    struct cfgnode *nod = cur->value;

    if (nod && nod->arbattrs) {
     size_t i;
     for (i = 0; nod->arbattrs[i]; i+=2) {
      if (strmatch (nod->arbattrs[i], "provide-service") && parse_boolean (nod->arbattrs[i+1])) {
       goto nextgroup;
      }
     }
    }

    if (strmatch (subsystem, "storage")) {
    } else {
     struct cfgnode *node = cur->value;

     if (strmatch (subsystem, "generic") || strmatch (subsystem, "arbitrary")) {
      have_generic = 1;
     } else if (strmatch (subsystem, "alsa") || strmatch (subsystem, "audio") || strmatch (subsystem, "sound")) {
      have_audio = 1;
     }

     if (node && node->svalue) {
      char **modules = str2set (':', node->svalue);

      if (modules) {
       pthread_t *threadid = emalloc (sizeof (pthread_t));

       if (ethread_create (threadid, NULL, (void *(*)(void *))linux_kernel_modules_load, modules)) {
        linux_kernel_modules_load (modules);
       } else {
        if (!node->flag)
         threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
       }
      }
     }
    }

    nextgroup:

    cur = streenext (cur);
   }

   streefree (linux_kernel_modules_nodes);
  }

  if (!have_generic) {
   char dwait;
   char **modules = linux_kernel_modules_get_by_subsystem ("generic", &dwait);

   if (modules) {
    pthread_t *threadid = emalloc (sizeof (pthread_t));

    if (ethread_create (threadid, NULL, (void *(*)(void *))linux_kernel_modules_load, modules)) {
     linux_kernel_modules_load (modules);
    } else {
     if (dwait)
      threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
    }
   }
  }

  if (!have_audio) {
   char dwait;
   char **modules = linux_kernel_modules_get_by_subsystem ("audio", &dwait);

   if (modules) {
    pthread_t *threadid = emalloc (sizeof (pthread_t));

    if (ethread_create (threadid, NULL, (void *(*)(void *))linux_kernel_modules_load, modules)) {
     linux_kernel_modules_load (modules);
    } else {
     if (dwait)
      threads = (pthread_t **)setadd ((void **)threads, threadid, SET_NOALLOC);
    }
   }
  }
 }

 if (threads) {
  int i = 0;

  for (; threads[i]; i++) {
   pthread_join (*(threads[i]), NULL);

   free (threads[i]);
  }

  free (threads);
 }

 return status_ok;
}