Viewing: libhsm_scanner.c
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, DDN Storage Corporation.
*/
/*
* lustre/utils/libhsm_scanner.c
*
* Library for scanning HSM backend fs.
*
* Author: Qian Yingjin <qian@ddn.com>
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libcfs/util/list.h>
#include "libhsm_scanner.h"
struct hsm_scan_item {
struct list_head hsi_item;
int hsi_depth;
char hsi_pathname[PATH_MAX];
};
static int hsm_scan_item_alloc(struct list_head *head,
const char *pathname, int depth)
{
struct hsm_scan_item *item;
int rc;
if (strlen(pathname) >= PATH_MAX) {
rc = -ENAMETOOLONG;
llapi_error(LLAPI_MSG_ERROR, rc,
"pathname is too long: %s\n", pathname);
return rc;
}
item = malloc(sizeof(struct hsm_scan_item));
if (item == NULL) {
rc = -ENOMEM;
llapi_error(LLAPI_MSG_ERROR, rc,
"cannot allocate hsm item for '%s'", pathname);
return rc;
}
item->hsi_depth = depth;
strncpy(item->hsi_pathname, pathname, sizeof(item->hsi_pathname) - 1);
list_add_tail(&item->hsi_item, head);
return 0;
}
int hsm_scan_handle_dir(struct hsm_scan_control *hsc, struct list_head *head,
struct hsm_scan_item *item)
{
char fullname[PATH_MAX + NAME_MAX + 1];
const char *pathname = item->hsi_pathname;
int depth = item->hsi_depth;
struct dirent *ent;
DIR *dir;
int ret;
int rc = 0;
dir = opendir(pathname);
if (dir == NULL) {
rc = -errno;
llapi_error(LLAPI_MSG_ERROR, rc, "failed to opendir '%s'",
pathname);
return rc;
}
while ((ent = readdir(dir)) != NULL) {
/* skip "." and ".." */
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
continue;
llapi_printf(LLAPI_MSG_DEBUG,
"check file %d:'%s' under directory '%s'\n",
depth, ent->d_name, pathname);
if (depth == 0 && ent->d_type == DT_DIR &&
strcmp(ent->d_name, "shadow") == 0) {
llapi_printf(LLAPI_MSG_DEBUG,
"skipping check of 'shadow' directory.\n");
} else {
if (ent->d_type == DT_REG) {
ret = hsc->hsc_func(pathname, ent->d_name, hsc);
if (ret && !rc) {
hsc->hsc_errnum++;
rc = ret;
/* ignore error, continue to check */
}
} else if (ent->d_type == DT_DIR) {
if (strlen(ent->d_name) + strlen(pathname) + 1
>= sizeof(fullname)) {
rc = -ENAMETOOLONG;
errno = ENAMETOOLONG;
llapi_err_noerrno(LLAPI_MSG_ERROR,
"ignore too long path: %s/%s\n",
pathname,
ent->d_name);
hsc->hsc_errnum++;
continue;
}
snprintf(fullname, sizeof(fullname), "%s/%s",
pathname, ent->d_name);
rc = hsm_scan_item_alloc(head, fullname,
depth + 1);
}
}
}
if (rc)
llapi_error(LLAPI_MSG_ERROR, rc, "failed to handle dir '%s'",
pathname);
closedir(dir);
return rc;
}
int hsm_scan_process(struct hsm_scan_control *hsc)
{
struct hsm_scan_item *item;
struct list_head head;
struct stat st;
int ret = 0;
int rc;
if (hsc->hsc_type != HSMTOOL_POSIX_V1 &&
hsc->hsc_type != HSMTOOL_POSIX_V2)
return -EOPNOTSUPP;
rc = stat(hsc->hsc_hsmpath, &st);
if (rc) {
llapi_error(LLAPI_MSG_ERROR, rc, "failed to stat '%s'",
hsc->hsc_hsmpath);
return rc;
}
if (!S_ISDIR(st.st_mode)) {
llapi_err_noerrno(LLAPI_MSG_ERROR,
"HSM root path '%s' must be a directory.",
hsc->hsc_hsmpath);
return -EINVAL;
}
INIT_LIST_HEAD(&head);
rc = hsm_scan_item_alloc(&head, hsc->hsc_hsmpath, 0);
if (rc)
return rc;
while (!list_empty(&head)) {
item = list_entry(head.next, struct hsm_scan_item, hsi_item);
list_del(&item->hsi_item);
ret = hsm_scan_handle_dir(hsc, &head, item);
if (!rc && ret)
rc = ret;
free(item);
}
return rc;
}