summaryrefslogtreecommitdiffhomepage
path: root/modutils/modutils.c
blob: 969926db98c83744aff1f1751af2ebdf4a1089fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Common modutils related functions for busybox
 *
 * Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
 *
 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
 */
#include "modutils.h"

#ifdef __UCLIBC__
extern int init_module(void *module, unsigned long len, const char *options);
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif

void FAST_FUNC replace(char *s, char what, char with)
{
	while (*s) {
		if (what == *s)
			*s = with;
		++s;
	}
}

char* FAST_FUNC replace_underscores(char *s)
{
	replace(s, '-', '_');
	return s;
}

int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim)
{
	char *tok;
	int len = 0;

	while ((tok = strsep(&string, delim)) != NULL) {
		if (tok[0] == '\0')
			continue;
		llist_add_to_end(llist, xstrdup(tok));
		len += strlen(tok);
	}
	return len;
}

char* FAST_FUNC filename2modname(const char *filename, char *modname)
{
	int i;
	char *from;

	if (filename == NULL)
		return NULL;
	if (modname == NULL)
		modname = xmalloc(MODULE_NAME_LEN);
	from = bb_get_last_path_component_nostrip(filename);
	for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
		modname[i] = (from[i] == '-') ? '_' : from[i];
	modname[i] = '\0';

	return modname;
}

char * FAST_FUNC parse_cmdline_module_options(char **argv)
{
	char *options;
	int optlen;

	options = xzalloc(1);
	optlen = 0;
	while (*++argv) {
		options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
		/* Spaces handled by "" pairs, but no way of escaping quotes */
		optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv);
	}
	return options;
}

/* Return:
 * 0 on success,
 * -errno on open/read error,
 * errno on init_module() error
 */
int FAST_FUNC bb_init_module(const char *filename, const char *options)
{
	size_t len;
	char *image;
	int rc;

	if (!options)
		options = "";

//TODO: audit bb_init_module_24 to match error code convention
#if ENABLE_FEATURE_2_4_MODULES
	if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
		return bb_init_module_24(filename, options);
#endif

	/* Use the 2.6 way */
	len = INT_MAX - 4095;
	errno = ENOMEM; /* may be changed by e.g. open errors below */
	image = xmalloc_open_zipped_read_close(filename, &len);
	if (!image)
		return -errno;

	errno = 0;
	init_module(image, len, options);
	rc = errno;
	free(image);
	return rc;
}

int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
{
	errno = 0;
	delete_module(module, flags);
	return errno;
}

const char* FAST_FUNC moderror(int err)
{
	switch (err) {
	case -1: /* btw: it's -EPERM */
		return "no such module";
	case ENOEXEC:
		return "invalid module format";
	case ENOENT:
		return "unknown symbol in module, or unknown parameter";
	case ESRCH:
		return "module has wrong symbol version";
	case ENOSYS:
		return "kernel does not support requested operation";
	}
	if (err < 0) /* should always be */
		err = -err;
	return strerror(err);
}