source: tools/hotplug/module_block.c @ 5930

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

add hotplug changes and portscan source

File size: 6.3 KB
RevLine 
[5930]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        hotplug_socket_send_env(block_vars);
263
264        return EXIT_SUCCESS;
265}
266
267int block_remove(void)
268{
269        char *devpath;
270        char devnode[FILENAME_MAX];
271
272        devpath = getenv("DEVPATH");
273        if (!devpath) {
274                dbg("missing DEVPATH environment variable, aborting.");
275                return EXIT_FAILURE;
276        }
277
278        if (!hotplug_devpath_to_devnode(devpath, devnode, sizeof(devnode))) {
279                dbg("could not get device node.");
280                return EXIT_FAILURE;
281        }
282
283        unlink(devnode);
284
285        if (bdpoll_kill(devpath) == -1)
286                dbg("could not kill bdpoll");
287
288        system("/sbin/hotplug.sh");
289        hotplug_socket_send_env(block_vars);
290
291        return EXIT_SUCCESS;
292}
293
Note: See TracBrowser for help on using the repository browser.