<div dir="ltr">Hi,<div><br></div><div>comments inline...</div><div><br></div><div>attached is the modified file.</div><div>this also includes the fix for alias loading. There was an error in modprobe_main().</div><div><br>
</div><div>llist_pop() returns the struct ag_list*, whereas this was assigned to char*, which is modified</div><div>as below.</div><div><br></div><div><div>      char *real = ((struct arg_list*)llist_pop(&module->rnames))->arg;</div>
<div>      struct module_s *m2 = get_mod(real, 0);</div></div><div class="gmail_extra"><br>regards,</div><div class="gmail_extra">Ashwini</div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 18, 2013 at 5:03 AM,  <span dir="ltr"><<a href="mailto:ibid.ag@gmail.com" target="_blank">ibid.ag@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5">On Tue, Dec 17, 2013 at 04:39:39PM +0530, Ashwini Sharma wrote:<br>

> Hi List,<br>
><br>
> An implementation for modprobe is attached.<br>
> go thru the same and let me know your inputs.<br>
><br>
> regards,<br>
> Ashwini<br>
<br>
</div></div>For comments see below.<br>
No big issues with style that I can see, except that it should be<br>
default n until Rob's looked over it.<br>
At 575 lines, it's largeish, but it seems reasonable to me...<br>
except perhaps for use of modules.dep:<br>
<a href="http://lists.landley.net/pipermail/toybox-landley.net/2013-August/001294.html" target="_blank">http://lists.landley.net/pipermail/toybox-landley.net/2013-August/001294.html</a><br>
<a href="http://lists.landley.net/pipermail/toybox-landley.net/2013-August/001297.html" target="_blank">http://lists.landley.net/pipermail/toybox-landley.net/2013-August/001297.html</a><br>
<br>
<br>
> /* modprobe.c - modprobe utility.<br>
>  *<br>
>  * Copyright 2012 Madhur Verma <<a href="mailto:mad.flexi@gmail.com">mad.flexi@gmail.com</a>><br>
>  * Copyright 2013 Kyungwan Han <<a href="mailto:asura321@gmail.com">asura321@gmail.com</a>><br>
>  *<br>
>  * No Standard.<br>
><br>
> USE_MODPROBE(NEWTOY(modprobe, "alrqvsDb", TOYFLAG_SBIN))<br>
><br>
> config MODPROBE<br>
>   bool "modprobe"<br>
>   default y<br>
>   help<br>
>     usage: modprobe [-alrqvsDb] MODULE [symbol=value][...]<br>
><br>
>     modprobe utility - inserts modules and dependencies.<br>
><br>
>     -a  Load multiple MODULEs<br>
>     -l  List (MODULE is a pattern)<br>
>     -r  Remove MODULE (stacks) or do autoclean<br>
>     -q  Quiet<br>
>     -v  Verbose<br>
>     -s  Log to syslog<br>
>     -D  Show dependencies<br>
>     -b  Apply blacklist to module names too<br>
> */<br>
> #define FOR_modprobe<br>
> #include "toys.h"<br>
> #include <sys/syscall.h><br>
> #include <fnmatch.h><br>
><br>
> GLOBALS(<br>
>   struct arg_list *probes;<br>
>   struct arg_list *dbase[256];<br>
>   char *cmdopts;<br>
>   int nudeps;<br>
>   uint8_t symreq;<br>
> )<br>
><br>
> /* Note: if "#define DBASE_SIZE" modified,<br>
>  * Please update GLOBALS dbase[256] accordingly.<br>
>  */<br>
> #define DBASE_SIZE  256<br>
> #define MODNAME_LEN 256<br>
<br>
Any reason not to use sizeof(TT.dbase)?<br></blockquote><div><br></div><div>At some point I read a post about not to use _sizeof()_ in macro definitions.</div><div>but I feel it can be used here. :-)</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

