~registry/kmod/master

« back to all changes in this revision

Viewing changes to tools/kmod-modprobe.c

  • Committer: Lucas De Marchi
  • Date: 2011-12-12 12:30:01 UTC
  • mfrom: (161.1.30)
  • Revision ID: git-v1:2fee2f13ce5f6b17dd672389de422217c56105e2
Merge branch 'use-mmap'

Conflicts:
        libkmod/libkmod.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * kmod-modprob - manage linux kernel modules using libkmod.
 
3
 *
 
4
 * Copyright (C) 2011  ProFUSION embedded systems
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation version 2.1.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
#include <stdio.h>
 
20
#include <stdlib.h>
 
21
#include <getopt.h>
 
22
#include <errno.h>
 
23
#include <string.h>
 
24
#include <sys/types.h>
 
25
#include <sys/stat.h>
 
26
#include <sys/utsname.h>
 
27
#include <unistd.h>
 
28
#include <syslog.h>
 
29
#include <limits.h>
 
30
 
 
31
#include "libkmod.h"
 
32
 
 
33
static int log_priority = LOG_CRIT;
 
34
static int use_syslog = 0;
 
35
 
 
36
#define DEFAULT_VERBOSE LOG_WARNING
 
37
static int verbose = DEFAULT_VERBOSE;
 
38
static int dry_run = 0;
 
39
static int ignore_loaded = 0;
 
40
static int show_resolved_aliases = 0;
 
41
static int first_time = 0;
 
42
static int ignore_commands = 0;
 
43
static int use_blacklist = 0;
 
44
static int force = 0;
 
45
static int strip_modversion = 0;
 
46
static int strip_vermagic = 0;
 
47
static int remove_dependencies = 0;
 
48
 
 
49
static const char cmdopts_s[] = "arRibft:lDcnC:d:S:sqvVh";
 
50
static const struct option cmdopts[] = {
 
51
        {"all", no_argument, 0, 'a'},
 
52
        {"remove", no_argument, 0, 'r'},
 
53
        {"remove-dependencies", no_argument, 0, 5},
 
54
        {"resolve-alias", no_argument, 0, 'R'},
 
55
        {"first-time", no_argument, 0, 3},
 
56
        {"ignore-install", no_argument, 0, 'i'},
 
57
        {"ignore-remove", no_argument, 0, 'i'},
 
58
        {"use-blacklist", no_argument, 0, 'b'},
 
59
        {"force", no_argument, 0, 'f'},
 
60
        {"force-modversion", no_argument, 0, 2},
 
61
        {"force-vermagic", no_argument, 0, 1},
 
62
 
 
63
        {"type", required_argument, 0, 't'},
 
64
        {"list", no_argument, 0, 'l'},
 
65
        {"show-depends", no_argument, 0, 'D'},
 
66
        {"showconfig", no_argument, 0, 'c'},
 
67
        {"show-config", no_argument, 0, 'c'},
 
68
        {"show-modversions", no_argument, 0, 4},
 
69
        {"dump-modversions", no_argument, 0, 4},
 
70
 
 
71
        {"dry-run", no_argument, 0, 'n'},
 
72
        {"show", no_argument, 0, 'n'},
 
73
 
 
74
        {"config", required_argument, 0, 'C'},
 
75
        {"dirname", required_argument, 0, 'd'},
 
76
        {"set-version", required_argument, 0, 'S'},
 
77
 
 
78
        {"syslog", no_argument, 0, 's'},
 
79
        {"quiet", no_argument, 0, 'q'},
 
80
        {"verbose", no_argument, 0, 'v'},
 
81
        {"version", no_argument, 0, 'V'},
 
82
        {"help", no_argument, 0, 'h'},
 
83
        {NULL, 0, 0, 0}
 
84
};
 
85
 
 
86
static void help(const char *progname)
 
87
{
 
88
        fprintf(stderr,
 
89
                "Usage:\n"
 
90
                "\t%s [options] [-i] [-b] modulename\n"
 
91
                "\t%s [options] -a [-i] [-b] modulename [modulename...]\n"
 
92
                "\t%s [options] -r [-i] modulename\n"
 
93
                "\t%s [options] -r -a [-i] modulename [modulename...]\n"
 
94
                "\t%s [options] -l [-t dirname] [wildcard]\n"
 
95
                "\t%s [options] -c\n"
 
96
                "\t%s [options] --dump-modversions filename\n"
 
97
                "Management Options:\n"
 
98
                "\t-a, --all                   \n"
 
99
                "\t-r, --remove                \n"
 
100
                "\t    --remove-dependencies   \n"
 
101
                "\t-R, --resolve-alias         \n"
 
102
                "\t    --first-time            \n"
 
103
                "\t-i, --ignore-install        \n"
 
104
                "\t-i, --ignore-remove         \n"
 
105
                "\t-b, --use-blacklist         \n"
 
106
                "\t-f, --force                 \n"
 
107
                "\t    --force-modversion      \n"
 
108
                "\t    --force-vermagic        \n"
 
109
                "\n"
 
110
                "Query Options:\n"
 
111
                "\t-t, --type=DIR              \n"
 
112
                "\t-l, --list                  \n"
 
113
                "\t-D, --show-depends          \n"
 
114
                "\t-c, --showconfig            \n"
 
115
                "\t-c, --show-config           \n"
 
116
                "\t    --show-modversions      \n"
 
117
                "\t    --dump-modversions      \n"
 
118
                "\n"
 
119
                "General Options:\n"
 
120
                "\t-n, --dry-run               \n"
 
121
                "\t-n, --show                  \n"
 
122
 
 
123
                "\t-C, --config=FILE           \n"
 
124
                "\t-d, --dirname=DIR           \n"
 
125
                "\t-S, --set-version=VERSION   \n"
 
126
 
 
127
                "\t-s, --syslog                print to syslog, not stderr\n"
 
128
                "\t-q, --quiet                 disable messages\n"
 
129
                "\t-v, --verbose               enables more messages\n"
 
130
                "\t-V, --version               show version\n"
 
131
                "\t-h, --help                  show this help\n",
 
132
                progname, progname, progname, progname, progname, progname,
 
133
                progname);
 
134
}
 
