]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/patch.cc
Update
[l4.git] / l4 / pkg / bootstrap / server / src / patch.cc
1 /**
2  * \file        bootstrap/server/src/patch.c
3  * \brief       Patching of boot modules
4  * 
5  * \date        09/2005
6  * \author      Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7
8 /*
9  * (c) 2005-2009 Author(s)
10  *     economic rights: Technische Universität Dresden (Germany)
11  *
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU General Public License 2.
14  * Please see the COPYING-GPL-2 file for details.
15  */
16
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21
22 #include <l4/sys/consts.h>
23 #include <l4/util/mb_info.h>
24 #include "panic.h"
25 #include "macros.h"
26 #include "types.h"
27 #include "patch.h"
28 #include "startup.h"
29
30
31 /* search module in module list */
32 static l4util_mb_mod_t*
33 search_module(const char *name, size_t name_len, l4util_mb_info_t *mbi,
34               const char **cmdline)
35 {
36   unsigned i;
37   const char *c = 0, *ce = 0;
38   l4util_mb_mod_t *mod;
39
40   for (i=0; i<mbi->mods_count; i++)
41     {
42       const char *m, *n;
43
44       mod = (L4_MB_MOD_PTR(mbi->mods_addr)) + i;
45       m = c = L4_CONST_CHAR_PTR(mod->cmdline);
46       ce = strchr(c, ' ');
47       if (!ce)
48         ce = c+strlen(c);
49       for (;;)
50         {
51           if (!(n = strchr(m, name[0])) || n+name_len>ce)
52             break;
53           if (!memcmp(name, n, name_len))
54             {
55               *cmdline = c;
56               return mod;
57             }
58           m = n+1;
59         }
60     }
61
62   return NULL;
63 }
64
65 /**
66  * Handle -patch=<module_name>,<variable>=blah parameter. Overwrite a specific
67  * module from command line. This allows to change the boot configuration (e.g.
68  * changing parameters of a loader script)
69  */
70 void
71 patch_module(const char **str, l4util_mb_info_t *mbi)
72 {
73   const char *nam_beg, *nam_end;
74   const char *var_beg, *var_end;
75   const char *val_beg, *val_end;
76   char *mod_beg, *mod_end, *mod_ptr, quote = 0;
77   l4_size_t var_size, val_size, max_patch_size;
78   const char *cmdline = 0;
79   l4util_mb_mod_t *mod;
80
81   /* nam_beg ... nam_end */
82   nam_beg = *str+8;
83   nam_end = strchr(nam_beg, ',');
84   if (!nam_end || strpbrk(nam_beg, "\011 =*")-1 < nam_end)
85     panic("-patch: bad module name");
86
87   mod = search_module(nam_beg, nam_end-nam_beg, mbi, &cmdline);
88   if (!mod)
89     panic("-patch: cannot find module \"%.*s\"",
90           (int)(nam_end-nam_beg), nam_beg);
91
92   mod_beg = L4_CHAR_PTR(mod->mod_start);
93   mod_end = L4_CHAR_PTR(mod->mod_end);
94
95   /* How much bytes the module can be enlarged to. The module cannot
96    * be extended beyond page boundaries because the next module starts
97    * there and we don't want to move the following modules. */
98   max_patch_size = l4_round_page((l4_addr_t)mod_end) - (l4_addr_t)mod_end - 1;
99
100   printf("  Patching module \"%s\"\n", cmdline);
101
102   for (var_beg=nam_end; *var_beg==','; var_beg=*str)
103     {
104       var_beg++;
105       /* var_beg ... var_end */
106       var_end = strchr(var_beg, '=');
107       if (!var_end || strpbrk(var_beg, "\011 ,*")-1 < nam_end)
108         panic("-patch: bad variable name");
109       var_size = var_end-var_beg;
110
111       /* val_beg ... val_end, consider quotes */
112       val_beg = val_end = var_end+1;
113       if (*val_end == '"' || *val_end == '\'')
114         {
115           val_beg++;
116           quote = *val_end++;
117         }
118       while (*val_end && ((!quote && !isspace(*val_end) && *val_end!=',') ||
119                           (quote && *val_end!=quote)))
120         val_end++;
121       *str = val_end;
122       if (quote)
123         (*str)++;
124       quote = 0;
125       val_size = val_end-val_beg;
126
127       /* replace all occurences of variable with value */
128       for (mod_ptr=mod_beg;;)
129         {
130           if (!(mod_ptr = (char *)memmem(mod_ptr, mod_end - mod_ptr,
131                                          var_beg, var_end - var_beg)))
132             break;
133           if (var_size < val_size && max_patch_size < val_size-var_size)
134             panic("-patch: not enough space in module");
135           max_patch_size += var_size - val_size;
136           memmove(mod_ptr+val_size, mod_ptr+var_size, mod_end-mod_ptr-var_size);
137           if (val_size < var_size)
138             memset(mod_end-var_size+val_size, 0, var_size-val_size);
139           memcpy(mod_ptr, val_beg, val_size);
140           mod_ptr += val_size;
141           mod_end += val_size - var_size;
142         }
143     }
144
145   mod->mod_end = (l4_addr_t)mod_end;
146 }
147
148
149 /**
150  * Handle -arg=<module_name>,blah parameter. Replace old command line
151  * parameters of <module_name> by blah. Useful for changing the boot
152  * configuration of a bootstrap image.
153  *
154  * Get a pointer to new argument and return the size.
155  */
156 char *
157 get_arg_module(char *cmdline, const char *name, unsigned *size)
158 {
159   char *val_beg = NULL, *val_end;
160   char *s = cmdline;
161
162   if (!s)
163     return 0;
164
165   while (!val_beg && (s = strstr(s, " -arg=")))
166     {
167       char *a, *name_end;
168
169       s += 6;
170       name_end = strchr(s, ',');
171       if (!name_end)
172         panic("comma missing after modname in -arg=");
173       *name_end = 0;
174
175       for (a = s; *a; a++)
176         if (isspace(*a))
177           panic("Invalid '-arg=modname,text' parameter");
178
179       // we do a fuzzy name-match here
180       if (strstr(name, s))
181         val_beg = name_end+1;
182       *name_end = ',';
183     }
184   if (!val_beg)
185     return 0;
186
187   // consider quotes
188   unsigned char quote = 0;
189   if (*val_beg == '"' || *val_beg == '\'')
190     quote = *val_beg++;
191   val_end = val_beg;
192
193   while (*val_end && ((!quote && !isspace(*val_end)) || *val_end!=quote))
194     val_end++;
195
196   *size = val_end - val_beg;
197   return val_beg;
198 }