mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
libapparmor: Move over the lib functions needed by cache loading code
The function names must be prepended with "_aa_" since they're going to be exported from libapparmor. The code bases using the _aa_autofree(), _aa_autoclose(), and _aa_autofclose() will need to internally alias those functions to the previously used autofree, autoclose, and autofclose names. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Acked-by: Seth Arnold <seth.arnold@canonical.com> Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
140
parser/lib.c
140
parser/lib.c
@@ -17,46 +17,18 @@
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <sys/apparmor_private.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
|
||||
/* automaticly free allocated variables tagged with autofree on fn exit */
|
||||
void __autofree(void *p)
|
||||
{
|
||||
void **_p = (void**)p;
|
||||
free(*_p);
|
||||
}
|
||||
|
||||
void __autoclose(int *fd)
|
||||
{
|
||||
if (*fd != -1) {
|
||||
/* if close was interrupted retry */
|
||||
while(close(*fd) == -1 && errno == EINTR);
|
||||
*fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void __autofclose(FILE **f)
|
||||
{
|
||||
if (*f) {
|
||||
fclose(*f);
|
||||
*f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void atomic_inc(unsigned int *v)
|
||||
{
|
||||
__sync_add_and_fetch(v, 1);
|
||||
@@ -67,115 +39,15 @@ bool atomic_dec_and_test(unsigned int *v)
|
||||
return __sync_sub_and_fetch(v, 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dirat_for_each: iterate over a directory calling cb for each entry
|
||||
* @dir: already opened directory (MAY BE NULL)
|
||||
* @name: name of the directory (MAY BE NULL)
|
||||
* @data: data pointer to pass to the callback fn (MAY BE NULL)
|
||||
* @cb: the callback to pass entry too (NOT NULL)
|
||||
*
|
||||
* Iterate over the entries in a directory calling cb for each entry.
|
||||
* The directory to iterate is determined by a combination of @dir and
|
||||
* @name.
|
||||
*
|
||||
* IF @name is a relative path it is determine relative to at @dir if it
|
||||
* is specified, else it the lookup is done relative to the current
|
||||
* working directory.
|
||||
*
|
||||
* If @name is not specified then @dir is used as the directory to iterate
|
||||
* over.
|
||||
*
|
||||
* It is an error if both @name and @dir are null
|
||||
*
|
||||
* The cb function is called with the DIR in use and the name of the
|
||||
* file in that directory. If the file is to be opened it should
|
||||
* use the openat, fstatat, and related fns.
|
||||
*
|
||||
* Returns: 0 on success, else -1 and errno is set to the error code
|
||||
*/
|
||||
int dirat_for_each(DIR *dir, const char *name, void *data,
|
||||
int (* cb)(DIR *, const char *, struct stat *, void *))
|
||||
{
|
||||
autofree struct dirent *dirent = NULL;
|
||||
DIR *d = NULL;
|
||||
int error;
|
||||
int retval = _aa_dirat_for_each(dir, name, data, cb);
|
||||
|
||||
if (!cb || (!dir && !name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (retval)
|
||||
PDEBUG("dirat_for_each failed: %m\n");
|
||||
|
||||
if (dir && (!name || *name != '/')) {
|
||||
dirent = (struct dirent *)
|
||||
malloc(offsetof(struct dirent, d_name) +
|
||||
fpathconf(dirfd(dir), _PC_NAME_MAX) + 1);
|
||||
} else {
|
||||
dirent = (struct dirent *)
|
||||
malloc(offsetof(struct dirent, d_name) +
|
||||
pathconf(name, _PC_NAME_MAX) + 1);
|
||||
}
|
||||
if (!dirent) {
|
||||
PDEBUG("could not alloc dirent");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (dir && *name != '/') {
|
||||
int fd = openat(dirfd(dir), name, O_RDONLY);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
d = fdopendir(fd);
|
||||
} else {
|
||||
d = opendir(name);
|
||||
}
|
||||
PDEBUG("Open dir '%s': %s\n", name, d ? "succeeded" : "failed");
|
||||
if (!(d))
|
||||
goto fail;
|
||||
} else { /* dir && !name */
|
||||
PDEBUG("Recieved cache directory\n");
|
||||
d = dir;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct dirent *ent;
|
||||
struct stat my_stat;
|
||||
|
||||
error = readdir_r(d, dirent, &ent);
|
||||
if (error) {
|
||||
PDEBUG("readdir_r failed");
|
||||
errno = error; /* readdir_r directly returns an errno */
|
||||
goto fail;
|
||||
} else if (!ent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (fstatat(dirfd(d), ent->d_name, &my_stat, 0)) {
|
||||
PDEBUG("stat failed for '%s'", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (cb(d, ent->d_name, &my_stat, data)) {
|
||||
PDEBUG("dir_for_each callback failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (d != dir)
|
||||
closedir(d);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
error = errno;
|
||||
if (d && d != dir)
|
||||
closedir(d);
|
||||
errno = error;
|
||||
|
||||
return -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user