135
 
 
136
static inline void _show(const char *fmt, ...)
 
137
{
 
138
        va_list args;
 
139
 
 
140
        if (verbose <= DEFAULT_VERBOSE)
 
141
                return;
 
142
 
 
143
        va_start(args, fmt);
 
144
        vfprintf(stdout, fmt, args);
 
145
        fflush(stdout);
 
146
        va_end(args);
 
147
}
 
148
 
 
149
static inline void _log(int prio, const char *fmt, ...)
 
150
{
 
151
        const char *prioname;
 
152
        char buf[32], *msg;
 
153
        va_list args;
 
154
 
 
155
        if (prio > verbose)
 
156
                return;
 
157
 
 
158
        va_start(args, fmt);
 
159
        if (vasprintf(&msg, fmt, args) < 0)
 
160
                msg = NULL;
 
161
        va_end(args);
 
162
        if (msg == NULL)
 
163
                return;
 
164
 
 
165
        switch (prio) {
 
166
        case LOG_CRIT:
 
167
                prioname = "FATAL";
 
168
                break;
 
169
        case LOG_ERR:
 
170
                prioname = "ERROR";
 
171
                break;
 
172
        case LOG_WARNING:
 
173
                prioname = "WARNING";
 
174
                break;
 
175
        case LOG_NOTICE:
 
176
                prioname = "NOTICE";
 
177
                break;
 
178
        case LOG_INFO:
 
179
                prioname = "INFO";
 
180
                break;
 
181
        case LOG_DEBUG:
 
182
                prioname = "DEBUG";
 
183
                break;
 
184
        default:
 
185
                snprintf(buf, sizeof(buf), "LOG-%03d", prio);
 
186
                prioname = buf;
 
187
        }
 
188
 
 
189
        if (use_syslog)
 
190
                syslog(LOG_NOTICE, "%s: %s", prioname, msg);
 
191
        else
 
192
                fprintf(stderr, "%s: %s", prioname, msg);
 
193
        free(msg);
 
194
 
 
195
        if (prio <= LOG_CRIT)
 
196
                exit(EXIT_FAILURE);
 
197
}
 
198
#define ERR(...) _log(LOG_ERR, __VA_ARGS__)
 
199
#define WRN(...) _log(LOG_WARNING, __VA_ARGS__)
 
200
#define INF(...) _log(LOG_INFO, __VA_ARGS__)
 
201
#define DBG(...) _log(LOG_DEBUG, __VA_ARGS__)
 
202
#define LOG(...) _log(log_priority, __VA_ARGS__)
 
203
#define SHOW(...) _show(__VA_ARGS__)
 
204
 
 
205
static int show_list(struct kmod_ctx *ctx, const char *list_type, const char *pattern)
 
206
{
 
207
        ERR("TODO - list is missing in kmod.\n");
 
208
        /*
 
209
          needs:
 
210
            struct kmod_list *kmod_get_dependencies(struct kmod_ctx *ctx);
 
211
            kmod_dependency_get_name()
 
212
            kmod_dependency_get_dependencies()
 
213
            kmod_dependency_unref_list()
 
214
        */
 
215
        return -ENOENT;
 
216
}
 
217
 
 
218
static int show_config(struct kmod_ctx *ctx)
 
219
{
 
220
        ERR("TODO - config is missing in kmod.\n");
 
221
        /*
 
222
          needs:
 
223
            struct kmod_list *kmod_get_config(struct kmod_ctx *ctx);
 
224
            kmod_config_get_type() {alias,options,blacklist,install,remove,softdeps}
 
225
            kmod_config_get_key()
 
226
            kmod_config_get_value()
 
227
            kmod_config_unref_list()
 
228
        */
 
229
        return -ENOENT;
 
230
}
 
231
 
 
232
static int show_modversions(struct kmod_ctx *ctx, const char *filename)
 
233
{
 
234
        ERR("TODO - modversions is missing in kmod.\n");
 
235
        /*
 
236
          needs:
 
237
            struct kmod_list *kmod_module_get_modversions(struct kmod_module *mod);
 
238
            kmod_module_modversion_get_address() [needs better naming?]
 
239
            kmod_module_modversion_get_name() [needs better naming?]
 
240
            kmod_module_modversion_unref_list()
 
241
         */
 
242
        return -ENOENT;
 
243
}
 
244
 
 
245
static int command_do(struct kmod_module *module, const char *type, const char *command, const char *cmdline_opts)
 
246
{
 
247
        const char *modname = kmod_module_get_name(module);
 
248
        char *p, *cmd = NULL;
 
249
        size_t cmdlen, cmdline_opts_len, varlen;
 
250
        int ret = 0;
 
251
 
 
252
        if (cmdline_opts == NULL)
 
253
                cmdline_opts = "";
 
254
        cmdline_opts_len = strlen(cmdline_opts);
 
255
 
 
256
        cmd = strdup(command);
 
257
        if (cmd == NULL)
 
258
                return -ENOMEM;
 
259
        cmdlen = strlen(cmd);
 
260
        varlen = sizeof("$CMDLINE_OPTS") - 1;
 
261
        while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
 
262
                size_t prefixlen = p - cmd;
 
263
                size_t suffixlen = cmdlen - prefixlen - varlen;
 
264
                size_t slen = cmdlen - varlen + cmdline_opts_len;
 
265
                char *suffix = p + varlen;
 
266
                char *s = malloc(slen + 1);
 
267
                if (s == NULL) {
 
268
                        free(cmd);
 
269
                        return -ENOMEM;
 
270
                }
 
271
                memcpy(s, cmd, p - cmd);
 
272
                memcpy(s + prefixlen, cmdline_opts, cmdline_opts_len);
 
273
                memcpy(s + prefixlen + cmdline_opts_len, suffix, suffixlen);
 
274
                s[slen] = '\0';
 
275
 
 
276
                free(cmd);
 
277
                cmd = s;
 
278
                cmdlen = slen;
 
279
        }
 
