hush/libbb/recursive_action.c

142 lines
3.4 KiB
C
Raw Normal View History

/* vi: set sw=4 ts=4: */
/*
* Utility routines.
*
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h> /* free() */
#include "libbb.h"
#undef DEBUG_RECURS_ACTION
/*
* Walk down all the directories under the specified
* location, and do something (something specified
* by the fileAction and dirAction function pointers).
*
* Unfortunately, while nftw(3) could replace this and reduce
* code size a bit, nftw() wasn't supported before GNU libc 2.1,
* and so isn't sufficiently portable to take over since glibc2.1
* is so stinking huge.
*/
int recursive_action(const char *fileName,
int recurse, int followLinks, int depthFirst,
int (*fileAction) (const char *fileName,
struct stat * statbuf,
void* userData),
int (*dirAction) (const char *fileName,
struct stat * statbuf,
void* userData),
void* userData)
{
int status;
struct stat statbuf;
struct dirent *next;
if (followLinks)
status = stat(fileName, &statbuf);
else
status = lstat(fileName, &statbuf);
if (status < 0) {
#ifdef DEBUG_RECURS_ACTION
2003-03-19 09:13:01 +00:00
bb_error_msg("status=%d followLinks=%d TRUE=%d",
status, followLinks, TRUE);
#endif
2003-03-19 09:13:01 +00:00
bb_perror_msg("%s", fileName);
return FALSE;
}
if (! followLinks && (S_ISLNK(statbuf.st_mode))) {
if (fileAction == NULL)
return TRUE;
else
return fileAction(fileName, &statbuf, userData);
}
if (! recurse) {
if (S_ISDIR(statbuf.st_mode)) {
if (dirAction != NULL)
return (dirAction(fileName, &statbuf, userData));
else
return TRUE;
}
}
if (S_ISDIR(statbuf.st_mode)) {
DIR *dir;
if (dirAction != NULL && ! depthFirst) {
status = dirAction(fileName, &statbuf, userData);
if (! status) {
2003-03-19 09:13:01 +00:00
bb_perror_msg("%s", fileName);
return FALSE;
} else if (status == SKIP)
return TRUE;
}
dir = opendir(fileName);
if (!dir) {
2003-03-19 09:13:01 +00:00
bb_perror_msg("%s", fileName);
return FALSE;
}
status = TRUE;
Christian Grigis, christian.grigis at smartdata dot ch writes: Hello everyone, Busybox's insmod fails to locate a module when that module is the only one existing in the /lib/modules directory (with a unique name). Example: # find /lib/modules/ -type f /lib/modules/kernel/drivers/char/bios.o # insmod bios insmod: bios.o: no module by that name found # touch /lib/modules/dummy # find /lib/modules/ -type f /lib/modules/kernel/drivers/char/bios.o /lib/modules/dummy # insmod bios Using /lib/modules/kernel/drivers/char/bios.o As long as there is another file in the /lib/modules directory, insmod finds it OK. I tracked the problem down to 'check_module_name_match()' in insmod.c: It returns TRUE when a match is found, and FALSE otherwise. In the case where there is only one module in the /lib/modules directory (or more that one module, but all with the same name), 'recursive_action()' will return TRUE and we end up on line 4196 in 'insmod.c' which returns an error. [The reason it works with more than one module with different names is that in this case there will always be one not matching, 'recursive_action()' will return FALSE and we end up in line 4189.] Now, from the implementation of 'recursive_action()' and from other usages of it (tar.c, etc.), it seems to me that FALSE should be returned to indicate that we want to stop the recursion, so TRUE and FALSE should be inverted in 'check_module_name_match()'. At the same time, 'recursive_action()' continues to recurse even after the recursive call has returned FALSE; again in my understanding and other usages of it, we can safely stop recursing at this point. Here is my patch against 1.00-pre8:
2004-04-06 11:56:26 +00:00
while (status && (next = readdir(dir)) != NULL) {
char *nextFile;
2003-05-26 14:07:50 +00:00
nextFile = concat_subpath_file(fileName, next->d_name);
if(nextFile == NULL)
continue;
if (! recursive_action(nextFile, TRUE, followLinks, depthFirst,
fileAction, dirAction, userData)) {
status = FALSE;
}
free(nextFile);
}
closedir(dir);
if (dirAction != NULL && depthFirst) {
if (! dirAction(fileName, &statbuf, userData)) {
2003-03-19 09:13:01 +00:00
bb_perror_msg("%s", fileName);
return FALSE;
}
}
if (! status)
return FALSE;
} else {
if (fileAction == NULL)
return TRUE;
else
return fileAction(fileName, &statbuf, userData);
}
return TRUE;
}
/* END CODE */
/*
Local Variables:
c-file-style: "linux"
c-basic-offset: 4
tab-width: 4
End:
*/