static void free_mem (void) { /* Remove all traces. */ clearenv (); /* Now remove the search tree. */ __tdestroy (known_values, free); known_values = NULL; }
free_mem (void) { name_database *top = service_table; name_database_entry *entry; service_library *library; if (top == NULL) /* Maybe we have not read the nsswitch.conf file. */ return; /* Don't disturb ongoing other threads (if there are any). */ service_table = NULL; entry = top->entry; while (entry != NULL) { name_database_entry *olde = entry; service_user *service = entry->service; while (service != NULL) { service_user *olds = service; if (service->known != NULL) __tdestroy (service->known, free); service = service->next; free (olds); } entry = entry->next; free (olde); } library = top->library; while (library != NULL) { service_library *oldl = library; __libc_dlclose (library->lib_handle); library = library->next; free (oldl); } free (top); }
ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, int flags) { struct ftw_data data; struct STAT st; int result = 0; int save_err; int cwdfd = -1; char *cwd = NULL; char *cp; /* First make sure the parameters are reasonable. */ if (dir[0] == '\0') { __set_errno (ENOENT); return -1; } data.maxdir = descriptors < 1 ? 1 : descriptors; data.actdir = 0; data.dirstreams = (struct dir_data **) alloca (data.maxdir * sizeof (struct dir_data *)); memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *)); /* PATH_MAX is always defined when we get here. */ data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX); data.dirbuf = (char *) malloc (data.dirbufsize); if (data.dirbuf == NULL) return -1; cp = __stpcpy (data.dirbuf, dir); /* Strip trailing slashes. */ while (cp > data.dirbuf + 1 && cp[-1] == '/') --cp; *cp = '\0'; data.ftw.level = 0; /* Find basename. */ while (cp > data.dirbuf && cp[-1] != '/') --cp; data.ftw.base = cp - data.dirbuf; data.flags = flags; /* This assignment might seem to be strange but it is what we want. The trick is that the first three arguments to the `ftw' and `nftw' callback functions are equal. Therefore we can call in every case the callback using the format of the `nftw' version and get the correct result since the stack layout for a function call in C allows this. */ data.func = (NFTW_FUNC_T) func; /* Since we internally use the complete set of FTW_* values we need to reduce the value range before calling a `ftw' callback. */ data.cvt_arr = is_nftw ? nftw_arr : ftw_arr; /* No object known so far. */ data.known_objects = NULL; /* Now go to the directory containing the initial file/directory. */ if (flags & FTW_CHDIR) { /* We have to be able to go back to the current working directory. The best way to do this is to use a file descriptor. */ cwdfd = __open (".", O_RDONLY | O_DIRECTORY); if (cwdfd == -1) { /* Try getting the directory name. This can be needed if the current directory is executable but not readable. */ if (errno == EACCES) /* GNU extension ahead. */ cwd = __getcwd (NULL, 0); if (cwd == NULL) goto out_fail; } else if (data.maxdir > 1) /* Account for the file descriptor we use here. */ --data.maxdir; if (data.ftw.base > 0) { /* Change to the directory the file is in. In data.dirbuf we have a writable copy of the file name. Just NUL terminate it for now and change the directory. */ if (data.ftw.base == 1) /* I.e., the file is in the root directory. */ result = __chdir ("/"); else { char ch = data.dirbuf[data.ftw.base - 1]; data.dirbuf[data.ftw.base - 1] = '\0'; result = __chdir (data.dirbuf); data.dirbuf[data.ftw.base - 1] = ch; } } } /* Get stat info for start directory. */ if (result == 0) { const char *name; if (data.flags & FTW_CHDIR) { name = data.dirbuf + data.ftw.base; if (name[0] == '\0') name = "."; } else name = data.dirbuf; if (((flags & FTW_PHYS) ? LXSTAT (_STAT_VER, name, &st) : XSTAT (_STAT_VER, name, &st)) < 0) { if (!(flags & FTW_PHYS) && errno == ENOENT && LXSTAT (_STAT_VER, name, &st) == 0 && S_ISLNK (st.st_mode)) result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN], &data.ftw); else /* No need to call the callback since we cannot say anything about the object. */ result = -1; } else { if (S_ISDIR (st.st_mode)) { /* Remember the device of the initial directory in case FTW_MOUNT is given. */ data.dev = st.st_dev; /* We know this directory now. */ if (!(flags & FTW_PHYS)) result = add_object (&data, &st); if (result == 0) result = ftw_dir (&data, &st, NULL); } else { int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F; result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag], &data.ftw); } } if ((flags & FTW_ACTIONRETVAL) && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS)) result = 0; } /* Return to the start directory (if necessary). */ if (cwdfd != -1) { int save_err = errno; __fchdir (cwdfd); __close_nocancel_nostatus (cwdfd); __set_errno (save_err); } else if (cwd != NULL) { int save_err = errno; __chdir (cwd); free (cwd); __set_errno (save_err); } /* Free all memory. */ out_fail: save_err = errno; __tdestroy (data.known_objects, free); free (data.dirbuf); __set_errno (save_err); return result; }