280
 
 
281
        SHOW("%s %s\n", type, cmd);
 
282
        if (dry_run)
 
283
                goto end;
 
284
 
 
285
        setenv("MODPROBE_MODULE", modname, 1);
 
286
        ret = system(cmd);
 
287
        unsetenv("MODPROBE_MODULE");
 
288
        if (ret == -1 || WEXITSTATUS(ret)) {
 
289
                LOG("Error running %s command for %s\n", type, modname);
 
290
                if (ret != -1)
 
291
                        ret = -WEXITSTATUS(ret);
 
292
        }
 
293
 
 
294
end:
 
295
        free(cmd);
 
296
        return ret;
 
297
}
 
298
 
 
299
static int rmmod_do_soft_dependencies(struct kmod_module *mod)
 
300
{
 
301
        ERR("TODO - implement soft dependencies!\n");
 
302
        /* remember to reverse soft dependencies! */
 
303
        return 0;
 
304
}
 
305
 
 
306
static int rmmod_do_dependencies(struct kmod_module *parent)
 
307
{
 
308
        int err = 0;
 
309
        struct kmod_list *d, *deps = kmod_module_get_holders(parent);
 
310
        kmod_list_foreach(d, deps) {
 
311
                struct kmod_module *dm = kmod_module_get_module(d);
 
312
                const char *cmd, *dmname = kmod_module_get_name(dm);
 
313
                int r;
 
314
 
 
315
                r = rmmod_do_dependencies(dm);
 
316
                if (r < 0) {
 
317
                        WRN("could not remove dependencies of '%s': %s\n",
 
318
                            dmname, strerror(-r));
 
319
                        goto dep_error;
 
320
                }
 
321
 
 
322
                if (!ignore_loaded) {
 
323
                        int state = kmod_module_get_initstate(dm);
 
324
                        if (state != KMOD_MODULE_LIVE &&
 
325
                                        state != KMOD_MODULE_COMING)
 
326
                                goto dep_done;
 
327
                }
 
328
 
 
329
                r = rmmod_do_soft_dependencies(dm);
 
330
                if (r < 0) {
 
331
                        WRN("could not remove soft dependencies of '%s': %s\n",
 
332
                            dmname, strerror(-r));
 
333
                        goto dep_error;
 
334
                }
 
335
 
 
336
                cmd = kmod_module_get_remove_commands(dm);
 
337
                if (cmd) {
 
338
                        r = command_do(dm, "remove", cmd, NULL);
 
339
                        if (r < 0) {
 
340
                                WRN("failed to execute remove command of '%s': "
 
341
                                    "%s\n", dmname, strerror(-r));
 
342
                                goto dep_error;
 
343
                        } else
 
344
                                goto dep_done;
 
345
                }
 
346
 
 
347
                r = kmod_module_get_refcnt(dm);
 
348
                if (r < 0) {
 
349
                        WRN("could not get module '%s' refcnt: %s\n",
 
350
                            dmname, strerror(-r));
 
351
                        goto dep_error;
 
352
                } else if (r > 0 && !ignore_loaded) {
 
353
                        LOG("Module %s is in use.\n", dmname);
 
354
                        r = -EBUSY;
 
355
                        goto dep_error;
 
356
                }
 
357
 
 
358
                SHOW("rmmod %s\n", dmname);
 
359
 
 
360
                if (!dry_run) {
 
361
                        r = kmod_module_remove_module(dm, 0);
 
362
                        if (r < 0) {
 
363
                                WRN("could not remove '%s': %s\n",
 
364
                                    dmname, strerror(-r));
 
365
                                goto dep_error;
 
366
                        }
 
367
                }
 
368
 
 
369
        dep_done:
 
370
                kmod_module_unref(dm);
 
371
                continue;
 
372
        dep_error:
 
373
                err = r;
 
374
                kmod_module_unref(dm);
 
375
                continue;
 
376
        }
 
377
        kmod_module_unref_list(deps);
 
378
        return err;
 
379
}
 
380
 
 
381
static int rmmod_do(struct kmod_module *mod)
 
