?? modprobe.c
字號:
/* modprobe.c: insert a module into the kernel, intelligently. Copyright (C) 2001 Rusty Russell. Copyright (C) 2002, 2003 Rusty Russell, IBM Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#define _GNU_SOURCE /* asprintf */#include <sys/utsname.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <dirent.h>#include <limits.h>#include <elf.h>#include <getopt.h>#include <fnmatch.h>#include <asm/unistd.h>#include <sys/wait.h>#include <syslog.h>#define streq(a,b) (strcmp((a),(b)) == 0)#include "zlibsupport.h"#include "list.h"#include "backwards_compat.c"extern long init_module(void *, unsigned long, const char *);extern long delete_module(const char *, unsigned int);struct module { struct list_head list; char *modname; char filename[0];};#ifndef MODULE_DIR#define MODULE_DIR "/lib/modules"#endiftypedef void (*errfn_t)(const char *fmt, ...);/* Do we use syslog or stderr for messages? */static int log;static void message(const char *prefix, const char *fmt, va_list *arglist){ char *buf, *buf2; vasprintf(&buf, fmt, *arglist); asprintf(&buf2, "%s%s", prefix, buf); if (log) syslog(LOG_NOTICE, buf2); else fprintf(stderr, "%s", buf2); free(buf2); free(buf);}static void warn(const char *fmt, ...){ va_list arglist; va_start(arglist, fmt); message("WARNING: ", fmt, &arglist); va_end(arglist);}static void fatal(const char *fmt, ...){ va_list arglist; va_start(arglist, fmt); message("FATAL: ", fmt, &arglist); va_end(arglist); exit(1);}static void grammar(const char *cmd, const char *filename, unsigned int line){ warn("%s line %u: ignoring bad line starting with '%s'\n", filename, line, cmd);}static void *do_nofail(void *ptr, const char *file, int line, const char *expr){ if (!ptr) { fatal("Memory allocation failure %s line %d: %s.\n", file, line, expr); } return ptr;}#define NOFAIL(ptr) do_nofail((ptr), __FILE__, __LINE__, #ptr)static void print_usage(const char *progname){ fprintf(stderr, "Usage: %s [-v] [-V] [-C config-file] [-n] [-i] [-q] [-o <modname>] <modname> [parameters...]\n" "%s -r [-n] [-i] [-v] <modulename> ...\n" "%s -l -t <dirname> [ -a <modulename> ...]\n", progname, progname, progname); exit(1);}static int fgetc_wrapped(FILE *file, unsigned int *linenum){ for (;;) { int ch = fgetc(file); if (ch != '\\') return ch; ch = fgetc(file); if (ch != '\n') return ch; if (linenum) (*linenum)++; }}static char *getline_wrapped(FILE *file, unsigned int *linenum){ int size = 1024; int i = 0; char *buf = NOFAIL(malloc(size)); for(;;) { int ch = fgetc_wrapped(file, linenum); if (i == size) { size *= 2; buf = NOFAIL(realloc(buf, size)); } if (ch < 0 && i == 0) { free(buf); return NULL; } if (ch < 0 || ch == '\n') { if (linenum) (*linenum)++; buf[i] = '\0'; return NOFAIL(realloc(buf, i+1)); } buf[i++] = ch; }}static struct module *find_module(const char *filename, struct list_head *list){ struct module *i; list_for_each_entry(i, list, list) { if (strcmp(i->filename, filename) == 0) return i; } return NULL;}/* Convert filename to the module name. Works if filename == modname, too. */static void filename2modname(char *modname, const char *filename){ const char *afterslash; unsigned int i; afterslash = strrchr(filename, '/'); if (!afterslash) afterslash = filename; else afterslash++; /* Convert to underscores, stop at first . */ for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) { if (afterslash[i] == '-') modname[i] = '_'; else modname[i] = afterslash[i]; } modname[i] = '\0';}static void add_module(char *filename, int namelen, struct list_head *list){ struct module *mod; /* If it's a duplicate: move it to the end, so it gets inserted where it is *first* required. */ mod = find_module(filename, list); if (mod) list_del(&mod->list); else { /* No match. Create a new module. */ mod = NOFAIL(malloc(sizeof(struct module) + namelen + 1)); memcpy(mod->filename, filename, namelen); mod->filename[namelen] = '\0'; mod->modname = NOFAIL(malloc(namelen + 1)); filename2modname(mod->modname, mod->filename); } list_add_tail(&mod->list, list);}/* Compare len chars of a to b, with _ and - equivalent. */static int modname_equal(const char *a, const char *b, unsigned int len){ unsigned int i; if (strlen(b) != len) return 0; for (i = 0; i < len; i++) { if ((a[i] == '_' || a[i] == '-') && (b[i] == '_' || b[i] == '-')) continue; if (a[i] != b[i]) return 0; } return 1;}/* Fills in list of modules if this is the line we want. */static int add_modules_dep_line(char *line, const char *name, struct list_head *list){ char *ptr; int len; char *modname; /* Ignore lines without : or which start with a # */ ptr = index(line, ':'); if (ptr == NULL || line[strspn(line, "\t ")] == '#') return 0; /* Is this the module we are looking for? */ *ptr = '\0'; if (strrchr(line, '/')) modname = strrchr(line, '/') + 1; else modname = line; len = strlen(modname); if (strchr(modname, '.')) len = strchr(modname, '.') - modname; if (!modname_equal(modname, name, len)) return 0; /* Create the list. */ add_module(line, ptr - line, list); ptr++; for(;;) { char *dep_start; ptr += strspn(ptr, " \t"); if (*ptr == '\0') break; dep_start = ptr; ptr += strcspn(ptr, " \t"); add_module(dep_start, ptr - dep_start, list); } return 1;}static void read_depends(const char *dirname, const char *start_name, struct list_head *list){ char *modules_dep_name; char *line; FILE *modules_dep; int done = 0; asprintf(&modules_dep_name, "%s/%s", dirname, "modules.dep"); modules_dep = fopen(modules_dep_name, "r"); if (!modules_dep) fatal("Could not load %s: %s\n", modules_dep_name, strerror(errno)); /* Stop at first line, as we can have duplicates (eg. symlinks from boot/ */ while (!done && (line = getline_wrapped(modules_dep, NULL)) != NULL) { done = add_modules_dep_line(line, start_name, list); free(line); } fclose(modules_dep); free(modules_dep_name);}/* We use error numbers in a loose translation... */static const char *insert_moderror(int err){ switch (err) { case ENOEXEC: return "Invalid module format"; case ENOENT: return "Unknown symbol in module, or unknown parameter (see dmesg)"; case ENOSYS: return "Kernel does not have module support"; default: return strerror(err); }}static const char *remove_moderror(int err){ switch (err) { case ENOENT: return "No such module"; case ENOSYS: return "Kernel does not have module unloading support"; default: return strerror(err); }}/* Is module in /proc/modules? If so, fill in usecount if not NULL. 0 means no, 1 means yes, -1 means unknown. */static int module_in_kernel(const char *modname, int *usecount){ FILE *proc_modules; char *line; /* Might not be mounted yet. Don't fail. */ proc_modules = fopen("/proc/modules", "r"); if (!proc_modules) return -1; while ((line = getline_wrapped(proc_modules, NULL)) != NULL) { char *entry = strtok(line, " \n"); if (entry && strcmp(entry, modname) == 0) { /* If it exists, usecount is the third entry. */ if (usecount) { entry = strtok(NULL, " \n"); if (entry && (entry = strtok(NULL, " \n")) != NULL) *usecount = atoi(entry); } free(line); fclose(proc_modules); return 1; } free(line); } fclose(proc_modules); return 0;}static void replace_modname(struct module *module, void *mem, unsigned long len, const char *oldname, const char *newname){ char *p; /* 64 - sizeof(unsigned long) - 1 */ if (strlen(newname) > 55) fatal("New name %s is too long\n", newname); /* Find where it is in the module structure. Don't assume layout! */ for (p = mem; p < (char *)mem + len - strlen(oldname); p++) { if (memcmp(p, oldname, strlen(oldname)) == 0) { strcpy(p, newname); return; } } warn("Could not find old name in %s to replace!\n", module->filename);}static void *get_section32(void *file, unsigned long size, const char *name, unsigned long *secsize){ Elf32_Ehdr *hdr = file; Elf32_Shdr *sechdrs = file + hdr->e_shoff; const char *secnames; unsigned int i; /* Too short? */ if (size < sizeof(*hdr)) return NULL; if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0])) return NULL; if (size < sechdrs[hdr->e_shstrndx].sh_offset) return NULL; secnames = file + sechdrs[hdr->e_shstrndx].sh_offset; for (i = 1; i < hdr->e_shnum; i++) if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) { *secsize = sechdrs[i].sh_size; return file + sechdrs[i].sh_offset; } return NULL;}static void *get_section64(void *file, unsigned long size, const char *name, unsigned long *secsize){ Elf64_Ehdr *hdr = file; Elf64_Shdr *sechdrs = file + hdr->e_shoff; const char *secnames; unsigned int i; /* Too short? */ if (size < sizeof(*hdr)) return NULL; if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0])) return NULL; if (size < sechdrs[hdr->e_shstrndx].sh_offset) return NULL; secnames = file + sechdrs[hdr->e_shstrndx].sh_offset; for (i = 1; i < hdr->e_shnum; i++) if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) { *secsize = sechdrs[i].sh_size; return file + sechdrs[i].sh_offset; } return NULL;}static int elf_ident(void *mod, unsigned long size){ /* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */ char *ident = mod; if (size < EI_CLASS || memcmp(mod, ELFMAG, SELFMAG) != 0) return ELFCLASSNONE; return ident[EI_CLASS];}static void *get_section(void *file, unsigned long size, const char *name, unsigned long *secsize){ switch (elf_ident(file, size)) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -