Lines 957-962
cannot change socket to nonblocking mode: %s"),
Link Here
|
957 |
finish_drop_privileges (); |
957 |
finish_drop_privileges (); |
958 |
} |
958 |
} |
959 |
|
959 |
|
|
|
960 |
#ifdef HAVE_INOTIFY |
961 |
#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF) |
962 |
#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF) |
963 |
void |
964 |
install_watches (struct traced_file *finfo) |
965 |
{ |
966 |
/* If we have inotify support use it exclusively with no fallback |
967 |
to stat. This is a design decision to make the implementation |
968 |
sipmler. Either we use fstat for the file name or we use inotify |
969 |
for both the file and parent directory. */ |
970 |
if (finfo->inotify_descr[TRACED_FILE] < 0) |
971 |
finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd, |
972 |
finfo->fname, |
973 |
TRACED_FILE_MASK); |
974 |
if (finfo->inotify_descr[TRACED_FILE] < 0) |
975 |
{ |
976 |
dbg_log (_("failed to add watch to file `%s': %s"), |
977 |
finfo->fname, strerror (errno)); |
978 |
return; |
979 |
} |
980 |
dbg_log (_("watching registered file `%s` (%d)"), |
981 |
finfo->fname, finfo->inotify_descr[TRACED_FILE]); |
982 |
/* Additionally listen for IN_CREATE events in the files parent |
983 |
directory. We do this because the file to be watched might be |
984 |
deleted and then added back again. When it is added back again |
985 |
we must re-add the watch. We must also cover IN_MOVED_TO to |
986 |
detect a file being moved into the directory. */ |
987 |
if (finfo->inotify_descr[TRACED_DIR] < 0) |
988 |
finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd, |
989 |
finfo->dname, |
990 |
TRACED_DIR_MASK); |
991 |
if (finfo->inotify_descr[TRACED_DIR] < 0) |
992 |
{ |
993 |
dbg_log (_("failed to add watch to directory `%s': %s"), |
994 |
finfo->fname, strerror (errno)); |
995 |
return; |
996 |
} |
997 |
dbg_log (_("watching registered directory `%s` (%d)"), |
998 |
finfo->dname, finfo->inotify_descr[TRACED_DIR]); |
999 |
} |
1000 |
#endif |
960 |
|
1001 |
|
961 |
/* Register the file in FINFO as a traced file for the database DBS[DBIX]. |
1002 |
/* Register the file in FINFO as a traced file for the database DBS[DBIX]. |
962 |
|
1003 |
|
Lines 985-1010
register_traced_file (size_t dbidx, struct traced_file *finfo)
Link Here
|
985 |
finfo->fname, dbnames[dbidx]); |
1026 |
finfo->fname, dbnames[dbidx]); |
986 |
|
1027 |
|
987 |
#ifdef HAVE_INOTIFY |
1028 |
#ifdef HAVE_INOTIFY |
988 |
if (inotify_fd < 0 |
1029 |
install_watches (finfo); |
989 |
|| (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname, |
|
|
990 |
IN_DELETE_SELF |
991 |
| IN_MODIFY)) < 0) |
992 |
#endif |
1030 |
#endif |
993 |
{ |
|
|
994 |
/* We need the modification date of the file. */ |
995 |
struct stat64 st; |
996 |
|
997 |
if (stat64 (finfo->fname, &st) < 0) |
998 |
{ |
999 |
/* We cannot stat() the file, disable file checking. */ |
1000 |
dbg_log (_("cannot stat() file `%s': %s"), |
1001 |
finfo->fname, strerror (errno)); |
1002 |
return; |
1003 |
} |
1004 |
|
1005 |
finfo->inotify_descr = -1; |
1006 |
finfo->mtime = st.st_mtime; |
1007 |
} |
1008 |
|
1031 |
|
1009 |
/* Queue up the file name. */ |
1032 |
/* Queue up the file name. */ |
1010 |
finfo->next = dbs[dbidx].traced_files; |
1033 |
finfo->next = dbs[dbidx].traced_files; |
Lines 1033-1045
invalidate_cache (char *key, int fd)
Link Here
|
1033 |
{ |
1056 |
{ |
1034 |
struct traced_file *runp = dbs[hstdb].traced_files; |
1057 |
struct traced_file *runp = dbs[hstdb].traced_files; |
1035 |
while (runp != NULL) |
1058 |
while (runp != NULL) |
1036 |
if (runp->call_res_init) |
1059 |
{ |
1037 |
{ |
1060 |
#ifdef HAVE_INOTIFY |
1038 |
res_init (); |
1061 |
/* During an invalidation we try to reload the traced |
1039 |
break; |
1062 |
file watches. This allows the user to re-sync if |
1040 |
} |
1063 |
inotify events were lost. */ |
1041 |
else |
1064 |
install_watches (runp); |
|
|
1065 |
#endif |
1066 |
if (runp->call_res_init) |
1067 |
{ |
1068 |
res_init (); |
1069 |
break; |
1070 |
} |
1042 |
runp = runp->next; |
1071 |
runp = runp->next; |
|
|
1072 |
} |
1043 |
} |
1073 |
} |
1044 |
break; |
1074 |
break; |
1045 |
} |
1075 |
} |
Lines 1884-1890
union __inev
Link Here
|
1884 |
registered with a database then mark that database as requiring its cache |
1914 |
registered with a database then mark that database as requiring its cache |
1885 |
to be cleared. We indicate the cache needs clearing by setting |
1915 |
to be cleared. We indicate the cache needs clearing by setting |
1886 |
TO_CLEAR[DBCNT] to true for the matching database. */ |
1916 |
TO_CLEAR[DBCNT] to true for the matching database. */ |
1887 |
static inline void |
1917 |
static void |
1888 |
inotify_check_files (bool *to_clear, union __inev *inev) |
1918 |
inotify_check_files (bool *to_clear, union __inev *inev) |
1889 |
{ |
1919 |
{ |
1890 |
/* Check which of the files changed. */ |
1920 |
/* Check which of the files changed. */ |
Lines 1894-1909
inotify_check_files (bool *to_clear, union __inev *inev)
Link Here
|
1894 |
|
1924 |
|
1895 |
while (finfo != NULL) |
1925 |
while (finfo != NULL) |
1896 |
{ |
1926 |
{ |
1897 |
/* Inotify event watch descriptor matches. */ |
1927 |
/* The configuration file was moved or deleted. |
1898 |
if (finfo->inotify_descr == inev->i.wd) |
1928 |
We stop watching it at that point, and reinitialize. */ |
|
|
1929 |
if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd |
1930 |
&& ((inev->i.mask & IN_MOVE_SELF) |
1931 |
|| (inev->i.mask & IN_DELETE_SELF) |
1932 |
|| (inev->i.mask & IN_IGNORED))) |
1933 |
{ |
1934 |
int ret; |
1935 |
bool moved = (inev->i.mask & IN_MOVE_SELF) != 0; |
1936 |
dbg_log (_("registered file `%s` was %s, removing watch"), |
1937 |
finfo->fname, moved ? "moved" : "deleted"); |
1938 |
/* File was moved out, remove the watch. Watches are |
1939 |
automatically removed when the file is deleted. */ |
1940 |
if (moved) |
1941 |
{ |
1942 |
ret = inotify_rm_watch (inotify_fd, inev->i.wd); |
1943 |
if (ret < 0) |
1944 |
dbg_log (_("failed to remove file watch `%s`: %s"), |
1945 |
finfo->fname, strerror (errno)); |
1946 |
} |
1947 |
finfo->inotify_descr[TRACED_FILE] = -1; |
1948 |
to_clear[dbcnt] = true; |
1949 |
if (finfo->call_res_init) |
1950 |
res_init (); |
1951 |
return; |
1952 |
} |
1953 |
/* The configuration file was open for writing and has just closed. |
1954 |
We reset the cache and reinitialize. */ |
1955 |
if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd) |
1899 |
{ |
1956 |
{ |
1900 |
/* Mark cache as needing to be cleared and reinitialize. */ |
1957 |
/* Mark cache as needing to be cleared and reinitialize. */ |
|
|
1958 |
dbg_log (_("registered file `%s` was written to"), finfo->fname); |
1901 |
to_clear[dbcnt] = true; |
1959 |
to_clear[dbcnt] = true; |
1902 |
if (finfo->call_res_init) |
1960 |
if (finfo->call_res_init) |
1903 |
res_init (); |
1961 |
res_init (); |
1904 |
return; |
1962 |
return; |
1905 |
} |
1963 |
} |
|
|
1964 |
/* The parent directory was moved or deleted. There is no coming |
1965 |
back from this. We do not track the parent of the parent, and |
1966 |
once this happens we trigger one last invalidation. You must |
1967 |
restart nscd to track subsequent changes. We track this to |
1968 |
do one last robust re-initialization and then we're done. */ |
1969 |
if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd |
1970 |
&& ((inev->i.mask & IN_DELETE_SELF) |
1971 |
|| (inev->i.mask & IN_MOVE_SELF) |
1972 |
|| (inev->i.mask & IN_IGNORED))) |
1973 |
{ |
1974 |
bool moved = (inev->i.mask & IN_MOVE_SELF) != 0; |
1975 |
/* The directory watch may have already been removed |
1976 |
but we don't know so we just remove it again and |
1977 |
ignore the error. Then we remove the file watch. |
1978 |
Note: watches are automatically removed for deleted |
1979 |
files. */ |
1980 |
if (moved) |
1981 |
inotify_rm_watch (inotify_fd, inev->i.wd); |
1982 |
if (finfo->inotify_descr[TRACED_FILE] != -1) |
1983 |
{ |
1984 |
dbg_log (_("registered parent directory `%s` was %s, removing watch on `%s`"), |
1985 |
finfo->dname, moved ? "moved" : "deleted", finfo->fname); |
1986 |
if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0) |
1987 |
dbg_log (_("failed to remove file watch `%s`: %s"), |
1988 |
finfo->dname, strerror (errno)); |
1989 |
} |
1990 |
finfo->inotify_descr[TRACED_FILE] = -1; |
1991 |
finfo->inotify_descr[TRACED_DIR] = -1; |
1992 |
to_clear[dbcnt] = true; |
1993 |
if (finfo->call_res_init) |
1994 |
res_init (); |
1995 |
/* Continue to the next entry since this might be the |
1996 |
parent directory for multiple registered files and |
1997 |
we want to remove watches for all registered files. */ |
1998 |
continue; |
1999 |
} |
2000 |
/* The parent directory had a create or moved to event. */ |
2001 |
if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd |
2002 |
&& strcmp (inev->i.name, finfo->sfname) == 0) |
2003 |
{ |
2004 |
/* We detected a directory change. We look for the creation |
2005 |
of the file we are tracking or the move of the same file |
2006 |
into the directory. */ |
2007 |
int ret; |
2008 |
dbg_log (_("registered file `%s` was %s, adding watch"), |
2009 |
finfo->fname, |
2010 |
inev->i.mask & IN_CREATE ? "created" : "moved into place"); |
2011 |
/* File was moved in or created. Regenerate the watch. */ |
2012 |
if (finfo->inotify_descr[TRACED_FILE] != -1) |
2013 |
{ |
2014 |
ret = inotify_rm_watch (inotify_fd, |
2015 |
finfo->inotify_descr[TRACED_FILE]); |
2016 |
if (ret < 0) |
2017 |
dbg_log (_("failed to remove file watch `%s`: %s"), |
2018 |
finfo->fname, strerror (errno)); |
2019 |
} |
2020 |
|
2021 |
ret = inotify_add_watch (inotify_fd, |
2022 |
finfo->fname, |
2023 |
TRACED_FILE_MASK); |
2024 |
if (ret < 0) |
2025 |
dbg_log (_("failed to add file watch `%s`: %s"), |
2026 |
finfo->fname, strerror (errno)); |
2027 |
|
2028 |
finfo->inotify_descr[TRACED_FILE] = ret; |
1906 |
|
2029 |
|
|
|
2030 |
/* The file is new or moved so mark cache as needing to |
2031 |
be cleared and reinitialize. */ |
2032 |
to_clear[dbcnt] = true; |
2033 |
if (finfo->call_res_init) |
2034 |
res_init (); |
2035 |
|
2036 |
/* Done re-adding the watch. Don't return, we may still |
2037 |
have other files in this same directory, same watch |
2038 |
descriptor, and need to process them. */ |
2039 |
} |
1907 |
finfo = finfo->next; |
2040 |
finfo = finfo->next; |
1908 |
} |
2041 |
} |
1909 |
} |
2042 |
} |
Lines 1925-1930
clear_db_cache (bool *to_clear)
Link Here
|
1925 |
} |
2058 |
} |
1926 |
} |
2059 |
} |
1927 |
|
2060 |
|
|
|
2061 |
int |
2062 |
handle_inotify_events (void) |
2063 |
{ |
2064 |
bool to_clear[lastdb] = { false, }; |
2065 |
union __inev inev; |
2066 |
|
2067 |
/* Read all inotify events for files registered via |
2068 |
register_traced_file(). */ |
2069 |
while (1) |
2070 |
{ |
2071 |
/* Potentially read multiple events into buf. */ |
2072 |
ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, |
2073 |
&inev.buf, |
2074 |
sizeof (inev))); |
2075 |
if (nb < (ssize_t) sizeof (struct inotify_event)) |
2076 |
{ |
2077 |
/* Not even 1 event. */ |
2078 |
if (__glibc_unlikely (nb == -1 && errno != EAGAIN)) |
2079 |
return -1; |
2080 |
/* Done reading events that are ready. */ |
2081 |
break; |
2082 |
} |
2083 |
/* Process all events. The normal inotify interface delivers |
2084 |
complete events on a read and never a partial event. */ |
2085 |
char *eptr = &inev.buf[0]; |
2086 |
ssize_t count; |
2087 |
while (1) |
2088 |
{ |
2089 |
/* Check which of the files changed. */ |
2090 |
inotify_check_files (to_clear, &inev); |
2091 |
count = sizeof (struct inotify_event) + inev.i.len; |
2092 |
eptr += count; |
2093 |
nb -= count; |
2094 |
if (nb >= (ssize_t) sizeof (struct inotify_event)) |
2095 |
memcpy (&inev, eptr, nb); |
2096 |
else |
2097 |
break; |
2098 |
} |
2099 |
continue; |
2100 |
} |
2101 |
/* Actually perform the cache clearing. */ |
2102 |
clear_db_cache (to_clear); |
2103 |
return 0; |
2104 |
} |
2105 |
|
1928 |
#endif |
2106 |
#endif |
1929 |
|
2107 |
|
1930 |
static void |
2108 |
static void |
Lines 2031-2072
main_loop_poll (void)
Link Here
|
2031 |
{ |
2209 |
{ |
2032 |
if (conns[1].revents != 0) |
2210 |
if (conns[1].revents != 0) |
2033 |
{ |
2211 |
{ |
2034 |
bool to_clear[lastdb] = { false, }; |
2212 |
int ret; |
2035 |
union __inev inev; |
2213 |
ret = handle_inotify_events (); |
2036 |
|
2214 |
if (ret == -1) |
2037 |
/* Read all inotify events for files registered via |
|
|
2038 |
register_traced_file(). */ |
2039 |
while (1) |
2040 |
{ |
2215 |
{ |
2041 |
ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev, |
2216 |
/* Something went wrong when reading the inotify |
2042 |
sizeof (inev))); |
2217 |
data. Better disable inotify. */ |
2043 |
if (nb < (ssize_t) sizeof (struct inotify_event)) |
2218 |
dbg_log (_("disabled inotify after read error %d"), errno); |
2044 |
{ |
2219 |
conns[1].fd = -1; |
2045 |
if (__builtin_expect (nb == -1 && errno != EAGAIN, |
2220 |
firstfree = 1; |
2046 |
0)) |
2221 |
if (nused == 2) |
2047 |
{ |
2222 |
nused = 1; |
2048 |
/* Something went wrong when reading the inotify |
2223 |
close (inotify_fd); |
2049 |
data. Better disable inotify. */ |
2224 |
inotify_fd = -1; |
2050 |
dbg_log (_("\ |
|
|
2051 |
disabled inotify after read error %d"), |
2052 |
errno); |
2053 |
conns[1].fd = -1; |
2054 |
firstfree = 1; |
2055 |
if (nused == 2) |
2056 |
nused = 1; |
2057 |
close (inotify_fd); |
2058 |
inotify_fd = -1; |
2059 |
} |
2060 |
break; |
2061 |
} |
2062 |
|
2063 |
/* Check which of the files changed. */ |
2064 |
inotify_check_files (to_clear, &inev); |
2065 |
} |
2225 |
} |
2066 |
|
|
|
2067 |
/* Actually perform the cache clearing. */ |
2068 |
clear_db_cache (to_clear); |
2069 |
|
2070 |
--n; |
2226 |
--n; |
2071 |
} |
2227 |
} |
2072 |
|
2228 |
|
Lines 2234-2270
main_loop_epoll (int efd)
Link Here
|
2234 |
# ifdef HAVE_INOTIFY |
2390 |
# ifdef HAVE_INOTIFY |
2235 |
else if (revs[cnt].data.fd == inotify_fd) |
2391 |
else if (revs[cnt].data.fd == inotify_fd) |
2236 |
{ |
2392 |
{ |
2237 |
bool to_clear[lastdb] = { false, }; |
2393 |
int ret; |
2238 |
union __inev inev; |
2394 |
ret = handle_inotify_events (); |
2239 |
|
2395 |
if (ret == -1) |
2240 |
/* Read all inotify events for files registered via |
|
|
2241 |
register_traced_file(). */ |
2242 |
while (1) |
2243 |
{ |
2396 |
{ |
2244 |
ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev, |
2397 |
/* Something went wrong when reading the inotify |
2245 |
sizeof (inev))); |
2398 |
data. Better disable inotify. */ |
2246 |
if (nb < (ssize_t) sizeof (struct inotify_event)) |
2399 |
dbg_log (_("disabled inotify after read error %d"), errno); |
2247 |
{ |
2400 |
(void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, NULL); |
2248 |
if (__glibc_unlikely (nb == -1 && errno != EAGAIN)) |
2401 |
close (inotify_fd); |
2249 |
{ |
2402 |
inotify_fd = -1; |
2250 |
/* Something went wrong when reading the inotify |
2403 |
break; |
2251 |
data. Better disable inotify. */ |
|
|
2252 |
dbg_log (_("disabled inotify after read error %d"), |
2253 |
errno); |
2254 |
(void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd, |
2255 |
NULL); |
2256 |
close (inotify_fd); |
2257 |
inotify_fd = -1; |
2258 |
} |
2259 |
break; |
2260 |
} |
2261 |
|
2262 |
/* Check which of the files changed. */ |
2263 |
inotify_check_files(to_clear, &inev); |
2264 |
} |
2404 |
} |
2265 |
|
|
|
2266 |
/* Actually perform the cache clearing. */ |
2267 |
clear_db_cache (to_clear); |
2268 |
} |
2405 |
} |
2269 |
# endif |
2406 |
# endif |
2270 |
# ifdef HAVE_NETLINK |
2407 |
# ifdef HAVE_NETLINK |