libefivar: Fix (instead of silence) the remaining warnings in libefivar.
[dragonfly.git] / usr.sbin / autofs / defined.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2016 The DragonFly Project
5  * Copyright (c) 2014 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * This software was developed by Edward Tomasz Napierala under sponsorship
9  * from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33
34 /*
35  * All the "defined" stuff is for handling variables,
36  * such as ${OSNAME}, in maps.
37  */
38
39 #include <sys/types.h>
40 #include <sys/utsname.h>
41 #include <assert.h>
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "common.h"
49
50 static TAILQ_HEAD(, defined_value)      defined_values;
51
52 static const char *
53 defined_find(const char *name)
54 {
55         struct defined_value *d;
56
57         TAILQ_FOREACH(d, &defined_values, d_next) {
58                 if (strcmp(d->d_name, name) == 0)
59                         return (d->d_value);
60         }
61
62         return (NULL);
63 }
64
65 char *
66 defined_expand(const char *string)
67 {
68         const char *value;
69         char c, *expanded, *name;
70         int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0;
71         bool backslashed = false, bracketed = false;
72
73         expanded = checked_strdup(string);
74
75         for (i = 0; string[i] != '\0'; i++) {
76                 c = string[i];
77                 if (c == '\\' && backslashed == false) {
78                         backslashed = true;
79                         continue;
80                 }
81                 if (backslashed) {
82                         backslashed = false;
83                         continue;
84                 }
85                 backslashed = false;
86                 if (c != '$')
87                         continue;
88
89                 /*
90                  * The 'before_len' variable contains the number
91                  * of characters before the '$'.
92                  */
93                 before_len = i;
94                 assert(i + 1 < (int)strlen(string));
95                 if (string[i + 1] == '{')
96                         bracketed = true;
97
98                 if (string[i + 1] == '\0') {
99                         log_warnx("truncated variable");
100                         return (NULL);
101                 }
102
103                 /*
104                  * Skip '$'.
105                  */
106                 i++;
107
108                 if (bracketed) {
109                         if (string[i + 1] == '\0') {
110                                 log_warnx("truncated variable");
111                                 return (NULL);
112                         }
113
114                         /*
115                          * Skip '{'.
116                          */
117                         i++;
118                 }
119
120                 /*
121                  * The 'name_off' variable contains the number
122                  * of characters before the variable name,
123                  * including the "$" or "${".
124                  */
125                 name_off = i;
126
127                 for (; string[i] != '\0'; i++) {
128                         c = string[i];
129                         /*
130                          * XXX: Decide on the set of characters that can be
131                          *      used in a variable name.
132                          */
133                         if (isalnum(c) || c == '_')
134                                 continue;
135
136                         /*
137                          * End of variable name.
138                          */
139                         if (bracketed) {
140                                 if (c != '}')
141                                         continue;
142
143                                 /*
144                                  * The 'after_off' variable contains the number
145                                  * of characters before the rest of the string,
146                                  * i.e. after the variable name.
147                                  */
148                                 after_off = i + 1;
149                                 assert(i > 1);
150                                 assert(i - 1 > name_off);
151                                 name_len = i - name_off;
152                                 break;
153                         }
154
155                         after_off = i;
156                         assert(i > 1);
157                         assert(i > name_off);
158                         name_len = i - name_off;
159                         break;
160                 }
161
162                 name = strndup(string + name_off, name_len);
163                 if (name == NULL)
164                         log_err(1, "strndup");
165                 value = defined_find(name);
166                 if (value == NULL) {
167                         log_warnx("undefined variable ${%s}", name);
168                         return (NULL);
169                 }
170
171                 /*
172                  * Concatenate it back.
173                  */
174                 ret = asprintf(&expanded, "%.*s%s%s",
175                     before_len, string, value, string + after_off);
176                 if (ret < 0)
177                         log_err(1, "asprintf");
178
179                 //log_debugx("\"%s\" expanded to \"%s\"", string, expanded);
180                 free(name);
181
182                 /*
183                  * Figure out where to start searching for next variable.
184                  */
185                 string = expanded;
186                 i = before_len + strlen(value);
187                 backslashed = bracketed = false;
188                 before_len = name_off = name_len = after_off = 0;
189                 assert(i <= (int)strlen(string));
190         }
191
192         if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) {
193                 log_warnx("truncated variable");
194                 return (NULL);
195         }
196
197         return (expanded);
198 }
199
200 static void
201 defined_add(const char *name, const char *value)
202 {
203         struct defined_value *d;
204         const char *found;
205
206         found = defined_find(name);
207         if (found != NULL)
208                 log_errx(1, "variable %s already defined", name);
209
210         log_debugx("defining variable %s=%s", name, value);
211
212         d = calloc(1, sizeof(*d));
213         if (d == NULL)
214                 log_err(1, "calloc");
215         d->d_name = checked_strdup(name);
216         d->d_value = checked_strdup(value);
217
218         TAILQ_INSERT_TAIL(&defined_values, d, d_next);
219 }
220
221 void
222 defined_parse_and_add(char *def)
223 {
224         char *name, *value;
225
226         value = def;
227         name = strsep(&value, "=");
228
229         if (value == NULL || value[0] == '\0')
230                 log_errx(1, "missing variable value");
231         if (name == NULL || name[0] == '\0')
232                 log_errx(1, "missing variable name");
233
234         defined_add(name, value);
235 }
236
237 void
238 defined_init(void)
239 {
240         struct utsname name;
241         int error;
242
243         TAILQ_INIT(&defined_values);
244
245         error = uname(&name);
246         if (error != 0)
247                 log_err(1, "uname");
248
249         defined_add("ARCH", name.machine);
250         defined_add("CPU", name.machine);
251         defined_add("DOLLAR", "$");
252         defined_add("HOST", name.nodename);
253         defined_add("OSNAME", name.sysname);
254         defined_add("OSREL", name.release);
255         defined_add("OSVERS", name.version);
256 }