Skip to content

Commit be33e33

Browse files
Andy Leminrdmark
authored andcommitted
updated parse_config_for_log_path to use iniparser
1 parent f5ae4e5 commit be33e33

File tree

4 files changed

+144
-111
lines changed

4 files changed

+144
-111
lines changed

test/testsuite/lantest.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@
1313
* GNU General Public License for more details.
1414
*/
1515

16+
/* Feature test macros for strdup and other POSIX functions - MUST be before any includes */
17+
#ifndef _GNU_SOURCE
18+
#define _GNU_SOURCE
19+
#endif
20+
#ifndef _DEFAULT_SOURCE
21+
#define _DEFAULT_SOURCE
22+
#endif
23+
#ifndef _POSIX_C_SOURCE
24+
#define _POSIX_C_SOURCE 200112L
25+
#endif
26+
27+
#include "specs.h"
28+
1629
/* Standard C library includes */
1730
#include <errno.h>
1831
#include <getopt.h>
@@ -37,12 +50,11 @@
3750
/* Netatalk library includes */
3851
#include "afpclient.h"
3952
#include "afphelper.h"
40-
#include "specs.h"
4153
#include "test.h"
4254

4355
/* Platform-specific includes */
4456
#ifdef __linux__
45-
#include "lantest_dircache_stats.c"
57+
#include "lantest_dircache_stats.h"
4658
#include "lantest_io_monitor.h"
4759
#endif
4860

@@ -1179,7 +1191,7 @@ void run_test(const int32_t dir)
11791191
clean_exit(ERROR_THREAD_OPERATIONS);
11801192
}
11811193

1182-
active_thread = 1; /* Mark thread as active */
1194+
active_thread = true; /* Mark thread as active */
11831195
#ifdef __linux__
11841196
capture_io_values(TEST_START);
11851197
#endif
@@ -1202,7 +1214,7 @@ void run_test(const int32_t dir)
12021214
clean_exit(ERROR_THREAD_OPERATIONS);
12031215
}
12041216

1205-
active_thread = 0; /* Thread successfully joined */
1217+
active_thread = false; /* Thread successfully joined */
12061218

12071219
if (FPCloseFork(Conn, fork)) {
12081220
clean_exit(ERROR_NETWORK_PROTOCOL);
@@ -2019,9 +2031,9 @@ int main(int32_t ac, char **av)
20192031
}
20202032

20212033
if (User[0] == '\0') {
2034+
uid_t uid = geteuid();
20222035
struct passwd pwd;
20232036
struct passwd *result = NULL;
2024-
uid_t uid = geteuid();
20252037
char buf[1024];
20262038
int32_t ret;
20272039
ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);

test/testsuite/lantest_dircache_stats.c

Lines changed: 113 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,53 @@
1+
/*
2+
* Copyright (c) 2025, Andy Lemin (andylemin)
3+
* Credits; Based on work by Netatalk contributors
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*/
15+
16+
/* Configuration header (must be first) */
17+
#ifdef HAVE_CONFIG_H
18+
#include "config.h"
19+
#endif /* HAVE_CONFIG_H */
20+
121
/* Standard C library includes */
22+
#include <stdio.h>
23+
24+
#ifdef __linux__
25+
26+
/* Standard C library includes for Linux implementation */
227
#include <errno.h>
328
#include <stdbool.h>
429
#include <stdint.h>
5-
#include <stdio.h>
630
#include <stdlib.h>
731
#include <string.h>
832
#include <sys/types.h>
933
#include <unistd.h>
1034

35+
/* Netatalk includes for INIPARSER_GETSTRDUP macro */
36+
#include <atalk/globals.h>
37+
38+
/* Iniparser includes */
39+
#ifdef HAVE_INIPARSER_INIPARSER_H
40+
#include <iniparser/iniparser.h>
41+
#else
42+
#include <iniparser.h>
43+
#endif
44+
1145
/* External globals from lantest.c */
1246
extern bool Debug;
1347

1448
/* Constants */
1549
#define LOG_BUFFER_SIZE (100 * 1024) /* 100KB buffer for reading log file */
1650
#define MAX_LOG_LINES_DISPLAY 10 /* Number of log lines to show when no stats found */
17-
#define CONFIG_LINE_SIZE 1024 /* Max line size for config file parsing */
1851

1952
/* Debug logging macro */
2053
#define DEBUG_LOG(fmt, ...) \
@@ -23,112 +56,52 @@ extern bool Debug;
2356
fprintf(stderr, "DEBUG: " fmt "\n", ##__VA_ARGS__); \
2457
} while(0)
2558

