Add system-wide config support for wsssht with proper precedence

- Update read_config_value_from_file() to support config precedence:
  1. ~/.config/wsssh/wssht.conf (user config)
  2. /etc/wsssht.conf (system config)
- Update man page to document config file precedence order
- Command line options still have highest priority
parent 28dccf5b
...@@ -108,9 +108,20 @@ Press Ctrl+C to close the tunnel and exit. ...@@ -108,9 +108,20 @@ Press Ctrl+C to close the tunnel and exit.
.RE .RE
.SH CONFIGURATION .SH CONFIGURATION
.B wsssht .B wsssht
supports a configuration file at supports configuration files with the following precedence order:
.RS
.IP 1. 3
Command line options (highest priority)
.IP 2. 3
User configuration:
.I ~/.config/wsssh/wssht.conf .I ~/.config/wsssh/wssht.conf
with the following options: .IP 3. 3
System configuration:
.I /etc/wsssht.conf
(lowest priority)
.RE
.PP
Configuration options:
.PP .PP
.RS .RS
.nf .nf
...@@ -130,10 +141,15 @@ Note: Unlike ...@@ -130,10 +141,15 @@ Note: Unlike
and and
.BR wsscp (1), .BR wsscp (1),
.B wsssht .B wsssht
uses its own configuration file uses its own configuration files
.I wssht.conf .I wssht.conf
instead of sharing instead of sharing
.I wsssh.conf. .I wsssh.conf.
System administrators can provide default settings in
.I /etc/wsssht.conf
which will be overridden by user settings in
.I ~/.config/wsssh/wssht.conf
and command line options.
.SH SEE ALSO .SH SEE ALSO
.BR wsssh (1), .BR wsssh (1),
.BR wsscp (1), .BR wsscp (1),
......
...@@ -92,47 +92,96 @@ char *read_config_value(const char *key) { ...@@ -92,47 +92,96 @@ char *read_config_value(const char *key) {
} }
char *read_config_value_from_file(const char *key, const char *config_file) { char *read_config_value_from_file(const char *key, const char *config_file) {
char *result = NULL;
// First try user config: ~/.config/wsssh/{config_file}.conf
char *home = getenv("HOME"); char *home = getenv("HOME");
if (!home) return NULL; if (home) {
char path[PATH_MAX]; char user_path[PATH_MAX];
snprintf(path, sizeof(path), "%s/.config/wsssh/%s.conf", home, config_file); snprintf(user_path, sizeof(user_path), "%s/.config/wsssh/%s.conf", home, config_file);
FILE *f = fopen(path, "r"); FILE *f = fopen(user_path, "r");
if (!f) return NULL; if (f) {
char line[256]; char line[256];
char section[64] = ""; char section[64] = "";
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
// Check for section headers // Check for section headers
if (line[0] == '[') { if (line[0] == '[') {
sscanf(line, "[%63[^]]", section); sscanf(line, "[%63[^]]", section);
continue; continue;
}
// Skip comments and empty lines
if (line[0] == '#' || line[0] == ';' || line[0] == '\n') continue;
char *equals = strchr(line, '=');
if (equals) {
*equals = '\0';
char *config_key = line;
char *value = equals + 1;
// Trim whitespace
while (*config_key == ' ' || *config_key == '\t') config_key++;
char *end = config_key + strlen(config_key) - 1;
while (end > config_key && (*end == ' ' || *end == '\t')) *end-- = '\0';
while (*value == ' ' || *value == '\t') value++;
end = value + strlen(value) - 1;
while (end > value && (*end == ' ' || *end == '\t' || *end == '\n')) *end-- = '\0';
// Check if key matches
if (strcmp(config_key, key) == 0) {
result = strdup(value);
break;
}
}
}
fclose(f);
} }
// Skip comments and empty lines }
if (line[0] == '#' || line[0] == ';' || line[0] == '\n') continue;
char *equals = strchr(line, '=');
if (equals) {
*equals = '\0';
char *config_key = line;
char *value = equals + 1;
// Trim whitespace
while (*config_key == ' ' || *config_key == '\t') config_key++;
char *end = config_key + strlen(config_key) - 1;
while (end > config_key && (*end == ' ' || *end == '\t')) *end-- = '\0';
while (*value == ' ' || *value == '\t') value++;
end = value + strlen(value) - 1;
while (end > value && (*end == ' ' || *end == '\t' || *end == '\n')) *end-- = '\0';
// Check if key matches (case-insensitive for section names) // If not found in user config, try system config: /etc/{config_file}.conf
if (strcmp(config_key, key) == 0) { if (!result) {
fclose(f); char system_path[PATH_MAX];
return strdup(value); snprintf(system_path, sizeof(system_path), "/etc/%s.conf", config_file);
FILE *f = fopen(system_path, "r");
if (f) {
char line[256];
char section[64] = "";
while (fgets(line, sizeof(line), f)) {
// Check for section headers
if (line[0] == '[') {
sscanf(line, "[%63[^]]", section);
continue;
}
// Skip comments and empty lines
if (line[0] == '#' || line[0] == ';' || line[0] == '\n') continue;
char *equals = strchr(line, '=');
if (equals) {
*equals = '\0';
char *config_key = line;
char *value = equals + 1;
// Trim whitespace
while (*config_key == ' ' || *config_key == '\t') config_key++;
char *end = config_key + strlen(config_key) - 1;
while (end > config_key && (*end == ' ' || *end == '\t')) *end-- = '\0';
while (*value == ' ' || *value == '\t') value++;
end = value + strlen(value) - 1;
while (end > value && (*end == ' ' || *end == '\t' || *end == '\n')) *end-- = '\0';
// Check if key matches
if (strcmp(config_key, key) == 0) {
result = strdup(value);
break;
}
}
} }
fclose(f);
} }
} }
fclose(f);
return NULL; return result;
} }
void print_trans_flag(void) { void print_trans_flag(void) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment