~ubuntu-branches/ubuntu/karmic/udev/karmic-proposed

1.1.14 by Scott James Remnant
Import upstream version 138
1
/*
2
 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3
 * Copyright (C) 2009 Canonical Ltd.
4
 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include <sys/types.h>
21
#include <errno.h>
22
#include <fcntl.h>
23
#include <stdio.h>
24
#include <dirent.h>
25
#include <stddef.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <unistd.h>
29
#include <sys/inotify.h>
30
31
#include "udev.h"
32
1.1.19 by Scott James Remnant
Import upstream version 143
33
static int inotify_fd = -1;
1.1.14 by Scott James Remnant
Import upstream version 138
34
35
/* inotify descriptor, will be shared with rules directory;
36
 * set to cloexec since we need our children to be able to add
37
 * watches for us
38
 */
1.1.19 by Scott James Remnant
Import upstream version 143
39
int udev_watch_init(struct udev *udev)
1.1.14 by Scott James Remnant
Import upstream version 138
40
{
41
	inotify_fd = inotify_init();
1.1.17 by Scott James Remnant
Import upstream version 141
42
	if (inotify_fd >= 0)
43
		util_set_fd_cloexec(inotify_fd);
1.1.14 by Scott James Remnant
Import upstream version 138
44
	else
45
		err(udev, "inotify_init failed: %m\n");
1.1.19 by Scott James Remnant
Import upstream version 143
46
	return inotify_fd;
1.1.14 by Scott James Remnant
Import upstream version 138
47
}
48
49
/* move any old watches directory out of the way, and then restore
50
 * the watches
51
 */
52
void udev_watch_restore(struct udev *udev)
53
{
54
	char filename[UTIL_PATH_SIZE], oldname[UTIL_PATH_SIZE];
55
56
	if (inotify_fd < 0)
57
		return;
58
1.1.19 by Scott James Remnant
Import upstream version 143
59
	util_strscpyl(oldname, sizeof(oldname), udev_get_dev_path(udev), "/.udev/watch.old", NULL);
60
	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/watch", NULL);
1.1.14 by Scott James Remnant
Import upstream version 138
61
	if (rename(filename, oldname) == 0) {
62
		DIR *dir;
63
		struct dirent *ent;
64
65
		dir = opendir(oldname);
66
		if (dir == NULL) {
67
			err(udev, "unable to open old watches dir '%s', old watches will not be restored: %m", oldname);
68
			return;
69
		}
70
1.1.19 by Scott James Remnant
Import upstream version 143
71
		for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
72
			char device[UTIL_PATH_SIZE];
73
			char *s;
74
			size_t l;
1.1.14 by Scott James Remnant
Import upstream version 138
75
			ssize_t len;
76
			struct udev_device *dev;
77
78
			if (ent->d_name[0] < '0' || ent->d_name[0] > '9')
79
				continue;
80
1.1.19 by Scott James Remnant
Import upstream version 143
81
			s = device;
82
			l = util_strpcpy(&s, sizeof(device), udev_get_sys_path(udev));
83
			len = readlinkat(dirfd(dir), ent->d_name, s, l);
84
			if (len <= 0 || len >= (ssize_t)l) {
85
				unlinkat(dirfd(dir), ent->d_name, 0);
1.1.14 by Scott James Remnant
Import upstream version 138
86
				continue;
87
			}
1.1.19 by Scott James Remnant
Import upstream version 143
88
			s[len] = '\0';
89
			dbg(udev, "old watch to '%s' found\n", device);
90
			dev = udev_device_new_from_syspath(udev, device);
1.1.14 by Scott James Remnant
Import upstream version 138
91
			if (dev == NULL) {
1.1.19 by Scott James Remnant
Import upstream version 143
92
				unlinkat(dirfd(dir), ent->d_name, 0);
1.1.14 by Scott James Remnant
Import upstream version 138
93
				continue;
94
			}
95
96
			info(udev, "restoring old watch on '%s'\n", udev_device_get_devnode(dev));
97
			udev_watch_begin(udev, dev);
98
99
			udev_device_unref(dev);
1.1.19 by Scott James Remnant
Import upstream version 143
100
			unlinkat(dirfd(dir), ent->d_name, 0);
1.1.14 by Scott James Remnant
Import upstream version 138
101
		}
102
103
		closedir(dir);
104
		rmdir(oldname);
105
106
	} else if (errno != ENOENT) {
107
		err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename);
