mount_root: code failed in failsafe
[project/fstools.git] / libfstools / ext4.c
1 /*
2  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17
18 #include <sys/mount.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <asm/byteorder.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <mtd/mtd-user.h>
27 #include <glob.h>
28
29 #include "libfstools.h"
30
31 #include "volume.h"
32
33 #define ext4_sysfs_path "/sys/block/mmcblk*/mmcblk*/uevent"
34 #define MAX_SIZE        128
35
36 #define EXT_SB_OFF      0x400
37 #define EXT_SB_KBOFF    (EXT_SB_OFF >> 10)
38 #define EXT_SB_MAGIC    "\123\357"
39 #define EXT_MAG_OFF     0x38
40
41 struct ext4_priv {
42         char    *name;
43         char    *devname;
44 };
45
46 static struct driver ext4_driver;
47
48 static int ext4_volume_init(struct volume *v)
49 {
50         char buf[MAX_SIZE];
51         struct ext4_priv *p;
52
53         p = (struct ext4_priv*)v->priv;
54         snprintf(buf, sizeof(buf), "/dev/%s",p->devname);
55
56         v->name = strdup(p->name);
57         v->type = EXT4VOLUME;
58         v->blk = strdup(buf);
59         return 0;
60 }
61
62 static int
63 ext4_part_match(char *dev, char *name, char *filename)
64 {
65         FILE *fp;
66         char buf[MAX_SIZE];
67         char devname[MAX_SIZE];
68         int i;
69         int ret = -1;
70
71         fp = fopen(filename, "r");
72         if (!fp)
73                 return ret;
74
75         while (fgets(buf, sizeof(buf), fp))  {
76                 if (strstr(buf, "DEVNAME"))  {
77                         strcpy(devname, buf + strlen("DEVNAME="));
78                         continue;
79                 }
80                 /* Match partition name */
81                 if (strstr(buf, name))  {
82                         ret = 0;
83                         break;
84                 }
85         }
86
87         fclose(fp);
88
89         /* make sure the string is \0 terminated */
90         devname[sizeof(devname) - 1] = '\0';
91
92         /* remove trailing whitespace */
93         i = strlen(devname) - 1;
94         while (i > 0 && devname[i] <= ' ')
95                 devname[i--] = '\0';
96
97         strcpy(dev, devname);
98         return ret;
99 }
100
101 static int ext4_find_devname(char *dev, char *name)
102 {
103         int i;
104         glob_t gl;
105
106         if (glob(ext4_sysfs_path, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl) < 0)
107                 return -1;
108
109         for (i = 0; i < gl.gl_pathc; i++) {
110                 if (!ext4_part_match(dev, name, gl.gl_pathv[i])) {
111                         globfree(&gl);
112                         return 0;
113                 }
114         }
115
116         globfree(&gl);
117         return -1;
118 }
119
120 static int check_for_mtd(const char *mtd)
121 {
122         FILE *fp;
123         char dev[MAX_SIZE];
124
125         if ((fp = fopen("/proc/mtd", "r"))) {
126                 while (fgets(dev, sizeof(dev), fp)) {
127                         if (strstr(dev, mtd)) {
128                                 fclose(fp);
129                                 return -1;
130                         }
131                 }
132         }
133         fclose(fp);
134         return 0;
135 }
136
137 static int ext4_volume_find(struct volume *v, char *name)
138 {
139         char buf[MAX_SIZE];
140         struct ext4_priv *p;
141
142         if (find_filesystem("ext4"))
143                 return -1;
144
145         if (check_for_mtd(name))
146                 return -1;
147
148         if (ext4_find_devname(buf, name))
149                 return -1;
150
151         p = calloc(1, sizeof(struct ext4_priv));
152         if (!p)
153                 return -1;
154
155         v->priv = p;
156         v->drv = &ext4_driver;
157
158         p->devname = strdup(buf);
159         p->name = strdup(name);
160         return ext4_volume_init(v);
161 }
162
163 static int ext4_volume_identify(struct volume *v)
164 {
165         char magic[32] = { 0 };
166         int off = (EXT_SB_KBOFF * 1024) + EXT_MAG_OFF;
167         int fd;
168
169         fd = open(v->blk, O_RDONLY);
170         if (fd == -1)
171                 return -1;
172
173         lseek(fd, off, SEEK_SET);
174         read(fd, magic, sizeof(EXT_SB_MAGIC) - 1);
175         close(fd);
176
177         if (v->type == EXT4VOLUME &&
178             !memcmp(EXT_SB_MAGIC, magic, sizeof(EXT_SB_MAGIC) - 1)) {
179                 return FS_EXT4FS;
180         }
181
182         ULOG_ERR("ext4 is not ready - marker found\n");
183         return FS_DEADCODE;
184 }
185
186 static struct driver ext4_driver = {
187         .name = "ext4",
188         .find = ext4_volume_find,
189         .init = ext4_volume_init,
190         .identify = ext4_volume_identify,
191 };
192
193 DRIVER(ext4_driver);