반응형
HP-UX에서 리눅스의 inotify와 유사한 기능을 제공하는 네이티브 C API는 존재하지 않습니다. HP-UX는 POSIX 표준을 따르는 유닉스 시스템이지만, inotify는 리눅스 커널에 특화된 기능으로, HP-UX에는 직접적인 대체재가 없습니다. 대신, HP-UX에서 파일 시스템 이벤트를 모니터링하려면 다음과 같은 대안을 사용할 수 있습니다:
- ** polling 방식 (주기적 파일 확인)**: 파일의 수정 시간을 주기적으로 확인하는 방식입니다. HP-UX에서 stat() 함수를 사용하여 파일의 타임스탬프를 체크할 수 있습니다.
- HP-UX audit 시스템: HP-UX는 파일 시스템 이벤트를 추적하기 위한 auditing 기능을 제공합니다. 하지만 이는 시스템 수준 설정이 필요하며, inotify처럼 실시간으로 응용 프로그램에 이벤트를 전달하지 않습니다.
- FAM (File Alteration Monitor): 과거 유닉스 시스템에서 사용되던 파일 모니터링 도구로, HP-UX에서도 일부 환경에서 지원될 수 있습니다. 그러나 최신 HP-UX 버전에서는 사용이 제한적일 수 있습니다
HP-UX에서 파일 수정 감지 및 내용 출력 예제 코드
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#define MAX_PATH 1024
#define MAX_BUFFER 1024
#define INITIAL_CAPACITY 10
// 글로벌 변수 (시그널 처리와 파일 핸들러 관리용)
static volatile int keep_running = 1;
static FILE *log_file = NULL;
// 파일 정보를 저장할 구조체
typedef struct {
char path[MAX_PATH];
time_t mtime; // 마지막 수정 시간
} FileInfo;
// 시그널 핸들러 (Ctrl+C 처리)
void signal_handler(int sig) {
keep_running = 0;
}
// 로그 파일에 기록하는 함수
void log_to_file(const char *message) {
if (log_file == NULL) return;
time_t now = time(NULL);
fprintf(log_file, "[%s] %s\n", ctime(&now), message);
fflush(log_file); // 즉시 기록 보장
}
// 파일 내용을 로그에 기록
void log_file_content(const char *filepath) {
FILE *file = fopen(filepath, "r");
if (file == NULL) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "파일 열기 실패: %s", filepath);
log_to_file(msg);
return;
}
char buffer[MAX_BUFFER];
snprintf(buffer, MAX_BUFFER, "파일 내용 (%s):", filepath);
log_to_file(buffer);
while (fgets(buffer, MAX_BUFFER, file) != NULL) {
buffer[strcspn(buffer, "\n")] = 0; // 개행 문자 제거
log_to_file(buffer);
}
fclose(file);
}
// 디렉토리 내 파일 목록을 재귀적으로 수집
void collect_files(const char *dirpath, FileInfo **files, int *file_count, int *capacity, const char *filter_ext) {
DIR *dir = opendir(dirpath);
if (dir == NULL) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "디렉토리 열기 실패: %s", dirpath);
log_to_file(msg);
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char fullpath[MAX_PATH];
snprintf(fullpath, MAX_PATH, "%s/%s", dirpath, entry->d_name);
struct stat file_stat;
if (stat(fullpath, &file_stat) == -1) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "stat 호출 실패: %s", fullpath);
log_to_file(msg);
continue;
}
if (S_ISDIR(file_stat.st_mode)) {
// 디렉토리면 재귀 호출
collect_files(fullpath, files, file_count, capacity, filter_ext);
} else if (S_ISREG(file_stat.st_mode)) {
// 필터링 적용
if (filter_ext && strstr(entry->d_name, filter_ext) == NULL) {
continue;
}
if (*file_count >= *capacity) {
*capacity *= 2;
*files = realloc(*files, *capacity * sizeof(FileInfo));
}
snprintf((*files)[*file_count].path, MAX_PATH, "%s", fullpath);
(*files)[*file_count].mtime = file_stat.st_mtime;
(*file_count)++;
}
}
closedir(dir);
}
// 파일 목록 갱신 및 변경 감지
int update_file_list(const char *dirpath, FileInfo **files, int *file_count, int *capacity, const char *filter_ext) {
int new_count = 0;
FileInfo *new_files = malloc(*capacity * sizeof(FileInfo));
// 새 파일 목록 수집
collect_files(dirpath, &new_files, &new_count, capacity, filter_ext);
// 변경 감지
for (int i = 0; i < *file_count; i++) {
int found = 0;
for (int j = 0; j < new_count; j++) {
if (strcmp((*files)[i].path, new_files[j].path) == 0) {
found = 1;
if ((*files)[i].mtime != new_files[j].mtime) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "파일 수정됨: %s (수정 시간: %s)", new_files[j].path, ctime(&new_files[j].mtime));
log_to_file(msg);
log_file_content(new_files[j].path);
}
break;
}
}
if (!found) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "파일 삭제됨: %s", (*files)[i].path);
log_to_file(msg);
}
}
for (int j = 0; j < new_count; j++) {
int found = 0;
for (int i = 0; i < *file_count; i++) {
if (strcmp((*files)[i].path, new_files[j].path) == 0) {
found = 1;
break;
}
}
if (!found) {
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "파일 추가됨: %s (생성/수정 시간: %s)", new_files[j].path, ctime(&new_files[j].mtime));
log_to_file(msg);
log_file_content(new_files[j].path);
}
}
// 기존 목록 교체
free(*files);
*files = new_files;
*file_count = new_count;
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2 || argc > 3) {
fprintf(stderr, "사용법: %s <디렉토리경로> [polling_interval_sec]\n");
return 1;
}
const char *dirpath = argv[1];
int polling_interval = (argc == 3) ? atoi(argv[2]) : 1;
if (polling_interval <= 0) polling_interval = 1;
// 로그 파일 열기
log_file = fopen("file_monitor.log", "a");
if (log_file == NULL) {
perror("로그 파일 열기 실패");
return 1;
}
// 시그널 핸들러 등록
signal(SIGINT, signal_handler);
FileInfo *files = NULL;
int file_count = 0;
int capacity = INITIAL_CAPACITY;
const char *filter_ext = ".txt"; // 감시할 파일 확장자 (NULL로 모든 파일 감시)
// 초기 파일 목록
if (update_file_list(dirpath, &files, &file_count, &capacity, filter_ext) == -1) {
fclose(log_file);
return 1;
}
char msg[MAX_BUFFER];
snprintf(msg, MAX_BUFFER, "디렉토리 모니터링 시작: %s (%d개 파일 감지됨, polling 간격: %d초)", dirpath, file_count, polling_interval);
log_to_file(msg);
// 모니터링 루프
while (keep_running) {
update_file_list(dirpath, &files, &file_count, &capacity, filter_ext);
sleep(polling_interval);
}
// 종료 처리
snprintf(msg, MAX_BUFFER, "모니터링 종료: %s", dirpath);
log_to_file(msg);
free(files);
fclose(log_file);
return 0;
}
기능 설명
- 중첩 디렉토리 감시:
- collect_files() 함수에서 재귀적으로 디렉토리를 탐색하여 하위 디렉토리의 파일까지 감시합니다.
- S_ISDIR로 디렉토리를 확인하고 재귀 호출합니다.
- 시그널 처리:
- signal(SIGINT, signal_handler)로 Ctrl+C를 감지하여 keep_running 플래그를 변경합니다.
- 종료 시 메모리와 로그 파일을 안전하게 정리합니다.
- 로그 파일 출력:
- file_monitor.log라는 파일에 모든 이벤트를 기록합니다.
- log_to_file()와 log_file_content()로 메시지와 파일 내용을 로그에 저장합니다.
- 기존 기능 유지:
- 파일 수정/추가/삭제 감지, polling 간격 조정, 확장자 필터링 등 이전 개선 사항을 모두 포함합니다.
한계
- 실시간성: 여전히 polling 방식의 한계로 inotify 수준의 즉각적인 감지는 불가능합니다.
- 성능: 중첩 디렉토리와 파일 수가 많아질수록 I/O 부하가 증가할 수 있습니다.
반응형
'프로그래밍 > Tips [IA]' 카테고리의 다른 글
도커(Docker) : 개념부터 장점, 쿠버네티스까지 (0) | 2025.04.07 |
---|---|
Windows 10 Microsoft Compatibility Telemetry 비활성화 가이드 (0) | 2025.03.14 |
[IA] Gitea service in Windows (0) | 2025.02.25 |
[IA] C# Word automation 테이블 병합 셀의 개수 파악 (0) | 2025.02.25 |
[IA] Simple Interpreter in C99 (0) | 2025.02.25 |