382
{
 
383
        const char *modname = kmod_module_get_name(mod);
 
384
        int err;
 
385
 
 
386
        if (!ignore_loaded) {
 
387
                int state = kmod_module_get_initstate(mod);
 
388
                if (state == KMOD_MODULE_BUILTIN) {
 
389
                        LOG("Module %s is builtin.\n", modname);
 
390
                        return -ENOENT;
 
391
                } else if (state != KMOD_MODULE_LIVE) {
 
392
                        if (first_time) {
 
393
                                LOG("Module %s is not in kernel.\n", modname);
 
394
                                return -ENOENT;
 
395
                        } else
 
396
                                return 0;
 
397
                }
 
398
        }
 
399
 
 
400
        /* not in original modprobe -r, but helpful */
 
401
        if (remove_dependencies) {
 
402
                err = rmmod_do_dependencies(mod);
 
403
                if (err < 0)
 
404
                        return err;
 
405
        }
 
406
 
 
407
        if (!ignore_commands) {
 
408
                const char *cmd;
 
409
 
 
410
                err = rmmod_do_soft_dependencies(mod);
 
411
                if (err < 0)
 
412
                        return err;
 
413
 
 
414
                cmd = kmod_module_get_remove_commands(mod);
 
415
                if (cmd)
 
416
                        return command_do(mod, "remove", cmd, NULL);
 
417
        }
 
418
 
 
419
        if (!ignore_loaded) {
 
420
                int usage = kmod_module_get_refcnt(mod);
 
421
                if (usage > 0) {
 
422
                        LOG("Module %s is in use.\n", modname);
 
423
                        return -EBUSY;
 
424
                }
 
425
        }
 
426
 
 
427
        SHOW("rmmod %s\n", modname);
 
428
 
 
429
        if (dry_run)
 
430
                err = 0;
 
431
        else {
 
432
                int flags = 0;
 
433
 
 
434
                if (force)
 
435
                        flags |= KMOD_REMOVE_FORCE;
 
436
 
 
437
                err = kmod_module_remove_module(mod, flags);
 
438
                if (err == -EEXIST) {
 
439
                        if (!first_time)
 
440
                                err = 0;
 
441
                        else
 
442
                                LOG("Module %s is not in kernel.\n", modname);
 
443
                }
 
444
        }
 
445
        return err;
 
446
}
 
447
 
 
448
static int rmmod_path(struct kmod_ctx *ctx, const char *path)
 
449
{
 
450
        struct kmod_module *mod;
 
451
        int err;
 
452
 
 
453
        err = kmod_module_new_from_path(ctx, path, &mod);
 
454
        if (err < 0) {
 
455
                LOG("Module %s not found.\n", path);
 
456
                return err;
 
457
        }
 
458
        err = rmmod_do(mod);
 
459
        kmod_module_unref(mod);
 
460
        return err;
 
461
}
 
462
 
 
463
static int rmmod_do_commands(struct kmod_ctx *ctx, const char *name)
 
464
{
 
465
        ERR("TODO - get commands for non modules!\n");
 
466
        return -ENOENT;
 
467
}
 
468
 
 
469
static int rmmod_alias(struct kmod_ctx *ctx, const char *alias)
 
470
{
 
471
        struct kmod_list *l, *list = NULL;
 
472
        int err;
 
473
 
 
474
        err = kmod_module_new_from_lookup(ctx, alias, &list);
 
475
        if (err < 0 || list == NULL) {
 
476
                if (list == NULL) {
 
477
                        err = rmmod_do_commands(ctx, alias);
 
478
                        if (err < 0)
 
479
                                LOG("Module %s not found.\n", alias);
 
480
                }
 
481
                return err;
 
482
        }
 
483
 
 
484
        kmod_list_foreach(l, list) {
 
485
                struct kmod_module *mod = kmod_module_get_module(l);
 
486
                err = rmmod_do(mod);
 
487
                kmod_module_unref(mod);
 
488
                if (err < 0)
 
489
                        break;
 
490
        }
 
491
 
 
492
        kmod_module_unref_list(list);
 
493
        return err;
 
494
}
 
495
 
 
496
static int rmmod(struct kmod_ctx *ctx, const char *name)
 
497
{
 
498
        struct stat st;
 
499
        if (stat(name, &st) == 0)
 
500
                return rmmod_path(ctx, name);
 
501
        else
 
502
                return rmmod_alias(ctx, name);
 
503
}
 
504
 
 
505
static int rmmod_all(struct kmod_ctx *ctx, char **args, int nargs)
 
506
{
 
507
        int i, err = 0;
 
508
 
 
509
        for (i = 0; i < nargs; i++) {
 
510
                int r = rmmod(ctx, args[i]);
 
511
                if (r < 0)
 
512
                        err = r;
 
513
        }
 
514
 
 
515
        return err;
 
516
}
 
517
 
 
518
static int insmod_do_soft_dependencies(struct kmod_module *mod)
 
519
{
 
520
        ERR("TODO - implement soft dependencies!\n");
 
521
        return 0;
 
522
}
 
523
 
 
524
static int insmod_do_dependencies(struct kmod_module *parent)
 
525
{
 
526
        int err = 0;
 
527
        struct kmod_list *d, *deps = kmod_module_get_dependencies(parent);
 
528
        kmod_list_foreach(d, deps) {
 
529
                struct kmod_module *dm = kmod_module_get_module(d);
 
530
                const char *cmd, *opts, *dmname = kmod_module_get_name(dm);
 
531
                int r;
 
532
 
 
533
                r = insmod_do_dependencies(dm);
 
534
                if (r < 0) {
 
535
                        WRN("could not insert dependencies of '%s': %s\n",
 
536
                            dmname, strerror(-r));
 
537
                        goto dep_error;
 
538
                }
 
539
 
 
540
                if (!ignore_loaded) {
 
541
                        int state = kmod_module_get_initstate(dm);
 
542
                        if (state == KMOD_MODULE_LIVE ||
 
543
                                        state == KMOD_MODULE_COMING ||
 
544
                                        state == KMOD_MODULE_BUILTIN)
 
545
                                goto dep_done;
 
546
                }
 
547
 
 
548
                r = insmod_do_soft_dependencies(dm);
 
549
                if (r < 0) {
 
550
                        WRN("could not insert soft dependencies of '%s': %s\n",
 
551
                            dmname, strerror(-r));
 
552
                        goto dep_error;
 
553
                }
 
554
 
 
555
                cmd = kmod_module_get_install_commands(dm);
 
556
                if (cmd) {
 
557
                        r = command_do(dm, "install", cmd, NULL);
 
558
                        if (r < 0) {
 
559
                                WRN("failed to execute install command of '%s':"
 
560
                                    " %s\n", dmname, strerror(-r));
 
561
                                goto dep_error;
 
562
                        } else
 
563
                                goto dep_done;
 
564
                }
 
565
 
 
566
                opts = kmod_module_get_options(dm);
 
567
                SHOW("insmod %s %s\n",
 
568
                        kmod_module_get_path(dm), opts ? opts : "");
 
569
 
 
570
                if (!dry_run) {
 
571
                        int flags = 0;
 
572
 
 
573
                        if (strip_modversion || force)
 
574
                                flags |= KMOD_INSERT_FORCE_MODVERSION;
 
575
                        if (strip_vermagic || force)
 
576
                                flags |= KMOD_INSERT_FORCE_VERMAGIC;
 
577
 
 
578
                        r = kmod_module_insert_module(dm, flags, opts);
 
579
                        if (r < 0) {
 
580
                                WRN("could not insert '%s': %s\n",
 
581
                                    dmname, strerror(-r));
 
582
                                goto dep_error;
 
583
                        }
 
584
                }
 
585
 
 
586
        dep_done:
 
587
                kmod_module_unref(dm);
 
588
                continue;
 
589
        dep_error:
 
590
                err = r;
 
591
                kmod_module_unref(dm);
 
592
                continue;
 
593
        }
 
594
        kmod_module_unref_list(deps);
 
595
        return err;
 
596
}
 
