unix/dualinit

src/config.c in master
Repositories | Summary | Log | Files | LICENSE

config.c (8381B) download


  1#include "config.h"
  2
  3#include "common.h"
  4#include "mount.h"
  5
  6#include <ctype.h>
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <sys/fcntl.h>
 11#include <sys/mount.h>
 12#include <unistd.h>
 13
 14#define CHECK_SECTION              \
 15	if (current_section == NULL) { \
 16		result = P_USAGE;          \
 17		goto error;                \
 18	}
 19
 20#define CHECK_ROOT                 \
 21	if (current_section != NULL) { \
 22		result = P_USAGE;          \
 23		goto error;                \
 24	}
 25
 26#define CHECK_PARAMS_EQUALS(n) \
 27	if (columns_size != (n)) { \
 28		result = P_USAGE;      \
 29		goto error;            \
 30	}
 31
 32#define CHECK_PARAMS_BETWEEN(a, b)                  \
 33	if (columns_size < (a) || columns_size > (b)) { \
 34		result = P_USAGE;                           \
 35		goto error;                                 \
 36	}
 37
 38#define CHECK_PARAMS_MORE(a)  \
 39	if (columns_size < (a)) { \
 40		result = P_USAGE;     \
 41		goto error;           \
 42	}
 43
 44#define PARSE_BOOL(dest)                   \
 45	if (streq(columns[1], "true"))         \
 46		dest = true;                       \
 47	else if (streq(columns[1], "false")) { \
 48		dest = false;                      \
 49	} else {                               \
 50		result = P_DATA;                   \
 51		goto error;                        \
 52	}
 53
 54
 55section_t sections[SECTION_MAX];
 56mount_t	  mounts[SECTION_MOUNT_MAX];
 57int		  section_size = 0;
 58int		  mount_size   = 0;
 59bool	  color		   = false;
 60bool	  verbose	   = true;
 61int		  timeout	   = 10;
 62
 63
 64parse_error_t config_parse(int fd, const char* filename) {
 65	FILE* file = fdopen(fd, "r");
 66	return config_parsef(file, filename);
 67}
 68
 69parse_error_t config_parsef(FILE* file, const char* filename) {
 70	section_t*	  current_section = NULL;
 71	bool		  in_mount		  = false;
 72	int			  linenr		  = 0;
 73	parse_error_t result		  = 0;
 74	int			  columns_size	  = 0;
 75	size_t		  alloc			  = 0;
 76	char*		  line_origin	  = NULL;
 77	ssize_t		  len			  = 0;
 78	ssize_t		  last_blank	  = 0;
 79	char*		  line			  = NULL;
 80	char		  columns[10][100];
 81
 82	// `getline` fetches one line from `file`
 83	while ((len = getline(&line_origin, &alloc, file)) > 0) {
 84		linenr++;
 85		// as `getline` doesn't add a terminating `\0`, concatinate it
 86		if (len + 1 > (ssize_t) alloc) {
 87			line = realloc(line_origin, alloc = len + 1);
 88			if (line == NULL) {
 89				printf("error: cannot allocate line\n");
 90				result = P_ALLOC;
 91				goto error;
 92			}
 93			line_origin = line;
 94		} else {
 95			line = line_origin;
 96		}
 97		line[len] = '\0';
 98
 99		last_blank = -1;
100
101		// some truncating
102		while (isblank(line[0]))
103			line++, len--;
104
105		for (ssize_t i = 0; i < len; i++) {
106			if (isblank(line[i])) {
107				if (last_blank == -1)
108					last_blank = i;
109			} else if (line[i] == '\n' || line[i] == ';' || line[i] == '#') {
110				len = (last_blank != -1) ? last_blank : i;
111				break;
112			} else {
113				last_blank = -1;
114			}
115		}
116
117		// if it's an empty string, skip it
118		if (len == 0)
119			continue;
120
121		// parse colums (aka. split by string)
122		columns_size	  = 0;
123		int	 column_index = 0;
124		bool string		  = false;
125		for (ssize_t i = 0; i <= len; i++) {
126			if (i == len || (isblank(line[i]) && !string)) {
127				if (column_index == 1 && columns[columns_size][0] == '-') {
128					columns[columns_size][0] = '\0';
129					columns_size++;
130					column_index = 0;
131				} else if (column_index > 0) {
132					columns[columns_size][column_index] = '\0';
133					columns_size++;
134					column_index = 0;
135				}
136			} else if (line[i] == '"') {
137				string = !string;
138			} else {
139				columns[columns_size][column_index++] = line[i];
140			}
141		}
142
143		// end
144		if (streq(columns[0], "end")) {
145			CHECK_PARAMS_EQUALS(1);
146
147			if (in_mount) {
148				in_mount = false;
149			} else if (current_section != NULL) {
150				current_section = NULL;
151			} else {
152				result = P_SCOPE;
153				goto error;
154			}
155			// <fstype> <source> <target> [options]
156		} else if (in_mount) {
157			CHECK_PARAMS_BETWEEN(3, 4);
158
159			mount_t* mnt = (current_section != NULL)
160							 ? &current_section->mounts[current_section->mount_size++]
161							 : &mounts[mount_size++];
162
163			mnt->try	= columns[0][0] == '*';
164			mnt->type	= strdupn(mnt->try ? columns[0] + 1 : columns[0]);
165			mnt->source = strdupn(columns[1]);
166			mnt->target = strdupn(columns[2]);
167			if (columns_size == 4) {
168				mnt->flags = mount_flags(columns[3], &mnt->options);
169			} else {
170				mnt->flags	 = 0;
171				mnt->options = NULL;
172			}
173			// mount
174		} else if (streq(columns[0], "mount")) {
175			CHECK_PARAMS_EQUALS(1);
176
177			in_mount = true;
178			// section
179		} else if (streq(columns[0], "section")) {
180			CHECK_ROOT;
181			CHECK_PARAMS_EQUALS(3);
182
183			if (current_section != NULL) {
184				result = P_REDEF;
185				goto error;
186			}
187
188			current_section				= &sections[section_size++];
189			current_section->init		= NULL;
190			current_section->mount_size = 0;
191			current_section->name		= strdupn(columns[1]);
192			current_section->root		= strdupn(columns[2]);
193			// rshare/share <dirs...>
194		} else if (streq(columns[0], "rshare") || streq(columns[0], "share")) {
195			CHECK_PARAMS_MORE(2);
196
197			for (int i = 1; i < columns_size; i++) {
198				mount_t* mnt = (current_section != NULL)
199								 ? &current_section->mounts[current_section->mount_size++]
200								 : &mounts[mount_size++];
201
202				char* target = columns[i];
203
204				mnt->try = target[0] == '*';
205				if (mnt->try)
206					target++;
207				mnt->source	 = strdupn(target);
208				mnt->target	 = strdupn(target);
209				mnt->type	 = NULL;
210				mnt->options = NULL;
211				mnt->flags	 = MS_BIND;
212				if (columns[0][0] == 'r')	 // aka. equals rshare
213					mnt->flags |= MS_REC;
214			}
215			// color <enable>
216		} else if (streq(columns[0], "color")) {
217			CHECK_ROOT;
218			CHECK_PARAMS_EQUALS(2);
219
220			PARSE_BOOL(color);
221			// verbose <enable>
222		} else if (streq(columns[0], "verbose")) {
223			CHECK_ROOT;
224			CHECK_PARAMS_EQUALS(2);
225
226			PARSE_BOOL(verbose);
227			// timeout <seconds>
228		} else if (streq(columns[0], "timeout")) {
229			CHECK_ROOT;
230			CHECK_PARAMS_EQUALS(2);
231
232			char* end;
233			timeout = strtol(columns[1], &end, 10);
234			if (end != strchr(columns[1], '\0')) {
235				result = P_DATA;
236				goto error;
237			}
238			// init <path>
239		} else if (streq(columns[0], "init")) {
240			CHECK_SECTION;
241			CHECK_PARAMS_MORE(2);
242
243			if (current_section->init != NULL) {
244				result = P_REDEF;
245				goto error;
246			}
247
248			current_section->init = strdupn(columns[1]);
249			// include <file>
250		} else if (streq(columns[0], "include")) {
251			CHECK_ROOT;
252			CHECK_PARAMS_EQUALS(2);
253
254			int fd = open(columns[1], O_RDONLY | O_NONBLOCK);
255			result = config_parse(fd, columns[1]);
256			close(fd);
257			if (result != 0)
258				goto cleanup;
259			// mmpf, unknown command
260		} else {
261			result = P_IDENTIFIER;
262			goto error;
263		}
264	}
265
266	// if there were no sections, raise an error as that not the intension
267	if (section_size == 0) {
268		result = P_SECTION;
269		goto error;
270	}
271
272	// if you reach this, there were no errors
273	// just skip to `cleanup`
274	goto cleanup;
275
276error:
277	// pretty-print error
278	printf("error in %s:%d: ", filename, linenr);
279	switch (result) {
280		case P_ALLOC:
281			printf("cannot allocate line\n");
282			break;
283		case P_SECTION:
284			printf("no section defined\n");
285			break;
286		case P_IDENTIFIER:
287			printf("unknown identifier '%s'\n", columns[0]);
288			break;
289		case P_USAGE:
290			printf("invalid usage of command '%s'\n", columns[0]);
291			break;
292		case P_SCOPE:
293			printf("invalid scope of command '%s'\n", columns[0]);
294			break;
295		case P_DATA:
296			printf("invalid paramter-type of '%s'\n", columns[0]);
297			break;
298		case P_REDEF:
299			printf("redefinition of '%s'\n", columns[0]);
300			break;
301	}
302	config_cleanup();
303
304cleanup:
305	if (line_origin != NULL)
306		free(line_origin);
307
308	return result;
309}
310
311void config_free_mount(mount_t* mount, int size) {
312	for (int i = 0; i < size; i++) {
313		if (mount[i].type != NULL)
314			free((void*) mount[i].type);
315		if (mount[i].source != NULL)
316			free((void*) mount[i].source);
317		if (mount[i].target != NULL)
318			free((void*) mount[i].target);
319		if (mount[i].options != NULL)
320			free((void*) mount[i].options);
321	}
322}
323
324void config_cleanup() {
325	config_free_mount(mounts, mount_size);
326	mount_size = 0;
327
328	for (int i = 0; i < section_size; i++) {
329		if (sections[i].name != NULL)
330			free((void*) sections[i].name);
331		if (sections[i].root != NULL)
332			free((void*) sections[i].root);
333		if (sections[i].init != NULL)
334			free((void*) sections[i].init);
335		config_free_mount(sections[i].mounts, sections[i].mount_size);
336	}
337	section_size = 0;
338}
339
340void config_reset() {
341	config_cleanup();
342
343	section_size = 0;
344	mount_size	 = 0;
345	color		 = false;
346	verbose		 = true;
347	timeout		 = 10;
348}