><br>
> // Modules flag definations<br>
> #define MOD_ALOADED   0x0001<br>
> #define MOD_BLACKLIST 0x0002<br>
> #define MOD_FNDDEPMOD 0x0004<br>
> #define MOD_NDDEPS    0x0008<br>
<br>
I can see using the macros, but I seem to remember Rob mentioning somewhere<br>
before that defining things just before you need them can clarify the<br>
code a little.<br>
<br>
That would mean moving them just above config_action().<br></blockquote><div><br></div><div>I tend to keep macros at the top all together, if required to move it can be, trivial one to do. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<br>
> static void (*dbg)(char *format, ...);<br>
> // dummy interface for debugging.<br>
> static void dummy(char *format, ...)<br>
> {<br>
> }<br>
><br>
> // Current probing modules info<br>
> struct module_s {<br>
>   uint32_t flags;<br>
>   char *cmdname, *name, *depent, *opts;<br>
>   struct arg_list *rnames, *dep;<br>
> };<br>
><br>
> // Converts path name FILE to module name.<br>
> static char *path2mod(char *file, char *mod)<br>
> {<br>
>       int i;<br>
>       char *from, *lslash;<br>
><br>
>       if (!file) return NULL;<br>
>       if (!mod) mod = xmalloc(MODNAME_LEN);<br>
><br>
>   lslash = strrchr(file, '/');<br>
>   if (!lslash || (lslash == file && !lslash[1])) from = file;<br>
>   else from = lslash + 1;<br>
<br>
A home-made basename()?<br></blockquote><div><br></div><div>The man page for  basename() caused this definition here. the example at man says</div><div><div>        path         dirname    basename</div><div>       "/usr/lib"    "/usr"    "lib"</div>
<div>       "/usr/"       "/"       "usr"</div><div>       "usr"         "."       "usr"</div><div>       "/"           "/"       "/"</div>
<div>       "."           "."       "."</div><div>       ".."          "."       ".."</div></div><div>in this case we are interested in the string, if any, after the last '/'.</div>
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
>   for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)<br>
>               mod[i] = (from[i] == '-') ? '_' : from[i];<br>
>       mod[i] = '\0';<br>
>       return mod;<br>
> }<br>
I presume you are only using this part for display.<br>
modprobe dm_crypt or dm-crypt will load dm-crypt.ko<br>
modprobe micheal-mic or micheal_mic will load micheal_mic.ko<br>
Whatever you do, either gets displayed with an '_'<br>
<br>
> // locate character in string.<br>
> static char *strchr_nul(char *s, int c)<br>
> {<br>
>   while(*s != '\0' && *s != c) s++;<br>
>   return (char*)s;<br>
> }<br>
<br>
I'm guessing this is because strchrnul is a non-standard glibc<br>
extension?<br></blockquote><div>Yes, this is non-standard in glibc.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

I don't know about uclibc or newlib (if the latter is relevant),<br>
but musl does include it.<br>
$ nm /opt/musl/lib/libc.a |grep strchrnul<br>
         U __strchrnul<br>
         U __strchrnul<br>
strchrnul.o:<br>
00000000 T __strchrnul<br>
00000000 W strchrnul<br>
         U __strchrnul<br>
