4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; if not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2019, DDN Storage Corporation.
26 * lustre/utils/libhsm_scanner.c
28 * Library for scanning HSM backend fs.
30 * Author: Qian Yingjin <qian@ddn.com>
39 #include <sys/types.h>
40 #include <libcfs/util/list.h>
41 #include "libhsm_scanner.h"
43 struct hsm_scan_item {
44 struct list_head hsi_item;
46 char hsi_pathname[PATH_MAX];
49 static int hsm_scan_item_alloc(struct list_head *head,
50 const char *pathname, int depth)
52 struct hsm_scan_item *item;
55 if (strlen(pathname) >= PATH_MAX) {
57 llapi_error(LLAPI_MSG_ERROR, rc,
58 "pathname is too long: %s\n", pathname);
62 item = malloc(sizeof(struct hsm_scan_item));
65 llapi_error(LLAPI_MSG_ERROR, rc,
66 "cannot allocate hsm item for '%s'", pathname);
70 item->hsi_depth = depth;
71 strncpy(item->hsi_pathname, pathname, sizeof(item->hsi_pathname) - 1);
72 list_add_tail(&item->hsi_item, head);
77 int hsm_scan_handle_dir(struct hsm_scan_control *hsc, struct list_head *head,
78 struct hsm_scan_item *item)
80 char fullname[PATH_MAX + NAME_MAX + 1];
81 const char *pathname = item->hsi_pathname;
82 int depth = item->hsi_depth;
88 dir = opendir(pathname);
91 llapi_error(LLAPI_MSG_ERROR, rc, "failed to opendir '%s'",
96 while ((ent = readdir(dir)) != NULL) {
97 /* skip "." and ".." */
98 if (strcmp(ent->d_name, ".") == 0 ||
99 strcmp(ent->d_name, "..") == 0)
102 llapi_printf(LLAPI_MSG_DEBUG,
103 "check file %d:'%s' under directory '%s'\n",
104 depth, ent->d_name, pathname);
105 if (depth == 0 && ent->d_type == DT_DIR &&
106 strcmp(ent->d_name, "shadow") == 0) {
107 llapi_printf(LLAPI_MSG_DEBUG,
108 "skipping check of 'shadow' directory.\n");
110 if (ent->d_type == DT_REG) {
111 ret = hsc->hsc_func(pathname, ent->d_name, hsc);
115 /* ignore error, continue to check */
117 } else if (ent->d_type == DT_DIR) {
118 if (strlen(ent->d_name) + strlen(pathname) + 1
119 >= sizeof(fullname)) {
121 errno = ENAMETOOLONG;
122 llapi_err_noerrno(LLAPI_MSG_ERROR,
123 "ignore too long path: %s/%s\n",
129 snprintf(fullname, sizeof(fullname), "%s/%s",
130 pathname, ent->d_name);
131 rc = hsm_scan_item_alloc(head, fullname,
138 llapi_error(LLAPI_MSG_ERROR, rc, "failed to handle dir '%s'",
145 int hsm_scan_process(struct hsm_scan_control *hsc)
147 struct hsm_scan_item *item;
148 struct list_head head;
153 if (hsc->hsc_type != HSMTOOL_POSIX_V1 &&
154 hsc->hsc_type != HSMTOOL_POSIX_V2)
157 rc = stat(hsc->hsc_hsmpath, &st);
159 llapi_error(LLAPI_MSG_ERROR, rc, "failed to stat '%s'",
164 if (!S_ISDIR(st.st_mode)) {
165 llapi_err_noerrno(LLAPI_MSG_ERROR,
166 "HSM root path '%s' must be a directory.",
171 INIT_LIST_HEAD(&head);
172 rc = hsm_scan_item_alloc(&head, hsc->hsc_hsmpath, 0);
176 while (!list_empty(&head)) {
177 item = list_entry(head.next, struct hsm_scan_item, hsi_item);
178 list_del(&item->hsi_item);
179 ret = hsm_scan_handle_dir(hsc, &head, item);