26-
#ifdef __linux__
27-
2859
/* Parse netatalk config file to extract log file path */
2960
static char *parse_config_for_log_path(void)
3061
{
31-
FILE *config_fp = NULL;
62+
dictionary *iniconfig = NULL;
3263
char *log_file_path = NULL;
33-
const char *config_paths[] = {
34-
"/etc/afp.conf",
35-
"/etc/netatalk/afp.conf",
36-
"/usr/local/etc/afp.conf",
37-
"/usr/local/etc/netatalk/afp.conf",
38-
NULL
39-
};
40-
41-
for (int i = 0; config_paths[i] != NULL; i++) {
42-
DEBUG_LOG("Trying to open config file: %s", config_paths[i]);
43-
44-
if (access(config_paths[i], F_OK) != 0) {
45-
DEBUG_LOG("Config file does not exist: %s", config_paths[i]);
46-
continue;
47-
}
64+
DEBUG_LOG("Loading config file: %safp.conf", _PATH_CONFDIR);
65+
/* Load the config file using iniparser */
66+
iniconfig = iniparser_load(_PATH_CONFDIR "afp.conf");
4867

49-
if (access(config_paths[i], R_OK) != 0) {
50-
DEBUG_LOG("Config file exists but not readable: %s", config_paths[i]);
51-
continue;
52-
}
68+
if (!iniconfig) {
69+
fprintf(stderr, "INFO: Could not load config file: %safp.conf\n",
70+
_PATH_CONFDIR);
71+
return NULL;
72+
}
5373

54-
config_fp = fopen(config_paths[i], "r");
55-
56-
if (config_fp) {
57-
DEBUG_LOG("Successfully opened config file: %s", config_paths[i]);
58-
char line[CONFIG_LINE_SIZE];
59-
60-
while (fgets(line, sizeof(line), config_fp)) {
61-
/* Look for "log file = " directive */
62-
char *ptr = strstr(line, "log file");
63-
64-
if (ptr) {
65-
ptr = strchr(ptr, '=');
66-
67-
if (ptr) {
68-
ptr++;
69-
70-
/* Extract path */
71-
while (*ptr && (*ptr == ' ' || *ptr == '\t')) {
72-
ptr++;
73-
}
74-
75-
char *end = ptr;
76-
77-
while (*end && *end != '\n' && *end != '\r' && *end != '#') {
78-
end++;
79-
}
80-
81-
if (end > ptr) {
82-
*end = '\0';
83-
end--;
84-
85-
while (end > ptr && (*end == ' ' || *end == '\t')) {
86-
*end = '\0';
87-
end--;
88-
}
89-
90-
if (ptr && *ptr != '\0') {
91-
DEBUG_LOG("Found log file path: %s", ptr);
92-
log_file_path = strdup(ptr);
93-
94-
if (!log_file_path) {
95-
fprintf(stderr, "ERROR: strdup() failed for log_file_path\n");
96-
fclose(config_fp);
97-
return NULL;
98-
}
99-
100-
break;
101-
} else {
102-
fprintf(stderr, "WARNING: Log file path was empty after trimming\n");
103-
}
104-
} else {
105-
fprintf(stderr, "WARNING: No content after '=' in log file line\n");
106-
}
107-
} else {
108-
fprintf(stderr, "WARNING: No '=' found in log file line\n");
109-
}
110-
}
111-
}
74+
/* Get the log file value from the Global section */
75+
log_file_path = INIPARSER_GETSTRDUP(iniconfig, INISEC_GLOBAL, "log file", NULL);
11276

113-
fclose(config_fp);
77+
if (log_file_path && *log_file_path != '\0') {
78+
DEBUG_LOG("Found log file path: %s", log_file_path);
79+
} else {
80+
DEBUG_LOG("No 'log file' configuration found in Global section");
11481

115-
if (log_file_path) {
116-
break;
117-
}
118-
} else {
119-
fprintf(stderr, "ERROR: Failed to open config file: %s (errno=%d: %s)\n",
120-
config_paths[i], errno, strerror(errno));
82+
if (log_file_path) {
83+
free(log_file_path);
84+
log_file_path = NULL;
12185
}
12286
}
12387

88+
/* Free the iniparser dictionary */
89+
iniparser_freedict(iniconfig);
12490
return log_file_path;
12591
}
12692

127-
/* Read the last portion of log file into buffer */
128-
static ssize_t read_log_tail(const char *log_file_path, char *buffer,
129-
size_t buffer_size)
93+
/* Read the last portion of log file into buffer
94+
* Buffer must be at least LOG_BUFFER_SIZE + 1 bytes */
95+
static ssize_t read_log_tail(const char *log_file_path, char *buffer)
13096
{
13197
FILE *log_fp = NULL;
98+
99+
/* Validate input parameters */
100+
if (!buffer) {
101+
fprintf(stderr, "ERROR: Buffer is NULL\n");
102+
return -1;
103+
}
104+
132105
DEBUG_LOG("Opening log file: %s", log_file_path);
133106
log_fp = fopen(log_file_path, "rb");
134107

@@ -164,10 +137,11 @@ static ssize_t read_log_tail(const char *log_file_path, char *buffer,
164137
return 0;
165138
}
166139

167-
/* Read from the end, up to buffer_size */
168-
long read_start = (file_size > (long)buffer_size) ? (file_size -
169-
(long)buffer_size) : 0;
170-
size_t read_size = (file_size > (long)buffer_size) ? buffer_size :
140+
/* Read from the end, up to LOG_BUFFER_SIZE to reserve space for null terminator */
141+
size_t max_read = LOG_BUFFER_SIZE;
142+
long read_start = (file_size > (long)max_read) ? (file_size -
143+
(long)max_read) : 0;
144+
size_t read_size = (file_size > (long)max_read) ? max_read :
171145
(size_t)file_size;
172146
DEBUG_LOG("Reading %zu bytes from position: %ld", read_size, read_start);
173147

@@ -186,6 +160,16 @@ static ssize_t read_log_tail(const char *log_file_path, char *buffer,
186160
return -1;
187161
}
188162

163+
/* Simple validation - fread cannot return more than requested */
164+
if (bytes_read > read_size) {
165+
fprintf(stderr, "ERROR: fread returned more bytes than requested\n");
166+
fclose(log_fp);
167+
return -1;
168+
}
169+
170+
/* Null-terminate the buffer
171+
* Since read_size <= LOG_BUFFER_SIZE and bytes_read <= read_size,
172+
* we know bytes_read <= LOG_BUFFER_SIZE, so this is always safe */
189173
buffer[bytes_read] = '\0';
190174
fclose(log_fp);
191175
return (ssize_t)bytes_read;
@@ -195,6 +179,12 @@ static ssize_t read_log_tail(const char *log_file_path, char *buffer,
195179
static char *find_dircache_stats_line(const char *buffer, size_t bytes_read)
196180
{
197181
char *stats_line = NULL;
182+
183+
/* Validate bytes_read before using for allocation */
184+
if (bytes_read == 0 || bytes_read > LOG_BUFFER_SIZE) {
185+
return NULL;
186+
}
187+
198188
/* Make a working copy of the buffer to avoid const issues */
199189
char *work_buffer = malloc(bytes_read + 1);
200190

@@ -255,6 +245,13 @@ static void display_last_log_lines(const char *buffer, size_t bytes_read)
255245
printf("(At least 'log level = default:info' is required)\n");
256246
printf("Last 10 lines of log file:\n");
257247
printf("---------------------------\n");
248+
249+
/* Validate bytes_read before using for allocation */
250+
if (bytes_read == 0 || bytes_read > LOG_BUFFER_SIZE) {
251+
printf("Invalid buffer size\n");
252+
return;
253+
}
254+
258255
/* Make a working copy of the buffer to avoid const issues */
259256
char *work_buffer = malloc(bytes_read + 1);
260257

@@ -324,12 +321,9 @@ static void display_last_log_lines(const char *buffer, size_t bytes_read)
324321
}
325322
}
326323

327-
#endif /* __linux__ */
328-
329324
/* Read and display dircache statistics from log file */
330-
static void display_dircache_statistics(void)
325+
void display_dircache_statistics(void)
331326
{
332-
#ifdef __linux__
333327
char *log_file_path = NULL;
334328
char *stats_line = NULL;
335329
static char buffer[LOG_BUFFER_SIZE + 1];
@@ -343,13 +337,20 @@ static void display_dircache_statistics(void)
343337
}
344338

345339
DEBUG_LOG("Log file path: %s", log_file_path);
346-
bytes_read = read_log_tail(log_file_path, buffer, LOG_BUFFER_SIZE);
340+
bytes_read = read_log_tail(log_file_path, buffer, sizeof(buffer));
347341

348342
if (bytes_read <= 0) {
349343
free(log_file_path);
350344
return;
351345
}
352346

347+
/* Validate bytes_read is positive and reasonable before casting */
348+
if (bytes_read < 0 || bytes_read > LOG_BUFFER_SIZE) {
349+
fprintf(stderr, "ERROR: Invalid bytes_read value: %zd\n", bytes_read);
350+
free(log_file_path);
351+
return;
352+
}
353+
353354
stats_line = find_dircache_stats_line(buffer, (size_t)bytes_read);
354355
printf("\nDircache Statistics (%s):\n", log_file_path);
355356
printf("------------------------------------------------------------------\n");
@@ -369,7 +370,14 @@ static void display_dircache_statistics(void)
369370
}
370371

371372
free(log_file_path);
372-
#else
373-
/* Not on Linux, function not available */
374-
#endif /* __linux__ */
375-
}
373+
}
374+
375+
#else /* !__linux__ */
376+
377+
/* Stub implementation for non-Linux systems */
378+
void display_dircache_statistics(void)
379+
{
380+
/* Not available on this platform */
381+
}
382+
383+
#endif /* __linux__ */
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Header file for lantest directory cache statistics functions
3+
*/
4+
5+
#ifndef LANTEST_DIRCACHE_STATS_H
6+
#define LANTEST_DIRCACHE_STATS_H
7+
8+
/* Function declaration for displaying dircache statistics */
9+
void display_dircache_statistics(void);
10+
11+
#endif /* LANTEST_DIRCACHE_STATS_H */

0 commit comments

Comments
 (0)