source: tools/hotplug/module_block.c @ 28036

Last change on this file since 28036 was 26548, checked in by gost, 10 years ago

[tools] hotplug for mipsel

File size: 6.6 KB
Line 
1/*
2    module_block.c
3
4    Creates block device nodes using hotplug environment variables.
5
6    Copyright (C) 2007 Andreas Oberritter
7    Copyright (C) 2005 Greg Kroah-Hartman <greg@kroah.com>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License 2.0 as published by
11    the Free Software Foundation.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with this program; if not, write to the Free Software Foundation, Inc.,
20    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21*/
22
23#define _GNU_SOURCE     /* for getline() */
24#include <errno.h>
25#include <fcntl.h>
26#include <libgen.h>
27#include <signal.h>
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <sys/stat.h>
32#include <sys/wait.h>
33#ifndef MIPSEL
34#include "hotplug_basename.h"
35#include "hotplug_devpath.h"
36#include "hotplug_pidfile.h"
37#include "hotplug_setenv.h"
38#include "hotplug_socket.h"
39#include "hotplug_timeout.h"
40#include "module_block.h"
41#include "udev.h"
42#else
43#include <hotplug_basename.h>
44#include <hotplug_devpath.h>
45#include <hotplug_pidfile.h>
46#include <hotplug_setenv.h>
47#include <hotplug_socket.h>
48#include <hotplug_timeout.h>
49#include <module_block.h>
50#include <udev.h>
51#endif
52
53static const char *block_vars[] = {
54        "ACTION",
55        "DEVPATH",
56        "PHYSDEVPATH",
57        "PHYSDEVDRIVER",
58        "X_E2_REMOVABLE",
59        "X_E2_CDROM",
60        NULL,
61};
62
63static int bdpoll_exec(const char devpath[], bool is_cdrom, bool support_media_changed)
64{
65        pid_t pid;
66        char *argv[5];
67        unsigned int i = 0;
68
69        pid = fork();
70        if (pid == -1) {
71                perror("fork");
72                return -1;
73        } else if (pid == 0) {
74                argv[i++] = "bdpoll";
75                argv[i++] = (char *)devpath;
76                if (is_cdrom)
77                        argv[i++] = "-c";
78                if (support_media_changed)
79                        argv[i++] = "-m";
80                argv[i++] = NULL;
81                if (execvp(argv[0], argv) == -1)
82                        perror(argv[0]);
83                return -1;
84        } else {
85                return pidfile_write(pid, "bdpoll.%s", hotplug_basename(devpath));
86        }
87}
88
89static int bdpoll_kill(const char devpath[])
90{
91        struct timeout t;
92        pid_t pid, wpid;
93
94        if (pidfile_read(&pid, "bdpoll.%s", hotplug_basename(devpath)) == -1)
95                return -1;
96
97        if (kill(pid, SIGTERM) == -1) {
98                perror("kill");
99                return -1;
100        }
101
102        timeout_init(&t, 1000);
103        do {
104                wpid = waitpid(pid, NULL, WNOHANG);
105                if (wpid == -1) {
106                        perror("waitpid");
107                        return -1;
108                }
109                if (wpid > 0)
110                        goto exit;
111        } while (!timeout_exceeded(&t));
112
113        if (kill(pid, SIGKILL) == -1) {
114                perror("kill");
115                return -1;
116        }
117
118exit:
119        pidfile_unlink("bdpoll.%s", hotplug_basename(devpath));
120        return 0;
121}
122
123static int do_mknod(const char *devnode, const char *major, const char *minor)
124{
125        dev_t dev = (atoi(major) << 8) | atoi(minor);
126
127        return mknod(devnode, S_IFBLK | S_IRUSR | S_IWUSR, dev);
128}
129
130static long sysfs_attr_get_long(const char *devpath, const char *attr_name)
131{
132        char *value;
133
134        value = sysfs_attr_get_value(devpath, attr_name);
135        if (value == NULL) {
136                errno = ERANGE;
137                return LONG_MAX;
138        }
139
140        errno = 0;
141        return strtol(value, NULL, 0);
142}
143
144#define GENHD_FL_REMOVABLE                      1
145static bool dev_is_removable(const char *devpath)
146{
147        long attr;
148
149        attr = sysfs_attr_get_long(devpath, "removable");
150        if ((attr != LONG_MAX) || (errno != ERANGE))
151                return (attr != 0);
152
153        attr = sysfs_attr_get_long(devpath, "capability");
154        if ((attr != LONG_MAX) || (errno != ERANGE))
155                return (attr & GENHD_FL_REMOVABLE);
156
157        return false;
158}
159
160#define GENHD_FL_MEDIA_CHANGE_NOTIFY            4
161static bool dev_can_notify_media_change(const char *devpath)
162{
163        long attr;
164
165        attr = sysfs_attr_get_long(devpath, "capability");
166        if ((attr != LONG_MAX) || (errno != ERANGE))
167                return (attr & GENHD_FL_MEDIA_CHANGE_NOTIFY);
168
169        return false;
170}
171
172#define GENHD_FL_CD                             8
173static bool dev_is_cdrom(const char *devpath)
174{
175        char pathname[FILENAME_MAX];
176        bool ret = false;
177        const char *str;
178        char *buf = NULL;
179        size_t n = 0;
180        long attr;
181        FILE *f;
182
183        attr = sysfs_attr_get_long(devpath, "capability");
184        if ((attr != LONG_MAX) || (errno != ERANGE))
185                return (attr & GENHD_FL_CD);
186
187        str = hotplug_basename(devpath);
188
189        if (!strncmp(str, "sr", 2))
190                return 1;
191
192        if ((strlen(str) > 2) &&
193            (str[0] == 'h') &&
194            (str[1] == 'd')) {
195                snprintf(pathname, sizeof(pathname), "/proc/ide/%s/media", str);
196
197                f = fopen(pathname, "r");
198                if (f == NULL) {
199                        dbg("can't open %s: %s", pathname, strerror(errno));
200                } else {
201                        if (getline(&buf, &n, f) != -1) {
202                                if (buf != NULL) {
203                                        if (n >= 5)
204                                                ret = !strncmp(buf, "cdrom", 5);
205                                        free(buf);
206                                }
207                        }
208                        fclose(f);
209                }
210        }
211
212        return ret;
213}
214
215int block_add(void)
216{
217        char *devpath;
218        const char *minor, *major;
219        char devnode[FILENAME_MAX];
220        bool is_removable;
221        bool is_cdrom;
222        bool support_media_changed;
223
224        sysfs_init();
225
226        /*
227         * DEVPATH=/block/sda
228         * DEVPATH=/block/sda/sda1
229         */
230        devpath = getenv("DEVPATH");
231        if (!devpath) {
232                dbg("missing DEVPATH environment variable, aborting.");
233                return EXIT_FAILURE;
234        }
235
236        minor = getenv("MINOR");
237        if (!minor) {
238                dbg("missing MINOR environment variable, aborting.");
239                return EXIT_FAILURE;
240        }
241
242        major = getenv("MAJOR");
243        if (!major) {
244                dbg("missing MAJOR environment variable, aborting.");
245                return EXIT_FAILURE;
246        }
247
248        if (!hotplug_devpath_to_devnode(devpath, devnode, sizeof(devnode))) {
249                dbg("could not get device node.");
250                return EXIT_FAILURE;
251        }
252
253        unlink(devnode);
254
255        if (do_mknod(devnode, major, minor) == -1) {
256                dbg("mknod: %s", strerror(errno));
257                return EXIT_FAILURE;
258        }
259
260        is_removable = dev_is_removable(devpath);
261        is_cdrom = is_removable && dev_is_cdrom(devpath);
262        support_media_changed = is_cdrom && dev_can_notify_media_change(devpath);
263
264        if (is_removable) {
265                if (bdpoll_exec(devpath, is_cdrom, support_media_changed) == -1)
266                        dbg("could not exec bdpoll");
267        }
268
269        hotplug_setenv_bool("X_E2_REMOVABLE", is_removable);
270        hotplug_setenv_bool("X_E2_CDROM", is_cdrom);
271
272        //system("/sbin/hotplug.sh");
273        system("/sbin/hotplug.sh >> /tmp/hotplug.log 2>&1");
274        hotplug_socket_send_env(block_vars);
275
276        return EXIT_SUCCESS;
277}
278
279int block_remove(void)
280{
281        char *devpath;
282        char devnode[FILENAME_MAX];
283
284        devpath = getenv("DEVPATH");
285        if (!devpath) {
286                dbg("missing DEVPATH environment variable, aborting.");
287                return EXIT_FAILURE;
288        }
289
290        if (!hotplug_devpath_to_devnode(devpath, devnode, sizeof(devnode))) {
291                dbg("could not get device node.");
292                return EXIT_FAILURE;
293        }
294
295        unlink(devnode);
296
297        if (bdpoll_kill(devpath) == -1)
298                dbg("could not kill bdpoll");
299
300        //system("/sbin/hotplug.sh");
301        system("/sbin/hotplug.sh >> /tmp/hotplug.log 2>&1");
302        hotplug_socket_send_env(block_vars);
303
304        return EXIT_SUCCESS;
305}
306
Note: See TracBrowser for help on using the repository browser.