xref: /dragonfly/usr.sbin/autofs/defined.c (revision 63bc498493e0888c7c5cc0b504fac8c967c31e74)
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 *
defined_find(const char * name)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 *
defined_expand(const char * string)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
defined_add(const char * name,const char * value)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
defined_parse_and_add(char * def)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
defined_init(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 }
257