597
 
 
598
static int insmod_do(struct kmod_module *mod, const char *extra_opts)
 
599
{
 
600
        const char *modname = kmod_module_get_name(mod);
 
601
        const char *conf_opts = kmod_module_get_options(mod);
 
602
        char *opts = NULL;
 
603
        int err;
 
604
 
 
605
        if (!ignore_loaded) {
 
606
                int state = kmod_module_get_initstate(mod);
 
607
 
 
608
                if (state == KMOD_MODULE_BUILTIN) {
 
609
                        if (first_time) {
 
610
                                LOG("Module %s already in kernel (builtin).\n",
 
611
                                    modname);
 
612
                                return -EEXIST;
 
613
                        }
 
614
                        return 0;
 
615
                } else if (state == KMOD_MODULE_LIVE) {
 
616
                        if (first_time) {
 
617
                                LOG("Module %s already in kernel.\n", modname);
 
618
                                return -EEXIST;
 
619
                        }
 
620
                        return 0;
 
621
                }
 
622
        }
 
623
 
 
624
        err = insmod_do_dependencies(mod);
 
625
        if (err < 0)
 
626
                return err;
 
627
 
 
628
        if (!ignore_commands) {
 
629
                const char *cmd;
 
630
 
 
631
                err = insmod_do_soft_dependencies(mod);
 
632
                if (err < 0)
 
633
                        return err;
 
634
 
 
635
                cmd = kmod_module_get_install_commands(mod);
 
636
                if (cmd)
 
637
                        return command_do(mod, "install", cmd, extra_opts);
 
638
        }
 
639
 
 
640
        if (conf_opts || extra_opts) {
 
641
                if (conf_opts == NULL)
 
642
                        opts = strdup(extra_opts);
 
643
                else if (extra_opts == NULL)
 
644
                        opts = strdup(conf_opts);
 
645
                else if (asprintf(&opts, "%s %s", conf_opts, extra_opts) < 0)
 
646
                        opts = NULL;
 
647
 
 
648
                if (opts == NULL)
 
649
                        return -ENOMEM;
 
650
        }
 
651
 
 
652
        SHOW("insmod %s %s\n", kmod_module_get_path(mod), opts ? opts : "");
 
653
 
 
654
        if (dry_run)
 
655
                err = 0;
 
656
        else {
 
657
                int flags = 0;
 
658
 
 
659
                if (strip_modversion || force)
 
660
                        flags |= KMOD_INSERT_FORCE_MODVERSION;
 
661
                if (strip_vermagic || force)
 
662
                        flags |= KMOD_INSERT_FORCE_VERMAGIC;
 
663
 
 
664
                err = kmod_module_insert_module(mod, flags, opts);
 
665
                if (err == -EEXIST) {
 
666
                        if (!first_time)
 
667
                                err = 0;
 
668
                        else
 
669
                                ERR("Module %s already in kernel.\n",
 
670
                                        kmod_module_get_name(mod));
 
671
                }
 
672
        }
 
673
        free(opts);
 
674
        return err;
 
675
}
 
676
 
 
677
static int insmod_path(struct kmod_ctx *ctx, const char *path, const char *extra_options)
 
678
{
 
679
        struct kmod_module *mod;
 
680
        int err;
 
681
 
 
682
        err = kmod_module_new_from_path(ctx, path, &mod);
 
683
        if (err < 0) {
 
684
                LOG("Module %s not found.\n", path);
 
685
                return err;
 
686
        }
 
687
        err = insmod_do(mod, extra_options);
 
688
        kmod_module_unref(mod);
 
689
        return err;
 
690
}
 
691
 
 
692
static int insmod_do_commands(struct kmod_ctx *ctx, const char *name)
 
693
{
 
694
        ERR("TODO - get commands for non modules!\n");
 
695
        return -ENOENT;
 
696
}
 
697
 
 
698
static int insmod_alias(struct kmod_ctx *ctx, const char *alias, const char *extra_options)
 
