1 /*
2  * This file contains helper functions for labeling support.
3  *
4  * Author : Richard Haines <richard_c_haines@btinternet.com>
5  */
6 
7 #include <stdlib.h>
8 #include <stdarg.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include <errno.h>
12 #include "label_internal.h"
13 
14 /*
15  * The read_spec_entries and read_spec_entry functions may be used to
16  * replace sscanf to read entries from spec files. The file and
17  * property services now use these.
18  */
19 
20 /*
21  * Read an entry from a spec file (e.g. file_contexts)
22  * entry - Buffer to allocate for the entry.
23  * ptr - current location of the line to be processed.
24  * returns  - 0 on success and *entry is set to be a null
25  *            terminated value. On Error it returns -1 and
26               errno will be set.
27  *
28  */
read_spec_entry(char ** entry,char ** ptr,int * len,const char ** errbuf)29 static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf)
30 {
31 	*entry = NULL;
32 	char *tmp_buf = NULL;
33 
34 	while (isspace(**ptr) && **ptr != '\0')
35 		(*ptr)++;
36 
37 	tmp_buf = *ptr;
38 	*len = 0;
39 
40 	while (!isspace(**ptr) && **ptr != '\0') {
41 		if (!isascii(**ptr)) {
42 			errno = EINVAL;
43 			*errbuf = "Non-ASCII characters found";
44 			return -1;
45 		}
46 		(*ptr)++;
47 		(*len)++;
48 	}
49 
50 	if (*len) {
51 		*entry = strndup(tmp_buf, *len);
52 		if (!*entry)
53 			return -1;
54 	}
55 
56 	return 0;
57 }
58 
59 /*
60  * line_buf - Buffer containing the spec entries .
61  * errbuf   - Double pointer used for passing back specific error messages.
62  * num_args - The number of spec parameter entries to process.
63  * ...      - A 'char **spec_entry' for each parameter.
64  * returns  - The number of items processed. On error, it returns -1 with errno
65  *            set and may set errbuf to a specific error message.
66  *
67  * This function calls read_spec_entry() to do the actual string processing.
68  * As such, can return anything from that function as well.
69  */
read_spec_entries(char * line_buf,const char ** errbuf,int num_args,...)70 int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...)
71 {
72 	char **spec_entry, *buf_p;
73 	int len, rc, items, entry_len = 0;
74 	va_list ap;
75 
76 	*errbuf = NULL;
77 
78 	len = strlen(line_buf);
79 	if (line_buf[len - 1] == '\n')
80 		line_buf[len - 1] = '\0';
81 	else
82 		/* Handle case if line not \n terminated by bumping
83 		 * the len for the check below (as the line is NUL
84 		 * terminated by getline(3)) */
85 		len++;
86 
87 	buf_p = line_buf;
88 	while (isspace(*buf_p))
89 		buf_p++;
90 
91 	/* Skip comment lines and empty lines. */
92 	if (*buf_p == '#' || *buf_p == '\0')
93 		return 0;
94 
95 	/* Process the spec file entries */
96 	va_start(ap, num_args);
97 
98 	items = 0;
99 	while (items < num_args) {
100 		spec_entry = va_arg(ap, char **);
101 
102 		if (len - 1 == buf_p - line_buf) {
103 			va_end(ap);
104 			return items;
105 		}
106 
107 		rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf);
108 		if (rc < 0) {
109 			va_end(ap);
110 			return rc;
111 		}
112 		if (entry_len)
113 			items++;
114 	}
115 	va_end(ap);
116 	return items;
117 }
118