aboutsummaryrefslogtreecommitdiffstats
path: root/init/initramfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'init/initramfs.c')
-rw-r--r--init/initramfs.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/init/initramfs.c b/init/initramfs.c
index f81cfa40a719..d28c1094d7e5 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -30,6 +30,7 @@ static void __init free(void *where)
30 30
31static __initdata struct hash { 31static __initdata struct hash {
32 int ino, minor, major; 32 int ino, minor, major;
33 mode_t mode;
33 struct hash *next; 34 struct hash *next;
34 char name[N_ALIGN(PATH_MAX)]; 35 char name[N_ALIGN(PATH_MAX)];
35} *head[32]; 36} *head[32];
@@ -41,7 +42,8 @@ static inline int hash(int major, int minor, int ino)
41 return tmp & 31; 42 return tmp & 31;
42} 43}
43 44
44static char __init *find_link(int major, int minor, int ino, char *name) 45static char __init *find_link(int major, int minor, int ino,
46 mode_t mode, char *name)
45{ 47{
46 struct hash **p, *q; 48 struct hash **p, *q;
47 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { 49 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
@@ -51,14 +53,17 @@ static char __init *find_link(int major, int minor, int ino, char *name)
51 continue; 53 continue;
52 if ((*p)->major != major) 54 if ((*p)->major != major)
53 continue; 55 continue;
56 if (((*p)->mode ^ mode) & S_IFMT)
57 continue;
54 return (*p)->name; 58 return (*p)->name;
55 } 59 }
56 q = (struct hash *)malloc(sizeof(struct hash)); 60 q = (struct hash *)malloc(sizeof(struct hash));
57 if (!q) 61 if (!q)
58 panic("can't allocate link hash entry"); 62 panic("can't allocate link hash entry");
59 q->ino = ino;
60 q->minor = minor;
61 q->major = major; 63 q->major = major;
64 q->minor = minor;
65 q->ino = ino;
66 q->mode = mode;
62 strcpy(q->name, name); 67 strcpy(q->name, name);
63 q->next = NULL; 68 q->next = NULL;
64 *p = q; 69 *p = q;
@@ -229,13 +234,25 @@ static int __init do_reset(void)
229static int __init maybe_link(void) 234static int __init maybe_link(void)
230{ 235{
231 if (nlink >= 2) { 236 if (nlink >= 2) {
232 char *old = find_link(major, minor, ino, collected); 237 char *old = find_link(major, minor, ino, mode, collected);
233 if (old) 238 if (old)
234 return (sys_link(old, collected) < 0) ? -1 : 1; 239 return (sys_link(old, collected) < 0) ? -1 : 1;
235 } 240 }
236 return 0; 241 return 0;
237} 242}
238 243
244static void __init clean_path(char *path, mode_t mode)
245{
246 struct stat st;
247
248 if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) {
249 if (S_ISDIR(st.st_mode))
250 sys_rmdir(path);
251 else
252 sys_unlink(path);
253 }
254}
255
239static __initdata int wfd; 256static __initdata int wfd;
240 257
241static int __init do_name(void) 258static int __init do_name(void)
@@ -248,9 +265,15 @@ static int __init do_name(void)
248 } 265 }
249 if (dry_run) 266 if (dry_run)
250 return 0; 267 return 0;
268 clean_path(collected, mode);
251 if (S_ISREG(mode)) { 269 if (S_ISREG(mode)) {
252 if (maybe_link() >= 0) { 270 int ml = maybe_link();
253 wfd = sys_open(collected, O_WRONLY|O_CREAT, mode); 271 if (ml >= 0) {
272 int openflags = O_WRONLY|O_CREAT;
273 if (ml != 1)
274 openflags |= O_TRUNC;
275 wfd = sys_open(collected, openflags, mode);
276
254 if (wfd >= 0) { 277 if (wfd >= 0) {
255 sys_fchown(wfd, uid, gid); 278 sys_fchown(wfd, uid, gid);
256 sys_fchmod(wfd, mode); 279 sys_fchmod(wfd, mode);
@@ -291,6 +314,7 @@ static int __init do_copy(void)
291static int __init do_symlink(void) 314static int __init do_symlink(void)
292{ 315{
293 collected[N_ALIGN(name_len) + body_len] = '\0'; 316 collected[N_ALIGN(name_len) + body_len] = '\0';
317 clean_path(collected, 0);
294 sys_symlink(collected + N_ALIGN(name_len), collected); 318 sys_symlink(collected + N_ALIGN(name_len), collected);
295 sys_lchown(collected, uid, gid); 319 sys_lchown(collected, uid, gid);
296 state = SkipIt; 320 state = SkipIt;