]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/inotify.c
1 /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <sys/inotify.h>
22 /* the strategy is to set a inotify on the directories containing
23 resolv files, for any files in the directory which are close-write
24 or moved into the directory.
26 When either of those happen, we look to see if the file involved
27 is actually a resolv-file, and if so, call poll-resolv with
28 the "force" argument, to ensure it's read.
30 This adds one new error condition: the directories containing
31 all specified resolv-files must exist at start-up, even if the actual
35 static char *inotify_buffer
;
36 #define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
38 void inotify_dnsmasq_init()
42 inotify_buffer
= safe_malloc(INOTIFY_SZ
);
43 daemon
->inotifyfd
= inotify_init1(IN_NONBLOCK
| IN_CLOEXEC
);
45 if (daemon
->inotifyfd
== -1)
46 die(_("failed to create inotify: %s"), NULL
, EC_MISC
);
48 for (res
= daemon
->resolv_files
; res
; res
= res
->next
)
50 char *d
= NULL
, *path
;
52 if (!(path
= realpath(res
->name
, NULL
)))
54 /* realpath will fail if the file doesn't exist, but
55 dnsmasq copes with missing files, so fall back
56 and assume that symlinks are not in use in that case. */
60 die(_("cannot cannonicalise resolv-file %s: %s"), res
->name
, EC_MISC
);
63 if ((d
= strrchr(path
, '/')))
65 *d
= 0; /* make path just directory */
66 res
->wd
= inotify_add_watch(daemon
->inotifyfd
, path
, IN_CLOSE_WRITE
| IN_MOVED_TO
);
68 res
->file
= d
+1; /* pointer to filename */
71 if (res
->wd
== -1 && errno
== ENOENT
)
72 die(_("directory %s for resolv-file is missing, cannot poll"), res
->name
, EC_MISC
);
75 die(_("failed to create inotify for %s: %s"), res
->name
, EC_MISC
);
81 /* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
82 void set_dynamic_inotify(int flag
, int total_size
, struct crec
**rhash
, int revhashsz
)
86 for (ah
= daemon
->dynamic_dirs
; ah
; ah
= ah
->next
)
88 DIR *dir_stream
= NULL
;
92 if (!(ah
->flags
& flag
))
95 if (stat(ah
->fname
, &buf
) == -1 || !(S_ISDIR(buf
.st_mode
)))
97 my_syslog(LOG_ERR
, _("bad dynamic directory %s: %s"),
98 ah
->fname
, strerror(errno
));
102 if (!(ah
->flags
& AH_WD_DONE
))
104 ah
->wd
= inotify_add_watch(daemon
->inotifyfd
, ah
->fname
, IN_CLOSE_WRITE
| IN_MOVED_TO
);
105 ah
->flags
|= AH_WD_DONE
;
107 /* Read contents of dir _after_ calling add_watch, in the ho[e of avoiding
108 a race which misses files being added as we start */
109 if (ah
->wd
== -1 || !(dir_stream
= opendir(ah
->fname
)))
111 my_syslog(LOG_ERR
, _("failed to create inotify for %s: %s"),
112 ah
->fname
, strerror(errno
));
116 while ((ent
= readdir(dir_stream
)))
118 size_t lendir
= strlen(ah
->fname
);
119 size_t lenfile
= strlen(ent
->d_name
);
122 /* ignore emacs backups and dotfiles */
124 ent
->d_name
[lenfile
- 1] == '~' ||
125 (ent
->d_name
[0] == '#' && ent
->d_name
[lenfile
- 1] == '#') ||
126 ent
->d_name
[0] == '.')
129 if ((path
= whine_malloc(lendir
+ lenfile
+ 2)))
131 strcpy(path
, ah
->fname
);
133 strcat(path
, ent
->d_name
);
135 /* ignore non-regular files */
136 if (stat(path
, &buf
) != -1 && S_ISREG(buf
.st_mode
))
138 if (ah
->flags
& AH_HOSTS
)
139 total_size
= read_hostsfile(path
, ah
->index
, total_size
, rhash
, revhashsz
);
141 else if (ah
->flags
& (AH_DHCP_HST
| AH_DHCP_OPT
))
142 option_read_dynfile(path
, ah
->flags
);
152 int inotify_check(time_t now
)
155 struct hostsfile
*ah
;
162 struct inotify_event
*in
;
164 while ((rc
= read(daemon
->inotifyfd
, inotify_buffer
, INOTIFY_SZ
)) == -1 && errno
== EINTR
);
169 for (p
= inotify_buffer
; rc
- (p
- inotify_buffer
) >= (int)sizeof(struct inotify_event
); p
+= sizeof(struct inotify_event
) + in
->len
)
171 in
= (struct inotify_event
*)p
;
173 for (res
= daemon
->resolv_files
; res
; res
= res
->next
)
174 if (res
->wd
== in
->wd
&& in
->len
!= 0 && strcmp(res
->file
, in
->name
) == 0)
177 /* ignore emacs backups and dotfiles */
179 in
->name
[in
->len
- 1] == '~' ||
180 (in
->name
[0] == '#' && in
->name
[in
->len
- 1] == '#') ||
184 for (ah
= daemon
->dynamic_dirs
; ah
; ah
= ah
->next
)
185 if (ah
->wd
== in
->wd
)
187 size_t lendir
= strlen(ah
->fname
);
190 if ((path
= whine_malloc(lendir
+ in
->len
+ 2)))
192 strcpy(path
, ah
->fname
);
194 strcat(path
, in
->name
);
196 if (ah
->flags
& AH_HOSTS
)
197 read_hostsfile(path
, ah
->index
, 0, NULL
, 0);
199 else if (ah
->flags
& AH_DHCP_HST
)
201 if (option_read_dynfile(path
, AH_DHCP_HST
))
203 /* Propogate the consequences of loading a new dhcp-host */
204 dhcp_update_configs(daemon
->dhcp_conf
);
205 lease_update_from_configs();
206 lease_update_file(now
);
210 else if (ah
->flags
& AH_DHCP_OPT
)
211 option_read_dynfile(path
, AH_DHCP_OPT
);