Annotation of freem/src/iniconf.c, revision 1.11
1.1 snw 1: /*
1.11 ! snw 2: * $Id: iniconf.c,v 1.10 2025/04/15 16:49:36 snw Exp $
1.1 snw 3: * Function implementations for reading
4: * FreeM configuration files
5: *
6: *
1.2 snw 7: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 8: * Copyright (C) 1998 MUG Deutschland
1.3 snw 9: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
1.1 snw 10: *
11: *
12: * This file is part of FreeM.
13: *
14: * FreeM is free software: you can redistribute it and/or modify
15: * it under the terms of the GNU Affero Public License as published by
16: * the Free Software Foundation, either version 3 of the License, or
17: * (at your option) any later version.
18: *
19: * FreeM is distributed in the hope that it will be useful,
20: * but WITHOUT ANY WARRANTY; without even the implied warranty of
21: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22: * GNU Affero Public License for more details.
23: *
24: * You should have received a copy of the GNU Affero Public License
25: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
26: *
1.4 snw 27: * $Log: iniconf.c,v $
1.11 ! snw 28: * Revision 1.10 2025/04/15 16:49:36 snw
! 29: * Make use of logprintf throughout codebase
! 30: *
1.10 snw 31: * Revision 1.9 2025/04/13 04:22:43 snw
32: * Fix snprintf calls
33: *
1.9 snw 34: * Revision 1.8 2025/04/10 15:31:25 snw
35: * Attempt to fix DosCopy calls for OS/2
36: *
1.8 snw 37: * Revision 1.7 2025/04/10 15:27:39 snw
38: * Detect Devuan distribution and fix OS/2 problem with iniconf.c
39: *
1.7 snw 40: * Revision 1.6 2025/04/10 01:24:38 snw
41: * Remove C++ style comments
42: *
1.6 snw 43: * Revision 1.5 2025/04/09 19:52:02 snw
44: * Eliminate as many warnings as possible while building with -Wall
45: *
1.5 snw 46: * Revision 1.4 2025/04/02 19:59:38 snw
47: * Automatically modify env.conf from fmadm reconfigure
48: *
1.4 snw 49: * Revision 1.3 2025/03/09 19:14:25 snw
50: * First phase of REUSE compliance and header reformat
51: *
1.3 snw 52: *
53: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
54: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 55: **/
56:
57: #define FALSE 0
58: #define TRUE 1
59: #include <stddef.h>
60: #include "iniconf.h"
61: #include "libfill.h"
62: #include <stdio.h>
63: #include <unistd.h>
64: #include <sys/types.h>
65: #include <pwd.h>
66: #include <string.h>
67: #include <limits.h>
1.4 snw 68: #include <fs.h>
1.1 snw 69: #include "mpsdef.h"
70:
1.7 snw 71: #if defined(__OS2__)
72: # include <os2.h>
73: #endif
74:
1.1 snw 75: extern char config_file[4096];
76:
77: #if !defined(PATH_MAX) && defined(_SCO_DS)
78: # define PATH_MAX 4096
79: #endif
80:
81: #if !defined(PATH_MAX) && defined(__gnu_hurd__)
82: # define PATH_MAX 1024
83: #endif
84:
85: #if !defined(PATH_MAX) && defined(_AIX)
86: # define PATH_MAX 1024
87: #endif
88:
89: #if defined(__NetBSD__) || defined(__FreeBSD__)
90: # include <sys/syslimits.h>
91: #endif
92:
1.6 snw 93: #if !defined(PATH_MAX)
94: # define PATH_MAX 4096
95: #endif
96:
97:
1.1 snw 98: int get_conf(char *section, char *key, char *value)
99: {
100: char *etcfile;
101: char *dotfile;
102: char *homedir;
103:
104: int exists_in_etc = FALSE;
105: int exists_in_dotfile = FALSE;
106: int dotexists;
107: int etcexists;
108:
109: char *etc_value;
110: char *dot_value;
111:
112: etc_value = (char *) malloc(CONF_BUFSIZE);
113: NULLPTRCHK(etc_value,"get_conf");
114: dot_value = (char *) malloc(CONF_BUFSIZE);
115: NULLPTRCHK(dot_value,"get_conf");
116:
117: etcfile = config_file;
118:
119:
120: #if !defined(__AMIGA) && !defined(_SCO_DS) && !defined(_AIX)
121: uid_t uid = geteuid();
122: struct passwd *pw = getpwuid(uid);
123:
124: if (pw == NULL) {
125: free (etc_value);
126: free (dot_value);
127:
128: return (FALSE);
129: }
130:
131: homedir = (char *) calloc(strlen(pw->pw_dir) + 1, sizeof(char));
132: NULLPTRCHK(homedir,"get_conf");
133:
134: (void) strcpy(homedir, pw->pw_dir);
135:
136: dotfile = calloc(PATH_MAX, sizeof(char));
137: NULLPTRCHK(dotfile,"get_conf");
138:
139: (void) strcat(dotfile, homedir);
140: (void) strcat(dotfile, "/.freemrc");
141:
142: etcexists = file_exists(etcfile);
143: dotexists = file_exists(dotfile);
144: #else
145:
146: #if defined(__AMIGA)
147: strcpy (etcfile, "./freem.conf");
148: etcexists = TRUE;
149: dotexists = FALSE;
150: #else
151: strcpy (etcfile, SYSCONFDIR"/freem.conf");
152:
153: etcexists = TRUE;
154: dotexists = FALSE;
155: #endif
156:
157: #endif
158:
159: if (etcexists == TRUE) {
160: exists_in_etc = read_profile_string(etcfile, section, key, etc_value);
161: }
162: else {
163: exists_in_etc = FALSE;
164: }
165:
166: if (dotexists == TRUE) {
167: exists_in_dotfile = read_profile_string(dotfile, section, key, dot_value);
168: }
169: else {
170: exists_in_dotfile = FALSE;
171: }
172:
173: if (exists_in_dotfile) {
174: strcpy (value, dot_value);
175:
176: free (etc_value);
177: free (dot_value);
178: #if !defined(__AMIGA) && !defined(_SCO_DS) && !defined(_AIX)
179: free (homedir);
180: free (dotfile);
181: #endif
182:
183: return (TRUE);
184: }
185:
186: if (exists_in_etc) {
187: strcpy(value, etc_value);
188:
189: free (etc_value);
190: free (dot_value);
191: #if !defined(__AMIGA) && !defined(_SCO_DS) && !defined(_AIX)
192: free (homedir);
193: free (dotfile);
194: #endif
195:
196: return (TRUE);
197: }
198:
199: free (etc_value);
200: free (dot_value);
201: #if !defined(__AMIGA) && !defined(_SCO_DS) && !defined(_AIX)
202: free (homedir);
203: free (dotfile);
204: #endif
205:
206: return (FALSE); /* didn't exist anywhere */
207: }
208:
209: int read_profile_string(char *file, char *section, char *key, char *value)
210: {
211:
212: register int i;
213:
214: FILE *fp;
215:
216: char *curkey;
217: char *curval;
218: char *fullsec;
219: char *cursec;
220: char *line;
221: int lnum = 0;
1.6 snw 222:
223: curkey = (char *) NULL;
1.1 snw 224:
225: fullsec = (char *) malloc(CONF_BUFSIZE);
226: NULLPTRCHK(fullsec,"read_profile_string");
227:
228: cursec = (char *) malloc(CONF_BUFSIZE);
229: NULLPTRCHK(cursec,"read_profile_string");
230:
231: line = (char *) malloc(CONF_BUFSIZE);
232: NULLPTRCHK(line,"read_profile_string");
233:
234:
235:
236:
1.9 snw 237: snprintf(fullsec, CONF_BUFSIZE - 1, "[%s]%c", section, '\0');
1.1 snw 238:
239: strcpy(cursec, "[]");
1.11 ! snw 240: if ((fp = fopen(file, "r")) == NULL) {
! 241: return FALSE;
! 242: }
1.1 snw 243:
1.9 snw 244: while(fgets(line, CONF_BUFSIZE - 1, fp) != NULL) {
1.1 snw 245: ++lnum;
246:
247: if(line[0] == '[') {
248: strcpy(cursec, line);
249:
250: for(i = 0; i < CONF_BUFSIZE; i++) {
251: if(cursec[i] == ']') {
252: cursec[i + 1] = '\0';
253: break;
254: }
255: }
256: }
257: else {
258: if ((line[0] != '[') && (strchr(line, '=') != NULL)) {
259: curkey = strtok(line, "=");
260: curval = strtok(NULL, "=");
261: curval = strtok(curval, "\n");
262:
263:
264: if((strcmp(curkey, key) == 0) && (strcmp(cursec, fullsec) == 0)) {
265: strcpy(value, curval);
266: (void) fclose(fp);
267:
268: free (fullsec);
269: free (curkey);
270: free (cursec);
271:
272: return(TRUE);
273: }
274: }
275: }
276:
277: }
278:
279: if (fp != NULL) {
280: (void) fclose(fp);
281: }
282:
283: /* if we've gotten here, the section and/or key was not found */
284: sprintf (value, "\0");
285:
286: free (fullsec);
287: free (curkey);
288: free (cursec);
289:
290: return(FALSE);
291:
292: }
293:
294: int file_exists(char *filename)
295: {
296: FILE *fp;
297:
298: if ((fp = fopen(filename, "r")) != NULL) {
299: (void) fclose(fp);
300:
301: return(TRUE);
302: }
303: else {
304: return(FALSE);
305: }
306: }
307:
1.4 snw 308: void parse_section_header(char *input, char *buf, size_t buflen)
309: {
310: strncpy (buf, &(input[1]), buflen);
311: buf[strlen (buf) - 2] = '\0';
312: }
313:
314: int modify_profile_string(char *file, char *section, char *key, char *value)
315: {
316: FILE *input_fp;
317: FILE *output_fp;
318: char output_filename[4096];
1.5 snw 319: char input_line[255];
1.4 snw 320: char current_section[255];
321: char *savptr;
322: char *current_key;
323: char tmpsi[255];
324: char tmps[255];
325: int changed = FALSE;
326:
1.9 snw 327: snprintf (output_filename, sizeof (output_filename) - 1, "%s.tmp", file);
1.4 snw 328:
329: if ((input_fp = fopen (file, "r")) == NULL) {
330: return FALSE;
331: }
332:
333: if ((output_fp = fopen (output_filename, "w+")) == NULL) {
334: fclose (input_fp);
335: return FALSE;
336: }
337:
338: while (fgets (input_line, 255, input_fp)) {
339: if (input_line[0] == '[') {
340: /* this is a section; write it unchanged */
341: fputs (input_line, output_fp);
342:
343: /* update the current section */
344: parse_section_header (input_line, current_section, 255);
345: }
346: else {
347: /* is this a key/value pair? */
348: if (strchr (input_line, '=') != NULL) {
349: /* are we in the requested section? */
350: if (strcmp (section, current_section) == 0) {
351: /* yes; we'll parse it */
352: strcpy (tmpsi, input_line);
353: savptr = tmpsi;
354: current_key = strtok_r (tmpsi, "=", &savptr);
355: /* is this key the one we're changing? */
356: if (strcmp (key, current_key) == 0) {
357: /* yes; modify it and write out*/
1.9 snw 358: snprintf (tmps, sizeof (tmps) - 1, "%s=%s\n", current_key, value);
1.4 snw 359:
360: fputs (tmps, output_fp);
361: changed = TRUE;
362: }
363: else {
364: /* not the requested key; pass it through unmodified */
365: fputs (input_line, output_fp);
366: }
367: }
368: else {
369: /* not the requested section; write it out unchanged */
370: fputs (input_line, output_fp);
371: }
372: }
373: else {
374: /* not a key/value pair; write it out unchanged */
375: fputs (input_line, output_fp);
376: }
377: }
378: }
379:
380: /* close both files */
381: fclose (output_fp);
382: fclose (input_fp);
383:
384: /* delete the original file */
385: unlink (file);
386:
387: /* rename the temporary file */
388: #if !defined(__OS2__)
389: cp (file, output_filename);
390: #else
1.8 snw 391: DosCopy (output_filename, file, 1);
1.4 snw 392: #endif
393:
394: return changed;
1.1 snw 395: }
396:
1.4 snw 397:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>