commit: 21c374ab77399a99e0e8b5fe1b6f67fdb25cb180
parent 50f9d24bb94d4595555872641eea33f902cebab7
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 28 Mar 2024 18:17:28 +0100
cmd/rm: Add assert(errno == 0) before functions known to change errno
Risky as different systems could change errno in extra places, but this way
we're sure errno is reset, in fact I forgot to reset it for faccessat(…W_OK…)
Diffstat:
M | cmd/rm.c | 49 | +++++++++++++++++++++++++++++++------------------ |
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/cmd/rm.c b/cmd/rm.c
@@ -9,6 +9,7 @@
#define _NETBSD_SOURCE
#endif
+#include <assert.h>
#include <ctype.h> // isprint
#include <dirent.h> // fdopendir, readdir, closedir
#include <errno.h> // errno
@@ -35,30 +36,31 @@ consentf(const char *restrict fmt, ...)
va_list ap;
- errno = 0;
-
+ assert(errno == 0);
va_start(ap, fmt);
int ret = vfprintf(stderr, fmt, ap);
va_end(ap);
- if(!ret)
+ if(ret < 0)
{
fprintf(stderr, "%s: Failed to print user prompt: %s\n", argv0, strerror(errno));
+ errno = 0;
goto end;
}
- errno = 0;
-
+ assert(errno == 0);
ssize_t nread = getline(&line, &len, stdin);
if(nread < 0)
{
fprintf(stderr, "\n%s: Failed getting user entry via getline: %s\n", argv0, strerror(errno));
+ errno = 0;
goto end;
}
if(nread == 0)
{
fprintf(stderr, "%s: Got empty response, considering it false\n", argv0);
+ errno = 0;
goto end;
}
@@ -97,12 +99,17 @@ do_unlinkat(int fd, char *name, char *acc_path)
struct stat stats;
int err = 0;
- errno = 0;
+ assert(errno == 0);
if(fstatat(fd, name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
{
- if(force && errno == ENOENT) return 0;
+ if(force && errno == ENOENT)
+ {
+ errno = 0;
+ return 0;
+ }
fprintf(stderr, "rm: Failed getting status for '%s': %s\n", acc_path, strerror(errno));
+ errno = 0;
return 1;
}
@@ -119,44 +126,44 @@ do_unlinkat(int fd, char *name, char *acc_path)
if(!force && opt_i)
if(!consentf("rm: Recurse into '%s' ? [y/N] ", acc_path)) return 0;
- errno = 0;
+ assert(errno == 0);
int dir = openat(fd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if(dir == -1)
{
fprintf(stderr, "rm: Couldn't open '%s' as directory: %s\n", acc_path, strerror(errno));
+ errno = 0;
return 1;
}
- errno = 0;
-
+ assert(errno == 0);
DIR *dirp = fdopendir(dir);
if(dirp == NULL)
{
fprintf(
stderr, "rm: Couldn't get DIR entry for opened '%s': %s\n", acc_path, strerror(errno));
+ errno = 0;
return 1;
}
while(true)
{
- errno = 0;
-
+ assert(errno == 0);
struct dirent *dp = readdir(dirp);
if(dp == NULL)
{
if(errno == 0) break;
fprintf(stderr, "rm: Failed reading directory '%s': %s\n", acc_path, strerror(errno));
- closedir(dirp);
+ closedir(dirp); // error ignored
+ errno = 0;
return 1;
}
if(strcmp(dp->d_name, ".") == 0) continue;
if(strcmp(dp->d_name, "..") == 0) continue;
- errno = 0;
-
char new_path[PATH_MAX] = "";
+ assert(errno == 0);
if(snprintf(new_path, PATH_MAX, "%s/%s", acc_path, dp->d_name) < 0)
{
fprintf(stderr,
@@ -164,7 +171,8 @@ do_unlinkat(int fd, char *name, char *acc_path)
name,
acc_path,
strerror(errno));
- err = 1;
+ err = 1;
+ errno = 0;
continue;
}
@@ -174,13 +182,14 @@ do_unlinkat(int fd, char *name, char *acc_path)
}
// fdopendir allocates memory for DIR, needs closedir
- errno = 0;
+ assert(errno == 0);
if(closedir(dirp) != 0)
{
fprintf(stderr,
"rm: Deallocating directory entry for '%s' failed: %s\n",
acc_path,
strerror(errno));
+ errno = 0;
return 1;
}
}
@@ -189,13 +198,17 @@ do_unlinkat(int fd, char *name, char *acc_path)
{
// FIXME: Terminal always considered to be present for tests reason
if(faccessat(fd, name, W_OK, AT_SYMLINK_NOFOLLOW) != 0 || opt_i)
+ {
+ errno = 0;
if(!consentf("rm: Remove '%s' ? [y/N] ", acc_path)) return 0;
+ }
}
- errno = 0;
+ assert(errno == 0);
if(unlinkat(fd, name, is_dir ? AT_REMOVEDIR : 0) != 0)
{
fprintf(stderr, "rm: Couldn't remove '%s': %s\n", acc_path, strerror(errno));
+ errno = 0;
return 1;
}
else if(verbose)