108
	}
109
}
110
111
void udev_watch_begin(struct udev *udev, struct udev_device *dev)
112
{
1.1.15 by Scott James Remnant
Import upstream version 139
113
	char filename[UTIL_PATH_SIZE];
1.1.14 by Scott James Remnant
Import upstream version 138
114
	int wd;
115
116
	if (inotify_fd < 0)
117
		return;
118
126 by Scott James Remnant
* Fix inotify watch code to remove any existing watch before beginning rule
119
	info(udev, "adding watch on '%s'\n", udev_device_get_devnode(dev));
1.1.14 by Scott James Remnant
Import upstream version 138
120
	wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
121
	if (wd < 0) {
122
		err(udev, "inotify_add_watch(%d, %s, %o) failed: %m\n",
123
		    inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
147 by Scott James Remnant
FFE LP: #427356.
124
		return;
1.1.14 by Scott James Remnant
Import upstream version 138
125
	}
126
1.1.15 by Scott James Remnant
Import upstream version 139
127
	snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
1.1.14 by Scott James Remnant
Import upstream version 138
128
	util_create_path(udev, filename);
129
	unlink(filename);
1.1.16 by Scott James Remnant
Import upstream version 140
130
	symlink(udev_device_get_devpath(dev), filename);
126 by Scott James Remnant
* Fix inotify watch code to remove any existing watch before beginning rule
131
132
	udev_device_set_watch_handle(dev, wd);
133
}
134
135
void udev_watch_end(struct udev *udev, struct udev_device *dev)
136
{
137
	int wd;
1.1.15 by Scott James Remnant
Import upstream version 139
138
	char filename[UTIL_PATH_SIZE];
139
140
	if (inotify_fd < 0)
126 by Scott James Remnant
* Fix inotify watch code to remove any existing watch before beginning rule
141
		return;
142
143
	wd = udev_device_get_watch_handle(dev);
144
	if (wd < 0)
145
		return;
146
147
	info(udev, "removing watch on '%s'\n", udev_device_get_devnode(dev));
1.1.14 by Scott James Remnant
Import upstream version 138
148
	inotify_rm_watch(inotify_fd, wd);
149
1.1.15 by Scott James Remnant
Import upstream version 139
150
	snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
1.1.14 by Scott James Remnant
Import upstream version 138
151
	unlink(filename);
126 by Scott James Remnant
* Fix inotify watch code to remove any existing watch before beginning rule
152
153
	udev_device_set_watch_handle(dev, -1);
1.1.14 by Scott James Remnant
Import upstream version 138
154
}
155
126 by Scott James Remnant
* Fix inotify watch code to remove any existing watch before beginning rule
156
struct udev_device *udev_watch_lookup(struct udev *udev, int wd)
1.1.14 by Scott James Remnant
Import upstream version 138
157
{
1.1.15 by Scott James Remnant
Import upstream version 139
158
	char filename[UTIL_PATH_SIZE];
1.1.19 by Scott James Remnant
Import upstream version 143
159
	char syspath[UTIL_PATH_SIZE];
160
	char *s;
161
	size_t l;
1.1.14 by Scott James Remnant
Import upstream version 138
162
	ssize_t len;
163
164
	if (inotify_fd < 0 || wd < 0)
165
		return NULL;
166
1.1.15 by Scott James Remnant
Import upstream version 139
167
	snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
1.1.19 by Scott James Remnant
Import upstream version 143
168
	s = syspath;
169
	l = util_strpcpy(&s, sizeof(syspath), udev_get_sys_path(udev));
170
	len = readlink(filename, s, l);
171
	if (len < 0 || (size_t)len >= l)
172
		return NULL;
173
	s[len] = '\0';
174
	return udev_device_new_from_syspath(udev, syspath);
1.1.14 by Scott James Remnant
Import upstream version 138
175
}