699
{
 
700
        struct kmod_list *l, *list = NULL;
 
701
        int err;
 
702
 
 
703
        err = kmod_module_new_from_lookup(ctx, alias, &list);
 
704
        if (err < 0 || list == NULL) {
 
705
                if (list == NULL) {
 
706
                        err = insmod_do_commands(ctx, alias);
 
707
                        if (err < 0)
 
708
                                LOG("Module %s not found.\n", alias);
 
709
                }
 
710
                return err;
 
711
        }
 
712
 
 
713
        if (use_blacklist) {
 
714
                struct kmod_list *filtered = NULL;
 
715
                err = kmod_module_get_filtered_blacklist(ctx, list, &filtered);
 
716
                DBG("using blacklist: input %p, output=%p\n", list, filtered);
 
717
                kmod_module_unref_list(list);
 
718
                if (err < 0) {
 
719
                        LOG("Could not filter alias list!\n");
 
720
                        return err;
 
721
                }
 
722
                list = filtered;
 
723
        }
 
724
 
 
725
        kmod_list_foreach(l, list) {
 
726
                struct kmod_module *mod = kmod_module_get_module(l);
 
727
                err = insmod_do(mod, extra_options);
 
728
                kmod_module_unref(mod);
 
729
                if (err < 0)
 
730
                        break;
 
731
        }
 
732
 
 
733
        kmod_module_unref_list(list);
 
734
        return err;
 
735
}
 
736
 
 
737
static int insmod(struct kmod_ctx *ctx, const char *name, const char *extra_options)
 
738
{
 
739
        struct stat st;
 
740
        if (stat(name, &st) == 0)
 
741
                return insmod_path(ctx, name, extra_options);
 
742
        else
 
743
                return insmod_alias(ctx, name, extra_options);
 
744
}
 
745
 
 
746
static int insmod_all(struct kmod_ctx *ctx, char **args, int nargs)
 
747
{
 
748
        int i, err = 0;
 
749
 
 
750
        for (i = 0; i < nargs; i++) {
 
751
                int r = insmod(ctx, args[i], NULL);
 
752
                if (r < 0)
 
753
                        err = r;
 
754
        }
 
755
 
 
756
        return err;
 
757
}
 
758
 
 
759
static void env_modprobe_options_append(const char *value)
 
760
{
 
761
        const char *old = getenv("MODPROBE_OPTIONS");
 
762
        char *env;
 
763
 
 
764
        if (old == NULL) {
 
765
                setenv("MODPROBE_OPTIONS", value, 1);
 
766
                return;
 
767
        }
 
768
 
 
769
        if (asprintf(&env, "%s %s", old, value) < 0) {
 
770
                ERR("could not append value to $MODPROBE_OPTIONS\n");
 
771
                return;
 
772
        }
 
773
 
 
774
        if (setenv("MODPROBE_OPTIONS", env, 1) < 0)
 
775
                ERR("could not setenv(MODPROBE_OPTIONS, \"%s\")\n", env);
 
776
        free(env);
 
777
}
 
778
 
 
779
static int options_from_array(char **args, int nargs, char **output)
 
780
{
 
781
        char *opts = NULL;
 
782
        size_t optslen = 0;
 
783
        int i, err = 0;
 
784
 
 
785
        for (i = 1; i < nargs; i++) {
 
786
                size_t len = strlen(args[i]);
 
787
                size_t qlen = 0;
 
788
                const char *value;
 
789
                void *tmp;
 
790
 
 
791
                value = strchr(args[i], '=');
 
792
                if (value) {
 
793
                        value++;
 
794
                        if (*value != '"' && *value != '\'') {
 
795
                                if (strchr(value, ' '))
 
796
                                        qlen = 2;
 
797
                        }
 
798
                }
 
799
 
 
800
                tmp = realloc(opts, optslen + len + qlen + 2);
 
801
                if (!tmp) {
 
802
                        err = -errno;
 
803
                        free(opts);
 
804
                        opts = NULL;
 
805
                        ERR("could not gather module options: out-of-memory\n");
 
806
                        break;
 
807
                }
 
808
                opts = tmp;
 
809
                if (optslen > 0) {
 
810
                        opts[optslen] = ' ';
 
811
                        optslen++;
 
812
                }
 
813
                if (qlen == 0) {
 
814
                        memcpy(opts + optslen, args[i], len + 1);
 
815
                        optslen += len;
 
816
                } else {
 
817
                        size_t keylen = value - args[i];
 
818
                        size_t valuelen = len - keylen;
 
819
                        memcpy(opts + optslen, args[i], keylen);
 
820
                        optslen += keylen;
 
821
                        opts[optslen] = '"';
 
822
                        optslen++;
 
823
                        memcpy(opts + optslen, value, valuelen);
 
824
                        optslen += valuelen;
 
825
                        opts[optslen] = '"';
 
826
                        optslen++;
 
827
                        opts[optslen] = '\0';
 
828
                }
 
829
        }
 
830
 
 
831
        *output = opts;
 
832
        return err;
 
833
}
 
834
 
 
835
static char **prepend_options_from_env(int *p_argc, char **orig_argv)
 
