source: tools/hotplug/module_block.c @ 24995

Last change on this file since 24995 was 6963, checked in by nit, 13 years ago

add full debug to hotplug (see /tmp/hotplug.log)

File size: 6.4 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#include "hotplug_basename.h"
34#include "hotplug_devpath.h"
35#include "hotplug_pidfile.h"
36#include "hotplug_setenv.h"
37#include "hotplug_socket.h"
38#include "hotplug_timeout.h"
39#include "module_block.h"
40#include "udev.h"
41
42static const char *block_vars[] = {
43        "ACTION",
44        "DEVPATH",
45        "PHYSDEVPATH",
46        "PHYSDEVDRIVER",
47        "X_E2_REMOVABLE",
48        "X_E2_CDROM",
49        NULL,
50};
51
52static int bdpoll_exec(const char devpath[], bool is_cdrom, bool support_media_changed)
53{
54        pid_t pid;
55        char *argv[5];
56        unsigned int i = 0;
57
58        pid = fork();
59        if (pid == -1) {
60                perror("fork");
61                return -1;
62        } else if (pid == 0) {
63                argv[i++] = "bdpoll";
64                argv[i++] = (char *)devpath;
65                if (is_cdrom)
66                        argv[i++] = "-c";
67                if (support_media_changed)
68                        argv[i++] = "-m";
69                argv[i++] = NULL;
70                if (execvp(argv[0], argv) == -1)
71                        perror(argv[0]);
72                return -1;
73        } else {
74                return pidfile_write(pid, "bdpoll.%s", hotplug_basename(devpath));
75        }
76}
77
78static int bdpoll_kill(const char devpath[])
79{
80        struct timeout t;
81        pid_t pid, wpid;
82
83        if (pidfile_read(&pid, "bdpoll.%s", hotplug_basename(devpath)) == -1)
84                return -1;
85
86        if (kill(pid, SIGTERM) == -1) {
87                perror("kill");
88                return -1;
89        }
90
91        timeout_init(&t, 1000);
92        do {
93                wpid = waitpid(pid, NULL, WNOHANG);
94                if (wpid == -1) {
95                        perror("waitpid");
96                        return -1;
97                }
98                if (wpid > 0)
99                        goto exit;
100        } while (!timeout_exceeded(&t));
101
102        if (kill(pid, SIGKILL) == -1) {
103                perror("kill");
104                return -1;
105        }
106
107exit:
108        pidfile_unlink("bdpoll.%s", hotplug_basename(devpath));
109        return 0;
110}
111
112static int do_mknod(const char *devnode, const char *major, const char *minor)
113{
114        dev_t dev = (atoi(major) << 8) | atoi(minor);
115
116        return mknod(devnode, S_IFBLK | S_IRUSR | S_IWUSR, dev);
117}
118
119static long sysfs_attr_get_long(const char *devpath, const char *attr_name)
120{
121        char *value;
122
123        value = sysfs_attr_get_value(devpath, attr_name);
124        if (value == NULL) {
125                errno = ERANGE;
126                return LONG_MAX;
127        }
128
129        errno = 0;
130        return strtol(value, NULL, 0);
131}
132
133#define GENHD_FL_REMOVABLE                      1
134static bool dev_is_removable(const char *devpath)
135{
136        long attr;
137
138        attr = sysfs_attr_get_long(devpath, "removable");
139        if ((attr != LONG_MAX) || (errno != ERANGE))
140                return (attr != 0);
141
142        attr = sysfs_attr_get_long(devpath, "capability");
143        if ((attr != LONG_MAX) || (errno != ERANGE))
144                return (attr & GENHD_FL_REMOVABLE);
145
146        return false;
147}
148
149#define GENHD_FL_MEDIA_CHANGE_NOTIFY            4
150static bool dev_can_notify_media_change(const char *devpath)
151{
152        long attr;
153
154        attr = sysfs_attr_get_long(devpath, "capability");
155        if ((attr != LONG_MAX) || (errno != ERANGE))
156                return (attr & GENHD_FL_MEDIA_CHANGE_NOTIFY);
157
158        return false;
159}
160
161#define GENHD_FL_CD                             8
162static bool dev_is_cdrom(const char *devpath)
163{
164        char pathname[FILENAME_MAX];
165        bool ret = false;
166        const char *str;
167        char *buf = NULL;
168        size_t n = 0;
169        long attr;
170        FILE *f;
171
172        attr = sysfs_attr_get_long(devpath, "capability");
173        if ((attr != LONG_MAX) || (errno != ERANGE))
174                return (attr & GENHD_FL_CD);
175
176        str = hotplug_basename(devpath);
177
178        if (!strncmp(str, "sr", 2))
179                return 1;
180
181        if ((strlen(str) > 2) &&
182            (str[0] == 'h') &&
183            (str[1] == 'd')) {
184                snprintf(pathname, sizeof(pathname), "/proc/ide/%s/media", str);
185
186                f = fopen(pathname, "r");
187                if (f == NULL) {
188                        dbg("can't open %s: %s", pathname, strerror(errno));
189                } else {
190                        if (getline(&buf, &n, f) != -1) {
191                                if (buf != NULL) {
192                                        if (n >= 5)
193                                                ret = !strncmp(buf, "cdrom", 5);
194                                        free(buf);
195                                }
196                        }
197                        fclose(f);
198                }
199        }
200
201        return ret;
202}
203
204int block_add(void)
205{
206        char *devpath;
207        const char *minor, *major;
208        char devnode[FILENAME_MAX];
209        bool is_removable;
210        bool is_cdrom;
211        bool support_media_changed;
212
213        sysfs_init();
214
215        /*
216         * DEVPATH=/block/sda
217         * DEVPATH=/block/sda/sda1
218         */
219        devpath = getenv("DEVPATH");
220        if (!devpath) {
221                dbg("missing DEVPATH environment variable, aborting.");
222                return EXIT_FAILURE;
223        }
224
225        minor = getenv("MINOR");
226        if (!minor) {
227                dbg("missing MINOR environment variable, aborting.");
228                return EXIT_FAILURE;
229        }
230
231        major = getenv("MAJOR");
232        if (!major) {
233                dbg("missing MAJOR environment variable, aborting.");
234                return EXIT_FAILURE;
235        }
236
237        if (!hotplug_devpath_to_devnode(devpath, devnode, sizeof(devnode))) {
238                dbg("could not get device node.");
239                return EXIT_FAILURE;
240        }
241
242        unlink(devnode);
243
244        if (do_mknod(devnode, major, minor) == -1) {
245                dbg("mknod: %s", strerror(errno));
246                return EXIT_FAILURE;
247        }
248
249        is_removable = dev_is_removable(devpath);
250        is_cdrom = is_removable && dev_is_cdrom(devpath);
251        support_media_changed = is_cdrom && dev_can_notify_media_change(devpath);
252
253        if (is_removable) {
254                if (bdpoll_exec(devpath, is_cdrom, support_media_changed) == -1)
255                        dbg("could not exec bdpoll");
256        }
257
258        hotplug_setenv_bool("X_E2_REMOVABLE", is_removable);
259        hotplug_setenv_bool("X_E2_CDROM", is_cdrom);
260
261        //system("/sbin/hotplug.sh");
262        system("/sbin/hotplug.sh >> /tmp/hotplug.log 2>&1");
263        hotplug_socket_send_env(block_vars);
264
265        return EXIT_SUCCESS;
266}
267
268int block_remove(void)
269{
270        char *devpath;
271        char devnode[FILENAME_MAX];
272
273        devpath = getenv("DEVPATH");
274        if (!devpath) {
275                dbg("missing DEVPATH environment variable, aborting.");
276                return EXIT_FAILURE;
277        }
278
279        if (!hotplug_devpath_to_devnode(devpath, devnode, sizeof(devnode))) {
280                dbg("could not get device node.");
281                return EXIT_FAILURE;
282        }
283
284        unlink(devnode);
285
286        if (bdpoll_kill(devpath) == -1)
287                dbg("could not kill bdpoll");
288
289        //system("/sbin/hotplug.sh");
290        system("/sbin/hotplug.sh >> /tmp/hotplug.log 2>&1");
291        hotplug_socket_send_env(block_vars);
292
293        return EXIT_SUCCESS;
294}
295
Note: See TracBrowser for help on using the repository browser.