2 * UDP Gateway persistent configuration
3 * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
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; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <glib/gmessages.h>
23 #include <glib/ghash.h>
24 #include <glib/gstring.h>
25 #include <glib/gmem.h>
29 #include <glib/gstrfuncs.h>
32 #include "configuration.h" /* self */
37 /* OK, GConf would be nice.
38 * Unfortunately the fully-static build does not support GConf process spawn at
39 * all. Also /etc/sysconfig directory is standard for the daemon services.
44 #define CONFIGURATION_FILE "/etc/sysconfig/udpgate"
47 static GHashTable *configuration_hash_new(void)
49 return g_hash_table_new_full(g_str_hash,g_str_equal,
50 (GDestroyNotify)g_free, /* key_equal_func; of g_strdup() strings */
51 (GDestroyNotify)g_free); /* value_equal_func; of g_strdup() strings */
54 static GHashTable *configuration_comments_hash_new(void)
56 static GHashTable *hash;
59 hash=g_hash_table_new(g_str_hash,g_str_equal);
60 g_hash_table_insert(hash,"PORT",_("Local UDP port"));
65 static gboolean configuration_file_write(const gchar *file_content)
69 g_return_val_if_fail(file_content!=NULL,FALSE);
71 if (!(f=fopen(CONFIGURATION_FILE,("w")))) {
72 g_warning(_("Error write opening configuration file \"%s\": %m"),CONFIGURATION_FILE);
75 if (fputs(file_content,f)<0) {
76 g_warning(_("Error writing configuration file \"%s\": %m"),CONFIGURATION_FILE);
77 fclose(f); /* errors ignored */
81 g_warning(_("Error closing configuration file \"%s\": %m"),CONFIGURATION_FILE);
85 struct configuration_hash_readwrite_hash_flush_foreach_param {
87 GHashTable *hash_flushed;
90 static void configuration_hash_readwrite_hash_flush_foreach
91 (const gchar *key,const gchar *value,struct configuration_hash_readwrite_hash_flush_foreach_param *param)
95 g_return_if_fail(key!=NULL);
96 g_return_if_fail(value!=NULL);
97 g_return_if_fail(param!=NULL);
98 g_return_if_fail(param->gstring!=NULL);
99 g_return_if_fail(param->hash_flushed!=NULL);
101 /* Already written out? */
102 if (g_hash_table_lookup(param->hash_flushed,key))
104 if (!(comment=g_hash_table_lookup(configuration_comments_hash_new(),key)))
105 comment=_("*** UNDOCUMENTED ***");
106 g_string_append(param->gstring,udpgate_printf_alloca("# %s: %s\n%s=%s\n",key,comment,key,value));
107 param->modified=TRUE;
109 g_message(_("Appended configuration variable name \"%s\", value \"%s\""),key,value);
112 /* hash_flush==NULL => read info and return new (GHashTable *)
113 * hash_flush!=NULL => update configuration file by this (GHashTable *)
115 /* FIXME: File locking! */
116 static GHashTable *configuration_hash_readwrite(GHashTable *hash_flush)
121 GHashTable *hash_fill;
122 /* Which 'keys' of 'hash_flush' were already written. 'key' must be g_free()able.
123 * Any 'value' is ignored. 'value' must be !=NULL. 'value' must be g_free()able.
125 GHashTable *hash_flushed;
127 gboolean modified=FALSE; /* 'gstring' contains modified value */
128 gboolean already_written=FALSE;
131 if (!(f=fopen(CONFIGURATION_FILE,(!hash_flush ? "r" : "rw")))) {
133 g_warning(_("Error r/o opening configuration file \"%s\": %m"),CONFIGURATION_FILE);
134 if (!hash_flush || already_written)
137 already_written=TRUE;
138 if (!configuration_file_write(_(
139 "# Configuration file for UDPGate - see its man page udpgate(1).\n"
147 hash_fill=configuration_hash_new();
153 hash_flushed=configuration_hash_new();
154 gstring=g_string_new(NULL);
157 while (errno=0,fgets(line,sizeof(line),f)) {
159 char *varname_start,*varname_stop,varname_stop_orig;
160 char *varcontent_start,*varcontent_stop,varcontent_stop_orig;
166 varcontent_stop=NULL;
167 /* Parse: ^\s*([[:alnum:]])\s*=\s*(\S*)\s*$
169 while (*s && isspace(*s)) s++;
170 if (!*s || *s=='#') {
173 g_string_append(gstring,line);
177 while (*s && isalnum(*s)) s++;
179 varname_stop_orig=*varname_stop;
180 while (*s && isspace(*s)) s++;
184 *varname_stop=varname_stop_orig;
186 *varcontent_stop=varcontent_stop_orig;
187 g_warning(_("Error parsing line %d of the configuration file \"%s\": %s"),lineno,CONFIGURATION_FILE,line);
190 while (*s && isspace(*s)) s++;
194 while (*s && !isspace(*s)) s++;
196 varcontent_stop_orig=*varcontent_stop;
197 while (*s && isspace(*s)) s++;
201 if (!*varname_start || !*varcontent_start)
205 *varcontent_stop='\0';
207 g_message(_("Parsed configuration variable name \"%s\", value \"%s\""),varname_start,varcontent_start);
210 hash_fill, /* hash_table */
211 g_strdup(varname_start), /* key */
212 g_strdup(varcontent_start)); /* value */
213 if (hash_flush && (value=g_hash_table_lookup(hash_flush,varname_start))) {
214 const char *line_new=udpgate_printf_alloca("%s=%s\n",varname_start,value);
216 *varname_stop=varname_stop_orig;
217 *varcontent_stop=varcontent_stop_orig;
218 if (strcmp(line,line_new))
222 g_string_append(gstring,line_new);
223 g_hash_table_insert(hash_flushed,g_strdup(varname_start),g_strdup(varcontent_start));
229 g_warning(_("Error reading line from the configuration file \"%s\": %s"),CONFIGURATION_FILE,strerror(errno));
231 g_hash_table_destroy(hash_fill);
232 fclose(f); /* errors ignored */
236 g_warning(_("Error closing configuration file \"%s\": %m"),CONFIGURATION_FILE);
238 struct configuration_hash_readwrite_hash_flush_foreach_param param;
240 /* Append variable names not yet present in the file */
241 param.gstring=gstring;
242 param.hash_flushed=hash_flushed;
243 param.modified=modified;
244 g_hash_table_foreach(hash_flush,(GHFunc)configuration_hash_readwrite_hash_flush_foreach,¶m);
245 g_hash_table_destroy(hash_flushed);
247 modified=param.modified;
251 configuration_file_write(gstring->str); /* errors ignored */
252 g_string_free(gstring,
253 TRUE); /* free_segment */
259 static void configuration_read_hash_foreach(const gchar *key,const gchar *value,gpointer user_data)
261 g_return_if_fail(key!=NULL);
262 g_return_if_fail(value!=NULL);
264 if (!strcmp(key,"PORT"))
265 optarg_port_set_string(value);
267 g_warning(_("Unknown configuration key \"%s\" with value \"%s\" found in the file \"%s\""),
268 key,value,CONFIGURATION_FILE);
271 gboolean configuration_read(void)
275 if (!(hash=configuration_hash_readwrite(NULL)))
277 g_hash_table_foreach(hash,(GHFunc)configuration_read_hash_foreach,NULL);
278 g_hash_table_destroy(hash);
282 gboolean configuration_write(void)
286 hash=g_hash_table_new(g_str_hash,g_str_equal);
287 g_hash_table_insert(hash,"PORT",(/* de-const */ gpointer)udpgate_printf_alloca("%d",(int)optarg_port));
288 configuration_hash_readwrite(hash); /* FIXME: errors ignored */
289 g_hash_table_destroy(hash);