836
{
 
837
        const char *p, *env = getenv("MODPROBE_OPTIONS");
 
838
        char **new_argv, *str_start, *str_end, *str, *s, *quote;
 
839
        int i, argc = *p_argc;
 
840
        size_t envlen, space_count = 0;
 
841
 
 
842
        if (env == NULL)
 
843
                return orig_argv;
 
844
 
 
845
        for (p = env; *p != '\0'; p++) {
 
846
                if (*p == ' ')
 
847
                        space_count++;
 
848
        }
 
849
 
 
850
        envlen = p - env;
 
851
        new_argv = malloc(sizeof(char *) * (argc + space_count + 3 + envlen));
 
852
        if (new_argv == NULL)
 
853
                return NULL;
 
854
 
 
855
        new_argv[0] = orig_argv[0];
 
856
        str_start = str = (char *) (new_argv + argc + space_count + 3);
 
857
        memcpy(str, env, envlen + 1);
 
858
 
 
859
        str_end = str_start + envlen;
 
860
 
 
861
        quote = NULL;
 
862
        for (i = 1, s = str; *s != '\0'; s++) {
 
863
                if (quote == NULL) {
 
864
                        if (*s == ' ') {
 
865
                                new_argv[i] = str;
 
866
                                i++;
 
867
                                *s = '\0';
 
868
                                str = s + 1;
 
869
                        } else if (*s == '"' || *s == '\'')
 
870
                                quote = s;
 
871
                } else {
 
872
                        if (*s == *quote) {
 
873
                                if (quote == str) {
 
874
                                        new_argv[i] = str + 1;
 
875
                                        i++;
 
876
                                        *s = '\0';
 
877
                                        str = s + 1;
 
878
                                } else {
 
879
                                        char *it;
 
880
                                        for (it = quote; it < s - 1; it++)
 
881
                                                it[0] = it[1];
 
882
                                        for (it = s - 1; it < str_end - 2; it++)
 
883
                                                it[0] = it[2];
 
884
                                        str_end -= 2;
 
885
                                        *str_end = '\0';
 
886
                                        s -= 2;
 
887
                                }
 
888
                                quote = NULL;
 
889
                        }
 
890
                }
 
891
        }
 
892
        if (str < s) {
 
893
                new_argv[i] = str;
 
894
                i++;
 
895
        }
 
896
 
 
897
        memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
 
898
        new_argv[i + argc] = NULL;
 
899
        *p_argc = i + argc - 1;
 
900
 
 
901
        return new_argv;
 
902
}
 
903
 
 
904
static void log_syslog(void *data, int priority, const char *file, int line,
 
905
                                const char *fn, const char *format,
 
906
                                va_list args)
 
907
{
 
908
        char *str, buf[32];
 
909
        const char *prioname;
 
910
 
 
911
        switch (priority) {
 
912
        case LOG_CRIT:
 
913
                prioname = "FATAL";
 
914
                break;
 
915
        case LOG_ERR:
 
916
                prioname = "ERROR";
 
917
                break;
 
918
        case LOG_WARNING:
 
919
                prioname = "WARNING";
 
920
                break;
 
921
        case LOG_NOTICE:
 
922
                prioname = "NOTICE";
 
923
                break;
 
924
        case LOG_INFO:
 
925
                prioname = "INFO";
 
926
                break;
 
927
        case LOG_DEBUG:
 
928
                prioname = "DEBUG";
 
929
                break;
 
930
        default:
 
931
                snprintf(buf, sizeof(buf), "LOG-%03d", priority);
 
932
                prioname = buf;
 
933
        }
 
934
 
 
935
        if (vasprintf(&str, format, args) < 0)
 
936
                return;
 
937
#ifdef ENABLE_DEBUG
 
938
        syslog(LOG_NOTICE, "%s: %s:%d %s() %s", prioname, file, line, fn, str);
 
939
#else
 
940
        syslog(LOG_NOTICE, "%s: %s", prioname, str);
 
941
#endif
 
942
        free(str);
 
943
        (void)data;
 
944
}
 
945
 
 
946
int main(int argc, char **orig_argv)
 
947
{
 
948
        struct kmod_ctx *ctx;
 
949
        char **args = NULL, **argv;
 
950
        const char **config_paths = NULL;
 
951
        int nargs = 0, n_config_paths = 0;
 
952
        char dirname_buf[PATH_MAX];
 
953
        const char *dirname = NULL;
 
954
        const char *root = NULL;
 
955
        const char *kversion = NULL;
 
956
        const char *list_type = NULL;
 
957
        int use_all = 0;
 
958
        int do_remove = 0;
 
959
        int do_show_config = 0;
 
960
        int do_show_modversions = 0;
 
961
        int do_show_list = 0;
 
962
        int err;
 
963
 
 
964
        argv = prepend_options_from_env(&argc, orig_argv);
 
965
        if (argv == NULL) {
 
966
                fputs("Error: could not prepend options from command line\n",
 
967
                        stderr);
 
968
                return EXIT_FAILURE;
 
969
        }
 
970
 
 
971
        for (;;) {
 
972
                int c, idx = 0;
 
973
                c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
 
974
                if (c == -1)
 
975
                        break;
 
976
                switch (c) {
 
977
                case 'a':
 
978
                        log_priority = LOG_WARNING;
 
979
                        use_all = 1;
 
980
                        break;
 
981
                case 'r':
 
982
                        do_remove = 1;
 
983
                        break;
 
984
                case 5:
 
985
                        remove_dependencies = 1;
 
986
                        break;
 
987
                case 'R':
 
988
                        show_resolved_aliases = 1;
 
989
                        break;
 
990
                case 3:
 
991
                        first_time = 1;
 
992
                        break;
 
993
                case 'i':
 
994
                        ignore_commands = 1;
 
995
                        break;
 
996
                case 'b':
 
997
                        use_blacklist = 1;
 
998
                        break;
 
999
                case 'f':
 
1000
                        force = 1;
 
1001
                        break;
 
1002
                case 2:
 
1003
                        strip_modversion = 1;
 
1004
                        break;
 
1005
                case 1:
 
1006
                        strip_vermagic = 1;
 
1007
                        break;
 
1008
                case 't':
 
1009
                        list_type = optarg;
 
1010
                        break;
 
1011
                case 'l':
 
1012
                        do_show_list = 1;
 
1013
                        break;
 
1014
                case 'D':
 
1015
                        ignore_loaded = 1;
 
1016
                        dry_run = 1;
 
1017
                        verbose++;
 
1018
                        break;
 
1019
                case 'c':
 
1020
                        do_show_config = 1;
 
1021
                        break;
 
1022
                case 4:
 
1023
                        do_show_modversions = 1;
 
1024
                        break;
 
1025
                case 'n':
 
1026
                        dry_run = 1;
 
1027
                        break;
 
1028
                case 'C': {
 
1029
                        size_t bytes = sizeof(char *) * (n_config_paths + 2);
 
1030
                        void *tmp = realloc(config_paths, bytes);
 
1031
                        if (!tmp) {
 
1032
                                fputs("Error: out-of-memory\n", stderr);
 
1033
                                goto cmdline_failed;
 
1034
                        }
 
1035
                        config_paths = tmp;
 
1036
                        config_paths[n_config_paths] = optarg;
 
1037
                        n_config_paths++;
 
1038
                        config_paths[n_config_paths] = NULL;
 
1039
 
 
1040
                        env_modprobe_options_append("-C");
 
1041
                        env_modprobe_options_append(optarg);
 
1042
                        break;
 
1043
                }
 
1044
                case 'd':
 
1045
                        root = optarg;
 
1046
                        break;
 
1047
                case 'S':
 
1048
                        kversion = optarg;
 
1049
                        break;
 
1050
                case 's':
 
1051
                        env_modprobe_options_append("-s");
 
1052
                        use_syslog = 1;
 
1053
                        break;
 
1054
                case 'q':
 
1055
                        env_modprobe_options_append("-q");
 
1056
                        verbose--;
 
1057
                        break;
 
1058
                case 'v':
 
1059
                        env_modprobe_options_append("-v");
 
1060
                        verbose++;
 
1061
                        break;
 
1062
                case 'V':
 
1063
                        puts(PACKAGE " version " VERSION);
 
1064
                        if (argv != orig_argv)
 
1065
                                free(argv);
 
1066
                        return EXIT_SUCCESS;
 
1067
                case 'h':
 
1068
                        help(argv[0]);
 
1069
                        if (argv != orig_argv)
 
1070
                                free(argv);
 
1071
                        return EXIT_SUCCESS;
 
1072
                case '?':
 
1073
                        goto cmdline_failed;
 
1074
                default:
 
1075
                        fprintf(stderr,
 
1076
                                "Error: unexpected getopt_long() value '%c'.\n",
 
1077
                                c);
 
1078
                        goto cmdline_failed;
 
1079
                }
 
1080
        }
 
1081
 
 
1082
        args = argv + optind;
 
1083
        nargs = argc - optind;
 
1084
 
 
1085
        if (!do_show_config && !do_show_list) {
 
1086
                if (nargs == 0) {
 
1087
                        fputs("Error: missing parameters. See -h.\n", stderr);
 
1088
                        goto cmdline_failed;
 
1089
                }
 
1090
        }
 
1091
 
 
1092
        if (!do_show_list && list_type != NULL) {
 
1093
                fputs("Error: -t (--type) only supported with -l (--list).\n",
 
1094
                      stderr);
 
1095
                goto cmdline_failed;
 
1096
        }
 
1097
 
 
1098
        if (root != NULL || kversion != NULL) {
 
1099
                struct utsname u;
 
1100
                if (root == NULL)
 
1101
                        root = "";
 
1102
                if (kversion == NULL) {
 
1103
                        if (uname(&u) < 0) {
 
1104
                                fprintf(stderr, "Error: uname() failed: %s\n",
 
1105
                                        strerror(errno));
 
1106
                                goto cmdline_failed;
 
1107
                        }
 
1108
                        kversion = u.release;
 
1109
                }
 
1110
                snprintf(dirname_buf, sizeof(dirname_buf), "%s/lib/modules/%s",
 
1111
                         root, kversion);
 
1112
                dirname = dirname_buf;
 
1113
        }
 
1114
 
 
1115
        ctx = kmod_new(dirname, config_paths);
 
1116
        if (!ctx) {
 
1117
                fputs("Error: kmod_new() failed!\n", stderr);
 
1118
                goto cmdline_failed;
 
1119
        }
 
1120
        kmod_load_resources(ctx);
 
1121
 
 
1122
        kmod_set_log_priority(ctx, verbose);
 
1123
        if (use_syslog) {
 
1124
                openlog("modprobe", LOG_CONS, LOG_DAEMON);
 
1125
                kmod_set_log_fn(ctx, log_syslog, NULL);
 
1126
        }
 
1127
 
 
1128
        if (do_show_list)
 
1129
                err = show_list(ctx, list_type, nargs > 0 ? args[0] : NULL);
 
1130
        else if (do_show_config)
 
1131
                err = show_config(ctx);
 
1132
        else if (do_show_modversions)
 
1133
                err = show_modversions(ctx, args[0]);
 
1134
        else if (do_remove)
 
1135
                err = rmmod_all(ctx, args, use_all ? nargs : 1);
 
1136
        else if (use_all)
 
1137
                err = insmod_all(ctx, args, nargs);
 
1138
        else {
 
1139
                char *opts;
 
1140
                err = options_from_array(args, nargs, &opts);
 
1141
                if (err == 0) {
 
1142
                        err = insmod(ctx, args[0], opts);
 
1143
                        free(opts);
 
1144
                }
 
1145
        }
 
1146
 
 
1147
        kmod_unref(ctx);
 
1148
 
 
1149
        if (use_syslog)
 
1150
                closelog();
 
1151
 
 
1152
        if (argv != orig_argv)
 
1153
                free(argv);
 
1154
        free(config_paths);
 
1155
        return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 
1156
 
 
1157
cmdline_failed:
 
1158
        if (argv != orig_argv)
 
1159
                free(argv);
 
1160
        free(config_paths);
 
1161
        return EXIT_FAILURE;
 
1162
}