<br>
> // Add options in opts from toadd.<br>
> static char *add_opts(char *opts, char *toadd)<br>
> {<br>
>   if (toadd) {<br>
>     int optlen = 0;<br>
><br>
>     if (opts) optlen = strlen(opts);<br>
>     opts = xrealloc(opts, optlen + strlen(toadd) + 2);<br>
>     sprintf(opts + optlen, " %s", toadd);<br>
>   }<br>
>   return opts;<br>
> }<br>
><br>
> // Remove first element from the list and return it.<br>
> static void *llist_popme(struct arg_list **head)<br>
> {<br>
>   char *data = NULL;<br>
>   struct arg_list *temp = *head;<br>
><br>
>   if (temp) {<br>
>     data = temp->arg;<br>
>     *head = temp->next;<br>
>     free(temp);<br>
>   }<br>
>   return data;<br>
> }<br>
><br>
> // Add new node at the beginning of the list.<br>
> static void llist_add(struct arg_list **old, void *data)<br>
> {<br>
>   struct arg_list *new = xmalloc(sizeof(struct arg_list));<br>
><br>
>   new->arg = (char*)data;<br>
>   new->next = *old;<br>
>   *old = new;<br>
> }<br>
><br>
> // Add new node at tail of list.<br>
> static void llist_add_tail(struct arg_list **head, void *data)<br>
> {<br>
>   while (*head) head = &(*head)->next;<br>
>   *head = xzalloc(sizeof(struct arg_list));<br>
>   (*head)->arg = (char*)data;<br>
> }<br>
><br>
> // Reverse list order.<br>
> static struct arg_list *llist_rev(struct arg_list *list)<br>
> {<br>
>   struct arg_list *rev = NULL;<br>
><br>
>   while (list) {<br>
>     struct arg_list *next = list->next;<br>
><br>
>     list->next = rev;<br>
>     rev = list;<br>
>     list = next;<br>
>   }<br>
>   return rev;<br>
> }<br>
><br>
> /*<br>
>  * Returns struct module_s from the data base if found, NULL otherwise.<br>
>  * if ps - create module entry, add it to data base and return the same mod.<br>
>  */<br>
> static struct module_s *get_mod(char *mod, uint8_t ps)<br>
<br>
What on earth does "ps" indicate?<br>
"add" would make the function much clearer.<br></blockquote><div> </div><div>Agreed, modified var name from "ps" to "add". looking better.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<br>
> {<br>
>   char name[MODNAME_LEN];<br>
>   struct module_s *modentry;<br>
>   struct arg_list *temp;<br>
>   unsigned i, hash = 0;<br>
><br>
>   path2mod(mod, name);<br>
>   for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i];<br>
>   hash %= DBASE_SIZE;<br>
>   for (temp = TT.dbase[hash]; temp; temp = temp->next) {<br>
>     modentry = (struct module_s *) temp->arg;<br>
>     if (!strcmp(modentry->name, name)) return modentry;<br>
>   }<br>
>   if (!ps) return NULL;<br>
>   modentry = xzalloc(sizeof(*modentry));<br>
>   modentry->name = xstrdup(name);<br>
>   llist_add(&TT.dbase[hash], modentry);<br>
>   return modentry;<br>
> }<br>
><br>
> /*<br>
>  * Read a line from file with \ continuation and escape commented line.<br>
>  * Return the line in allocated string (*li)<br>
>  */<br>
> static int read_line(FILE *fl, char **li)<br>
> {<br>
>   char *nxtline = NULL, *line;<br>
>   int len, nxtlen, linelen, nxtlinelen;<br>
><br>
>   while (1) {<br>
>     line = NULL;<br>
>     linelen = nxtlinelen = 0;<br>
>     len = getline(&line, (size_t*)&linelen, fl);<br>
>     if (len <= 0) return len;<br>
>     // checking for commented lines.<br>
>     if (line[0] != '#') break;<br>
>     free(line);<br>
>   }<br>
>   for (;;) {<br>
>     if (line[len - 1] == '\n') len--;<br>
>     // checking line continuation.<br>
>     if (!len || line[len - 1] != '\\') break;<br>
>     len--;<br>
>     nxtlen = getline(&nxtline, (size_t*)&nxtlinelen, fl);<br>
<br>
EINVAL is the only documented error for getline(), but I'd expect it to<br>
also fail if ENOMEM (since getline uses malloc()/realloc()).<br>
Which suggests that (not currently existent) xgetline() should be used.</blockquote><div><br></div><div> get_rawline() in lib/lib.c is doing the things you are expecting.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
 </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
>     if (nxtlen <= 0) break;<br>
>     if (linelen < len + nxtlen + 1) {<br>
>       linelen = len + nxtlen + 1;<br>
>       line = xrealloc(line, linelen);<br>
>     }<br>
>     memcpy(&line[len], nxtline, nxtlen);<br>
>     len += nxtlen;<br>
>   }<br>
>   line[len] = '\0';<br>
>   *li = xstrdup(line);<br>
>   if (line) free(line);<br>
>   if (nxtline) free(nxtline);<br>
>   return len;<br>
> }<br>
><br>
> /*<br>
>  * Action to be taken on all config files in default directories<br>
>  * checks for aliases, options, install, remove and blacklist<br>
>  */<br>
> static int config_action(struct dirtree *node)<br>
> {<br>
>   FILE *fc;<br>
>   char *filename, *tokens[3], *line, *linecp;<br>
>   struct module_s *modent;<br>
>   int tcount = 0;<br>
><br>
>   if (!dirtree_notdotdot(node)) return 0;<br>
>   if (S_ISDIR(node->st.st_mode)) return DIRTREE_RECURSE;<br>
><br>
>   if (!S_ISREG(node->st.st_mode)) return 0; // process only regular file<br>
>   filename = dirtree_path(node, NULL);<br>
>   if (!(fc = fopen(filename, "r"))) {<br>
>     free(filename);<br>
>     return 0;<br>
>   }<br>
>   for (line = linecp = NULL; read_line(fc, &line) > 0;<br>
>       free(line), free(linecp), line = linecp = NULL) {<br>
>     char *tk = NULL;<br>
><br>
>     if (!strlen(line)) continue;<br>
>     linecp = xstrdup(line);<br>
>     for (tk = strtok(linecp, "# \t"), tcount = 0; tk;<br>
>         tk = strtok(NULL, "# \t"), tcount++) {<br>
>       tokens[tcount] = tk;<br>
>       if (tcount == 2) {<br>
>         tokens[2] = line + strlen(tokens[0]) + strlen(tokens[1]) + 2;<br>
>         break;<br>
>       }<br>
>     }<br>
>     if (!tk) continue;<br>
>     // process the tokens[0] contains first word of config line.<br>
>     if (!strcmp(tokens[0], "alias")) {<br>
>       struct arg_list *temp;<br>
>       char aliase[MODNAME_LEN], *realname;<br>
><br>
>       if (!tokens[2]) continue;<br>
>       path2mod(tokens[1], aliase);<br>
>       for (temp = TT.probes; temp; temp = temp->next) {<br>
>         modent = (struct module_s *) temp->arg;<br>
>         if (fnmatch(aliase, modent->name, 0)) continue;<br>
>         realname = path2mod(tokens[2], NULL);<br>
>         llist_add(&modent->rnames, realname);<br>
>         if (modent->flags & MOD_NDDEPS) {<br>
>           modent->flags &= ~MOD_NDDEPS;<br>
>           TT.nudeps--;<br>
>         }<br>
>         modent = get_mod(realname, 1);<br>
>         if (!(modent->flags & MOD_NDDEPS)) {<br>
>           modent->flags |= MOD_NDDEPS;<br>
>           TT.nudeps++;<br>
>         }<br>
>       }<br>
>     } else if (!strcmp(tokens[0], "options")) {<br>
>       if (!tokens[2]) continue;<br>
>       modent = get_mod(tokens[1], 1);<br>
>       modent->opts = add_opts(modent->opts, tokens[2]);<br>
>     } else if (!strcmp(tokens[0], "include"))<br>
>       dirtree_read(tokens[1], config_action);<br>
>     else if (!strcmp(tokens[0], "blacklist"))<br>
>       get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;<br>
>     else if (!strcmp(tokens[0], "install")) continue;<br>
>     else if (!strcmp(tokens[0], "remove")) continue;<br>
>     else error_msg("Invalid option %s found in file %s", tokens[0], filename);<br>
>   }<br>
>   fclose(fc);<br>
>   free(filename);<br>
>   return 0;<br>
> }<br>
><br>
> // Show matched modules else return -1 on failure.<br>
> static int depmode_read_entry(char *cmdname)<br>
> {<br>
>   char *line;<br>
>   int ret = -1;<br>
>   FILE *fe = xfopen("modules.dep", "r");<br>
><br>
>   while (read_line(fe, &line) > 0) {<br>
>     char *tmp = strchr(line, ':');<br>
><br>
>     if (tmp) {<br>
>       *tmp = '\0';<br>
>      char *name = basename(line);<br>
><br>
>       tmp = strchr(name, '.');<br>
>       if (tmp) *tmp = '\0';<br>
>       if (!cmdname) {<br>
>         if (tmp) *tmp = '.';<br>
>         xprintf("%s\n", line);<br>
>         ret = 0;<br>
>       } else if (!fnmatch(cmdname, name, 0)) {<br>
>         if (tmp) *tmp = '.';<br>
>         xprintf("%s\n", line);<br>
>         ret = 0;<br>
>       }<br>
>     }<br>
>     free(line);<br>
>   }<br>
>   return ret;<br>
> }<br>
><br>
> // Finds dependencies for modules from the modules.dep file.<br>
See comment at the top about using modules.dep.<br>
I suppose if the goal were to keep from duplicating the guts of nm and<br>
running that for every module, that might be a sensible reason...<br></blockquote><div><br></div><div>As all the information is at one place for a module in modules.dep, why keep recursing throu all the </div><div>modules and directories again. Just reusing the work done already.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
> static void find_dep(void)<br>
> {<br>
>   char *line = NULL;<br>
>   struct module_s *mod;<br>
>   FILE *fe = xfopen("modules.dep", "r");<br>
><br>
>   for (; read_line(fe, &line) > 0; free(line)) {<br>
>     char *tmp = strchr(line, ':');<br>
><br>
>     if (tmp) {<br>
>       *tmp = '\0';<br>
>       mod = get_mod(line, 0);<br>
>       if (!mod) continue;<br>
>       if ((mod->flags & MOD_ALOADED) &&<br>
>           !(toys.optflags & (FLAG_r | FLAG_D))) continue;<br>
><br>
>       mod->flags |= MOD_FNDDEPMOD;<br>
>       if ((mod->flags & MOD_NDDEPS) && (!mod->dep)) {<br>
>         TT.nudeps--;<br>
>         llist_add(&mod->dep, xstrdup(line));<br>
>         tmp++;<br>
>         if (*tmp) {<br>
>           char *tok;<br>
><br>
>           while ((tok = strsep(&tmp, " \t"))) {<br>
>             if (!*tok) continue;<br>
>             llist_add_tail(&mod->dep, xstrdup(tok));<br>
>           }<br>
>         }<br>
>       }<br>
>     }<br>
>   }<br>
>   fclose(fe);<br>
> }<br>
><br>
> // Remove a module from the Linux Kernel. if !modules does auto remove.<br>
> static int rm_mod(char *modules, uint32_t flags)<br>
> {<br>
>   errno = 0;<br>
>   if (modules) {<br>
>     int len = strlen(modules);<br>
><br>
>     if (len > 3 && !strcmp(&modules[len-3], ".ko" )) modules[len-3] = 0;<br>
>   }<br>
>   if (!flags) flags = O_NONBLOCK|O_EXCL;<br>
>   syscall(__NR_delete_module, modules, flags);<br>
>   return errno;<br>
> }<br>
><br>
> // Insert module same as insmod implementation.<br>
If it's the same as insmod, it should be shared with insmod.<br>
That said, I can see an initial version duplicating it.<br></blockquote><div><br></div><div>It is same as insmod.  Did not want to modify multiple files at the same time.</div><div>Can factor this out, once modprobe is in tree.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
> static int ins_mod(char *modules, char *flags)<br>
> {<br>
>   char *buf = NULL;<br>
>   int len, res;<br>
>   int fd = xopen(modules, O_RDONLY);<br>
><br>
>   len = fdlength(fd);<br>
>   buf = xmalloc(len);<br>
>   xreadall(fd, buf, len);<br>
>   xclose(fd);<br>
><br>
>   while (flags && strlen(toybuf) + strlen(flags) + 2 < sizeof(toybuf)) {<br>
>     strcat(toybuf, flags);<br>
>     strcat(toybuf, " ");<br>
>   }<br>
>   res = syscall(__NR_init_module, buf, len, toybuf);<br>
>   if (CFG_TOYBOX_FREE && buf != toybuf) free(buf);<br>
>   if (res) perror_exit("failed to load %s ", toys.optargs[0]);<br>
>   return res;<br>
> }<br>
><br>
> // Add module in probes list, if not loaded.<br>
> static void add_mod(char *name)<br>
> {<br>
>   struct module_s *mod = get_mod(name, 1);<br>
><br>
>   if (!(toys.optflags & (FLAG_r | FLAG_D)) && (mod->flags & MOD_ALOADED)) {<br>
>     dbg("skipping %s, it is already loaded\n", name);<br>
>     return;<br>
>   }<br>
>   dbg("queuing %s\n", name);<br>
>   mod->cmdname = name;<br>
>   mod->flags |= MOD_NDDEPS;<br>
>   llist_add_tail(&TT.probes, mod);<br>
>   TT.nudeps++;<br>
>   if (!strncmp(mod->name, "symbol:", 7)) TT.symreq = 1;<br>
> }<br>
><br>
> // Parse cmdline options suplied for module.<br>
> static char *add_cmdopt(char **argv)<br>
> {<br>
>   char *opt = xzalloc(1);<br>
>   int lopt = 0;<br>
><br>
>   while (*++argv) {<br>
>     char *fmt, *var, *val;<br>
><br>
>     var = *argv;<br>
>     opt = xrealloc(opt, lopt + 2 + strlen(var) + 2);<br>
>     // check for key=val or key = val.<br>
>     fmt = "%.*s%s ";<br>
>     val = strchr_nul(var, '=');<br>
>     if (*val) {<br>
>       val++;<br>
>       if (strchr(val, ' ')) fmt = "%.*s\"%s\" ";<br>
>     }<br>
>     lopt += sprintf(opt + lopt, fmt, (int) (val - var), var, val);<br>
>   }<br>
>   return opt;<br>
> }<br>
><br>
> // Probes a single module and loads all its dependencies.<br>
> static int go_probe(struct module_s *m)<br>
> {<br>
>   int rc = 0, first = 1;<br>
><br>
>   if (!(m->flags & MOD_FNDDEPMOD)) {<br>
>     if (!(toys.optflags & FLAG_s))<br>
>       error_msg("module %s not found in modules.dep", m->name);<br>
>     return -ENOENT;<br>
>   }<br>
>   dbg("go_prob'ing %s\n", m->name);<br>
>   if (!(toys.optflags & FLAG_r)) m->dep = llist_rev(m->dep);<br>
><br>
>   while (m->dep) {<br>
>     struct module_s *m2;<br>
>     char *fn, *options;<br>
><br>
>     rc = 0;<br>
>     fn = llist_popme(&m->dep);<br>
>     m2 = get_mod(fn, 1);<br>
>     // are we removing ?<br>
>     if (toys.optflags & FLAG_r) {<br>
>       if (m2->flags & MOD_ALOADED) {<br>
>         if ((rc = rm_mod(m2->name, O_EXCL))) {<br>
>           if (first) {<br>
>             perror_msg("can't unload module %s", m2->name);<br>
>             break;<br>
>           }<br>
>         } else m2->flags &= ~MOD_ALOADED;<br>
>       }<br>
>       first = 0;<br>
>       continue;<br>
>     }<br>
>     options = m2->opts;<br>
>     m2->opts = NULL;<br>
>     if (m == m2) options = add_opts(options, TT.cmdopts);<br>
><br>
>     // are we only checking dependencies ?<br>
>     if (toys.optflags & FLAG_D) {<br>
>       dbg(options ? "insmod %s %s\n" : "insmod %s\n", fn, options);<br>
>       if (options) free(options);<br>
>       continue;<br>
>     }<br>
>     if (m2->flags & MOD_ALOADED) {<br>
>       dbg("%s is already loaded, skipping\n", fn);<br>
>       if (options) free(options);<br>
>       continue;<br>
>     }<br>
>     // none of above is true insert the module.<br>
>     rc = ins_mod(fn, options);<br>
>     dbg("loaded %s '%s', rc:%d\n", fn, options, rc);<br>
>     if (rc == EEXIST) rc = 0;<br>
>     if (options) free(options);<br>
>     if (rc) {<br>
>       perror_msg("can't load module %s (%s)", m2->name, fn);<br>
>       break;<br>
>     }<br>
>     m2->flags |= MOD_ALOADED;<br>
>   }<br>
>   return rc;<br>
> }<br>
><br>
> void modprobe_main(void)<br>
> {<br>
>   struct utsname uts;<br>
>   char **argv = toys.optargs, *procline = NULL;<br>
>   FILE *fs;<br>
>   struct module_s *module;<br>
>   unsigned flags = toys.optflags;<br>
><br>
>   dbg = dummy;<br>
>   if (flags & FLAG_v) dbg = xprintf;<br>
><br>
>   if ((toys.optc < 1) && (((flags & FLAG_r) && (flags & FLAG_l))<br>
>         ||(!((flags & FLAG_r)||(flags & FLAG_l))))) {<br>
>         toys.exithelp++;<br>
>         error_exit(" Syntex Error.");<br>
>   }<br>
>   // Check for -r flag without arg if yes then do auto remove.<br>
>   if ((flags & FLAG_r) && (!toys.optc)) {<br>
>     if (rm_mod(NULL, O_NONBLOCK | O_EXCL) != 0)       perror_exit("rmmod");<br>
>     return;<br>
>   }<br>
><br>
>   // change directory to /lib/modules/<release>/<br>
>   xchdir("/lib/modules");<br>
>   uname(&uts);<br>
>   xchdir(uts.release);<br>
><br>
>   // modules.dep processing for dependency check.<br>
>   if (flags & FLAG_l) {<br>
>     if (depmode_read_entry(toys.optargs[0])) error_exit("no module found.");<br>
>     return;<br>
>   }<br>
>   // Read /proc/modules to get loadded modules.<br>
>   fs = xfopen("/proc/modules", "r");<br>
><br>
>   while (read_line(fs, &procline) > 0) {<br>
>     *(strchr(procline, ' ')) = '\0';<br>
>     get_mod(procline, 1)->flags = MOD_ALOADED;<br>
>     free(procline);<br>
>     procline = NULL;<br>
>   }<br>
>   fclose(fs);<br>
>   if ((flags & FLAG_a) || (flags & FLAG_r)) {<br>
>     do {<br>
>       add_mod(*argv++);<br>
>     } while (*argv);<br>
>   } else {<br>
>     add_mod(argv[0]);<br>
>     TT.cmdopts = add_cmdopt(argv);<br>
>   }<br>
>   if (!TT.probes) {<br>
>     fprintf(stderr, "All modules loaded successfully. \n");<br>
>     return;<br>
>   }<br>
>   dirtree_read("/etc/modprobe.conf", config_action);<br>
>   dirtree_read("/etc/modprobe.d", config_action);<br>
>   if (TT.symreq) dirtree_read("modules.symbols", config_action);<br>
>   if (TT.nudeps) dirtree_read("modules.alias", config_action);<br>
>   find_dep();<br>
>   while ((module = llist_popme(&TT.probes))) {<br>
>     if (!module->rnames) {<br>
>       dbg("probing by module name\n");<br>
>       /* This is not an alias. Literal names are blacklisted<br>
>        * only if '-b' is given.<br>
>        */<br>
>       if (!(flags & FLAG_b) || !(module->flags & MOD_BLACKLIST))<br>
>         go_probe(module);<br>
>       continue;<br>
>     }<br>
>     do { // Probe all real names for the alias.<br>
>       char *real = llist_pop(&module->rnames);<br>
>       struct module_s *m2 = get_mod(real, 0);<br>
><br>
>       dbg("probing alias %s by realname %s\n", module->name, real);<br>
>       if (!m2) continue;<br>
>       if (!(m2->flags & MOD_BLACKLIST)<br>
>           && (!(m2->flags & MOD_ALOADED) || (flags & (FLAG_r | FLAG_D))))<br>
>         go_probe(m2);<br>
>       free(real);<br>
>     } while (module->rnames);<br>
>   }<br>
> }<br>
<br>
> _______________________________________________<br>
> Toybox mailing list<br>
> <a href="mailto:Toybox@lists.landley.net">Toybox@lists.landley.net</a><br>
> <a href="http://lists.landley.net/listinfo.cgi/toybox-landley.net" target="_blank">http://lists.landley.net/listinfo.cgi/toybox-landley.net</a><br>
<br>
_______________________________________________<br>
Toybox mailing list<br>
<a href="mailto:Toybox@lists.landley.net">Toybox@lists.landley.net</a><br>
<a href="http://lists.landley.net/listinfo.cgi/toybox-landley.net" target="_blank">http://lists.landley.net/listinfo.cgi/toybox-landley.net</a><br>
</blockquote></div><br></div></div>