1
2 /*
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <dirent.h>
21 #include <errno.h>
22
23 #include <sys/types.h>
24
25 #include "vold.h"
26 #include "mmc.h"
27 #include "media.h"
28
29 #define DEBUG_BOOTSTRAP 0
30
31 static int mmc_bootstrap_controller(char *sysfs_path);
32 static int mmc_bootstrap_card(char *sysfs_path);
33 static int mmc_bootstrap_block(char *devpath);
34 static int mmc_bootstrap_mmcblk(char *devpath);
35 static int mmc_bootstrap_mmcblk_partition(char *devpath);
36
37 /*
38 * Bootstrap our mmc information.
39 */
mmc_bootstrap()40 int mmc_bootstrap()
41 {
42 DIR *d;
43 struct dirent *de;
44
45 if (!(d = opendir(SYSFS_CLASS_MMC_PATH))) {
46 LOG_ERROR("Unable to open '%s' (%s)", SYSFS_CLASS_MMC_PATH,
47 strerror(errno));
48 return -errno;
49 }
50
51 while ((de = readdir(d))) {
52 char tmp[255];
53
54 if (de->d_name[0] == '.')
55 continue;
56
57 sprintf(tmp, "%s/%s", SYSFS_CLASS_MMC_PATH, de->d_name);
58 if (mmc_bootstrap_controller(tmp)) {
59 LOG_ERROR("Error bootstrapping controller '%s' (%s)", tmp,
60 strerror(errno));
61 }
62 }
63
64 closedir(d);
65
66 return 0;
67 }
68
mmc_bootstrap_controller(char * sysfs_path)69 static int mmc_bootstrap_controller(char *sysfs_path)
70 {
71 DIR *d;
72 struct dirent *de;
73
74 #if DEBUG_BOOTSTRAP
75 LOG_VOL("bootstrap_controller(%s):", sysfs_path);
76 #endif
77 if (!(d = opendir(sysfs_path))) {
78 LOG_ERROR("Unable to open '%s' (%s)", sysfs_path, strerror(errno));
79 return -errno;
80 }
81
82 while ((de = readdir(d))) {
83 char tmp[255];
84
85 if (de->d_name[0] == '.')
86 continue;
87
88 if ((!strcmp(de->d_name, "uevent")) ||
89 (!strcmp(de->d_name, "subsystem")) ||
90 (!strcmp(de->d_name, "device")) ||
91 (!strcmp(de->d_name, "power"))) {
92 continue;
93 }
94
95 sprintf(tmp, "%s/%s", sysfs_path, de->d_name);
96
97 if (mmc_bootstrap_card(tmp) < 0)
98 LOG_ERROR("Error bootstrapping card '%s' (%s)", tmp, strerror(errno));
99 } // while
100
101 closedir(d);
102 return 0;
103 }
104
mmc_bootstrap_card(char * sysfs_path)105 static int mmc_bootstrap_card(char *sysfs_path)
106 {
107 char saved_cwd[255];
108 char new_cwd[255];
109 char *devpath;
110 char *uevent_params[4];
111 char *p;
112 char filename[255];
113 char tmp[255];
114 ssize_t sz;
115
116 #if DEBUG_BOOTSTRAP
117 LOG_VOL("bootstrap_card(%s):", sysfs_path);
118 #endif
119
120 /*
121 * sysfs_path is based on /sys/class, but we want the actual device class
122 */
123 if (!getcwd(saved_cwd, sizeof(saved_cwd))) {
124 LOGE("Error getting working dir path");
125 return -errno;
126 }
127
128 if (chdir(sysfs_path) < 0) {
129 LOGE("Unable to chdir to %s (%s)", sysfs_path, strerror(errno));
130 return -errno;
131 }
132
133 if (!getcwd(new_cwd, sizeof(new_cwd))) {
134 LOGE("Buffer too small for device path");
135 return -errno;
136 }
137
138 if (chdir(saved_cwd) < 0) {
139 LOGE("Unable to restore working dir");
140 return -errno;
141 }
142
143 devpath = &new_cwd[4]; // Skip over '/sys'
144
145 /*
146 * Collect parameters so we can simulate a UEVENT
147 */
148 sprintf(tmp, "DEVPATH=%s", devpath);
149 uevent_params[0] = (char *) strdup(tmp);
150
151 sprintf(filename, "/sys%s/type", devpath);
152 p = read_file(filename, &sz);
153 p[strlen(p) - 1] = '\0';
154 sprintf(tmp, "MMC_TYPE=%s", p);
155 free(p);
156 uevent_params[1] = (char *) strdup(tmp);
157
158 sprintf(filename, "/sys%s/name", devpath);
159 p = read_file(filename, &sz);
160 p[strlen(p) - 1] = '\0';
161 sprintf(tmp, "MMC_NAME=%s", p);
162 free(p);
163 uevent_params[2] = (char *) strdup(tmp);
164
165 uevent_params[3] = (char *) NULL;
166
167 if (simulate_uevent("mmc", devpath, "add", uevent_params) < 0) {
168 LOGE("Error simulating uevent (%s)", strerror(errno));
169 return -errno;
170 }
171
172 /*
173 * Check for block drivers
174 */
175 char block_devpath[255];
176 sprintf(tmp, "%s/block", devpath);
177 sprintf(filename, "/sys%s/block", devpath);
178 if (!access(filename, F_OK)) {
179 if (mmc_bootstrap_block(tmp)) {
180 LOGE("Error bootstrapping block @ %s", tmp);
181 }
182 }
183
184 return 0;
185 }
186
mmc_bootstrap_block(char * devpath)187 static int mmc_bootstrap_block(char *devpath)
188 {
189 char blockdir_path[255];
190 DIR *d;
191 struct dirent *de;
192
193 #if DEBUG_BOOTSTRAP
194 LOG_VOL("mmc_bootstrap_block(%s):", devpath);
195 #endif
196
197 sprintf(blockdir_path, "/sys%s", devpath);
198
199 if (!(d = opendir(blockdir_path))) {
200 LOGE("Failed to opendir %s", devpath);
201 return -errno;
202 }
203
204 while ((de = readdir(d))) {
205 char tmp[255];
206
207 if (de->d_name[0] == '.')
208 continue;
209 sprintf(tmp, "%s/%s", devpath, de->d_name);
210 if (mmc_bootstrap_mmcblk(tmp))
211 LOGE("Error bootstraping mmcblk @ %s", tmp);
212 }
213 closedir(d);
214 return 0;
215 }
216
mmc_bootstrap_mmcblk(char * devpath)217 static int mmc_bootstrap_mmcblk(char *devpath)
218 {
219 char *mmcblk_devname;
220 int part_no;
221 int rc;
222
223 #if DEBUG_BOOTSTRAP
224 LOG_VOL("mmc_bootstrap_mmcblk(%s):", devpath);
225 #endif
226
227 if ((rc = mmc_bootstrap_mmcblk_partition(devpath))) {
228 LOGE("Error bootstrapping mmcblk partition '%s'", devpath);
229 return rc;
230 }
231
232 for (mmcblk_devname = &devpath[strlen(devpath)];
233 *mmcblk_devname != '/'; mmcblk_devname--);
234 mmcblk_devname++;
235
236 for (part_no = 0; part_no < 4; part_no++) {
237 char part_file[255];
238 sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
239 if (!access(part_file, F_OK)) {
240 char part_devpath[255];
241
242 sprintf(part_devpath, "%s/%sp%d", devpath, mmcblk_devname, part_no);
243 if (mmc_bootstrap_mmcblk_partition(part_devpath))
244 LOGE("Error bootstrapping mmcblk partition '%s'", part_devpath);
245 }
246 }
247
248 return 0;
249 }
250
mmc_bootstrap_mmcblk_partition(char * devpath)251 static int mmc_bootstrap_mmcblk_partition(char *devpath)
252 {
253 char filename[255];
254 char *uevent_buffer;
255 ssize_t sz;
256 char *uevent_params[4];
257 char tmp[255];
258 FILE *fp;
259 char line[255];
260
261 #if DEBUG_BOOTSTRAP
262 LOG_VOL("mmc_bootstrap_mmcblk_partition(%s):", devpath);
263 #endif
264
265 sprintf(tmp, "DEVPATH=%s", devpath);
266 uevent_params[0] = strdup(tmp);
267
268 sprintf(filename, "/sys%s/uevent", devpath);
269 if (!(fp = fopen(filename, "r"))) {
270 LOGE("Unable to open '%s' (%s)", filename, strerror(errno));
271 return -errno;
272 }
273
274 while (fgets(line, sizeof(line), fp)) {
275 line[strlen(line)-1] = 0;
276 if (!strncmp(line, "DEVTYPE=", 8))
277 uevent_params[1] = strdup(line);
278 else if (!strncmp(line, "MAJOR=",6))
279 uevent_params[2] = strdup(line);
280 else if (!strncmp(line, "MINOR=",6))
281 uevent_params[3] = strdup(line);
282 }
283 fclose(fp);
284
285 if (!uevent_params[1] || !uevent_params[2] || !uevent_params[3]) {
286 LOGE("mmcblk uevent missing required params");
287 return -1;
288 }
289 uevent_params[4] = '\0';
290
291 if (simulate_uevent("block", devpath, "add", uevent_params) < 0) {
292 LOGE("Error simulating uevent (%s)", strerror(errno));
293 return -errno;
294 }
295 return 0;
296 }
297