blob: a7b789c16bbcc9f350a2d902fe0b90b22ad6adab [file] [log] [blame]
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001
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 <errno.h>
21#include <dirent.h>
22#include <unistd.h>
23
24#include <sys/types.h>
25#include <sys/inotify.h>
26#include <sys/stat.h>
27
28#include "vold.h"
29#include "inotify.h"
30#include "blkdev.h"
31#include "volmgr.h"
32
33#define DEBUG_INOTIFY 0
34
35static int handle_inotify_event(struct inotify_event *evt);
36
37int process_inotify_event(int fd)
38{
39 char buffer[512];
40 int len;
41 int offset = 0;
42
43 if ((len = read(fd, buffer, sizeof(buffer))) < 0) {
44 LOGE("Unable to read inotify event (%m)\n");
45 return -errno;
46 }
47
48 while (len >= (int) sizeof(struct inotify_event)) {
49 struct inotify_event *evt = (struct inotify_event *) &buffer[offset];
50
51 if (handle_inotify_event(evt) < 0)
52 LOGE("Error handling inotify event (%m)\n");
53
54 len -= sizeof(struct inotify_event) + evt->len;
55 offset += sizeof(struct inotify_event) + evt->len;
56
57 }
58 return 0;
59}
60
61struct blk_dev_entry {
62 int minor;
63 char *name;
64 struct blk_dev_entry *next;
65};
66
67int inotify_bootstrap(void)
68{
69 DIR *d;
70 struct dirent *de;
71
72 if (!(d = opendir(DEVPATH))) {
73 LOGE("Unable to open directory '%s' (%m)\n", DEVPATH);
74 return -errno;
75 }
76
77 struct blk_dev_entry *blkdevs[255];
78
79 memset(blkdevs, 0, sizeof(blkdevs));
80
81 while((de = readdir(d))) {
82 char filename[255];
83 struct stat sbuf;
84
85 if (de->d_name[0] == '.')
86 continue;
87
88 sprintf(filename, "%s/%s", DEVPATH, de->d_name);
89
90 if (stat(filename, &sbuf) < 0) {
91 LOGE("Unable to stat '%s' (%m)\n", filename);
92 continue;
93 }
94
95 if (!S_ISBLK(sbuf.st_mode))
96 continue;
97
98
99 int major = (sbuf.st_rdev & 0xfff00) >> 8;
100 int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
101
102 struct blk_dev_entry *entry;
103
104 if (!(entry = malloc(sizeof(struct blk_dev_entry)))) {
105 LOGE("Out of memory\n");
106 break;
107 }
108 entry->minor = minor;
109 entry->name = strdup(de->d_name);
110 entry->next = NULL;
111
112 if (!blkdevs[major])
113 blkdevs[major] = entry;
114 else {
115 struct blk_dev_entry *scan = blkdevs[major];
116
117 /*
118 * Insert the entry in minor number ascending order
119 */
120 while(scan) {
121 if (minor < scan->minor) {
122 entry->next = scan;
123
124 if (scan == blkdevs[major])
125 blkdevs[major] = entry;
126 else
127 scan->next = entry;
128 break;
129 }
130 scan = scan->next;
131 }
132 if (!scan) {
133 scan = blkdevs[major];
134 while(scan->next)
135 scan = scan->next;
136 scan->next = entry;
137 }
138 }
139
140 }
141
142 closedir(d);
143
144 int i = 0;
145
146 for (i = 0; i < 255; i++) {
147 if (!blkdevs[i])
148 continue;
149 struct blk_dev_entry *scan = blkdevs[i];
150
151 while(scan) {
152 struct inotify_event *evt;
153 int len;
154
155 len = sizeof(struct inotify_event) + strlen(scan->name);
156
157 if (!(evt = malloc(len))) {
158 LOGE("Out of memory\n");
159 break;
160 }
161 memset(evt, 0, len);
162 strcpy(evt->name, scan->name);
163 evt->mask = IN_CREATE;
164
165 if (handle_inotify_event(evt) < 0)
166 LOGE("Error handling bootstrapped inotify event (%m)\n");
167 free(evt);
168
169 scan = scan->next;
170 }
171 }
172
173 for (i = 0; i < 255; i++) {
174 if (!blkdevs[i])
175 continue;
176
177 if (!blkdevs[i]->next) {
178 free(blkdevs[i]->name);
179 free(blkdevs[i]);
180 blkdevs[i] = NULL;
181 continue;
182 }
183
184 struct blk_dev_entry *scan = blkdevs[i];
185 while(scan) {
186 struct blk_dev_entry *next = scan->next->next;
187
188 free(scan->next->name);
189 free(scan->next);
190
191 scan->next = next;
192 scan = next;
193 }
194
195 } // for
196
197
198 return 0;
199}
200
201static int handle_inotify_event(struct inotify_event *evt)
202{
203 char filename[255];
204 int rc;
205
206#if DEBUG_INOTIFY
207 LOG_VOL("Inotify '%s' %s\n", evt->name, (evt->mask == IN_CREATE ? "created" : "deleted"));
208#endif
209
210 sprintf(filename, "%s%s", DEVPATH, evt->name);
211
212 if (evt->mask == IN_CREATE) {
213 struct stat sbuf;
214
215 if (stat(filename, &sbuf) < 0) {
216 LOGE("Unable to stat '%s' (%m)\n", filename);
217 return -errno;
218 }
219
220 if (!S_ISBLK(sbuf.st_mode)) {
221#if DEBUG_INOTIFY
222 LOG_VOL("Ignoring inotify on '%s' (not a block device)\n", evt->name);
223#endif
224 return 0;
225 }
226
227 int major = (sbuf.st_rdev & 0xfff00) >> 8;
228 int minor = (sbuf.st_rdev & 0xff) | ((sbuf.st_rdev >> 12) & 0xfff00);
229
230 blkdev_t *blkdev = blkdev_lookup_by_devno(major, minor);
231
232 if ((rc = blkdev_handle_devicefile_created(blkdev, filename)) < 0) {
233 LOGE("Error handling device file '%s' creation (%s)\n", filename, strerror(rc));
234 return rc;
235 }
236
237 if (!blkdev) {
238#if DEBUG_INOTIFY
239 LOG_VOL("No backing blkdev for '%s' available (yet) - pending volmgr dispatch\n", filename);
240#endif
241 return 0;
242 }
243
244#if DEBUG_INOTIFY
245 LOG_VOL("NUM_PENDING_PARTITIONS = %d\n", blkdev_get_num_pending_partitions(blkdev));
246#endif
247 if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
248 if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
249 LOGE("Error from volmgr - %d\n", rc);
250 return rc;
251 }
252 }
253 } else {
254 blkdev_t *blkdev;
255
256 if (!(blkdev = blkdev_lookup_by_dev_fspath(filename))) {
257#if DEBUG_INOTIFY
258 LOG_VOL("Ignoring removal of '%s' (no backend blkdev)\n", filename);
259#endif
260 return 0;
261 }
262
263 if ((rc = blkdev_handle_devicefile_removed(blkdev, filename)) < 0) {
264 LOGE("Error handling device file '%s' removal (%s)\n", filename, strerror(rc));
265 return rc;
266 }
267 }
268
269 return 0;
270}