Blame


1 1d126e2d 2019-08-24 stsp /* $OpenBSD: conf.c,v 1.107 2017/10/27 08:29:32 mpi Exp $ */
2 1d126e2d 2019-08-24 stsp /* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */
3 1d126e2d 2019-08-24 stsp
4 1d126e2d 2019-08-24 stsp /*
5 1d126e2d 2019-08-24 stsp * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
6 1ff82748 2023-02-17 thomas * Copyright (c) 2000, 2001, 2002 HÃ¥kan Olsson. All rights reserved.
7 1d126e2d 2019-08-24 stsp *
8 1d126e2d 2019-08-24 stsp * Redistribution and use in source and binary forms, with or without
9 1d126e2d 2019-08-24 stsp * modification, are permitted provided that the following conditions
10 1d126e2d 2019-08-24 stsp * are met:
11 1d126e2d 2019-08-24 stsp * 1. Redistributions of source code must retain the above copyright
12 1d126e2d 2019-08-24 stsp * notice, this list of conditions and the following disclaimer.
13 1d126e2d 2019-08-24 stsp * 2. Redistributions in binary form must reproduce the above copyright
14 1d126e2d 2019-08-24 stsp * notice, this list of conditions and the following disclaimer in the
15 1d126e2d 2019-08-24 stsp * documentation and/or other materials provided with the distribution.
16 1d126e2d 2019-08-24 stsp *
17 1d126e2d 2019-08-24 stsp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1d126e2d 2019-08-24 stsp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1d126e2d 2019-08-24 stsp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1d126e2d 2019-08-24 stsp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1d126e2d 2019-08-24 stsp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1d126e2d 2019-08-24 stsp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1d126e2d 2019-08-24 stsp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1d126e2d 2019-08-24 stsp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1d126e2d 2019-08-24 stsp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 1d126e2d 2019-08-24 stsp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1d126e2d 2019-08-24 stsp */
28 1d126e2d 2019-08-24 stsp
29 1d126e2d 2019-08-24 stsp #include <sys/types.h>
30 8b925c6c 2022-07-16 thomas #include <sys/queue.h>
31 1d126e2d 2019-08-24 stsp #include <sys/stat.h>
32 1d126e2d 2019-08-24 stsp
33 1d126e2d 2019-08-24 stsp #include <ctype.h>
34 1d126e2d 2019-08-24 stsp #include <fcntl.h>
35 1d126e2d 2019-08-24 stsp #include <stdarg.h>
36 1d126e2d 2019-08-24 stsp #include <stdio.h>
37 1d126e2d 2019-08-24 stsp #include <stdlib.h>
38 1d126e2d 2019-08-24 stsp #include <string.h>
39 1d126e2d 2019-08-24 stsp #include <unistd.h>
40 1d126e2d 2019-08-24 stsp #include <errno.h>
41 1d126e2d 2019-08-24 stsp
42 dd038bc6 2021-09-21 thomas.ad #include "got_compat.h"
43 dd038bc6 2021-09-21 thomas.ad
44 1d126e2d 2019-08-24 stsp #include "got_error.h"
45 1d126e2d 2019-08-24 stsp
46 1d126e2d 2019-08-24 stsp #include "got_lib_gitconfig.h"
47 1d126e2d 2019-08-24 stsp
48 1d126e2d 2019-08-24 stsp #ifndef nitems
49 1d126e2d 2019-08-24 stsp #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
50 1d126e2d 2019-08-24 stsp #endif
51 1d126e2d 2019-08-24 stsp
52 1d126e2d 2019-08-24 stsp #define LOG_MISC 0
53 1d126e2d 2019-08-24 stsp #define LOG_REPORT 1
54 1d126e2d 2019-08-24 stsp #ifdef GITCONFIG_DEBUG
55 1d126e2d 2019-08-24 stsp #define LOG_DBG(x) log_debug x
56 1d126e2d 2019-08-24 stsp #else
57 1d126e2d 2019-08-24 stsp #define LOG_DBG(x)
58 1d126e2d 2019-08-24 stsp #endif
59 1d126e2d 2019-08-24 stsp
60 5fab8a45 2023-02-23 thomas #define log_print(...) fprintf(stderr, __VA_ARGS__)
61 5fab8a45 2023-02-23 thomas #define log_error(...) fprintf(stderr, __VA_ARGS__)
62 1d126e2d 2019-08-24 stsp
63 1d126e2d 2019-08-24 stsp #ifdef GITCONFIG_DEBUG
64 1d126e2d 2019-08-24 stsp static void
65 1d126e2d 2019-08-24 stsp log_debug(int cls, int level, const char *fmt, ...)
66 1d126e2d 2019-08-24 stsp {
67 1d126e2d 2019-08-24 stsp va_list ap;
68 1d126e2d 2019-08-24 stsp
69 1d126e2d 2019-08-24 stsp va_start(ap, fmt);
70 1d126e2d 2019-08-24 stsp vfprintf(stderr, fmt, ap);
71 1d126e2d 2019-08-24 stsp va_end(ap);
72 b6ac0d36 2023-02-20 thomas putc('\n', stderr);
73 1d126e2d 2019-08-24 stsp }
74 1d126e2d 2019-08-24 stsp #endif
75 1d126e2d 2019-08-24 stsp
76 1d126e2d 2019-08-24 stsp struct got_gitconfig_trans {
77 1d126e2d 2019-08-24 stsp TAILQ_ENTRY(got_gitconfig_trans) link;
78 1d126e2d 2019-08-24 stsp int trans;
79 1d126e2d 2019-08-24 stsp enum got_gitconfig_op {
80 1d126e2d 2019-08-24 stsp CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION
81 1d126e2d 2019-08-24 stsp } op;
82 1d126e2d 2019-08-24 stsp char *section;
83 1d126e2d 2019-08-24 stsp char *tag;
84 1d126e2d 2019-08-24 stsp char *value;
85 1d126e2d 2019-08-24 stsp int override;
86 1d126e2d 2019-08-24 stsp int is_default;
87 1d126e2d 2019-08-24 stsp };
88 1d126e2d 2019-08-24 stsp
89 1d126e2d 2019-08-24 stsp TAILQ_HEAD(got_gitconfig_trans_head, got_gitconfig_trans);
90 1d126e2d 2019-08-24 stsp
91 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding {
92 1d126e2d 2019-08-24 stsp LIST_ENTRY(got_gitconfig_binding) link;
93 1d126e2d 2019-08-24 stsp char *section;
94 1d126e2d 2019-08-24 stsp char *tag;
95 1d126e2d 2019-08-24 stsp char *value;
96 1d126e2d 2019-08-24 stsp int is_default;
97 1d126e2d 2019-08-24 stsp };
98 1d126e2d 2019-08-24 stsp
99 1d126e2d 2019-08-24 stsp LIST_HEAD(got_gitconfig_bindings, got_gitconfig_binding);
100 1d126e2d 2019-08-24 stsp
101 1d126e2d 2019-08-24 stsp struct got_gitconfig {
102 1d126e2d 2019-08-24 stsp struct got_gitconfig_bindings bindings[256];
103 1d126e2d 2019-08-24 stsp struct got_gitconfig_trans_head trans_queue;
104 1d126e2d 2019-08-24 stsp char *addr;
105 1d126e2d 2019-08-24 stsp int seq;
106 1d126e2d 2019-08-24 stsp };
107 1d126e2d 2019-08-24 stsp
108 1d126e2d 2019-08-24 stsp static __inline__ u_int8_t
109 49d691e8 2021-09-25 thomas.ad conf_hash(const char *s)
110 1d126e2d 2019-08-24 stsp {
111 1d126e2d 2019-08-24 stsp u_int8_t hash = 0;
112 1d126e2d 2019-08-24 stsp
113 1d126e2d 2019-08-24 stsp while (*s) {
114 1d126e2d 2019-08-24 stsp hash = ((hash << 1) | (hash >> 7)) ^ tolower((unsigned char)*s);
115 1d126e2d 2019-08-24 stsp s++;
116 1d126e2d 2019-08-24 stsp }
117 1d126e2d 2019-08-24 stsp return hash;
118 1d126e2d 2019-08-24 stsp }
119 1d126e2d 2019-08-24 stsp
120 1d126e2d 2019-08-24 stsp /*
121 1d126e2d 2019-08-24 stsp * Insert a tag-value combination from LINE (the equal sign is at POS)
122 1d126e2d 2019-08-24 stsp */
123 1d126e2d 2019-08-24 stsp static int
124 1d126e2d 2019-08-24 stsp conf_remove_now(struct got_gitconfig *conf, char *section, char *tag)
125 1d126e2d 2019-08-24 stsp {
126 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *cb, *next;
127 1d126e2d 2019-08-24 stsp
128 1d126e2d 2019-08-24 stsp for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb;
129 1d126e2d 2019-08-24 stsp cb = next) {
130 1d126e2d 2019-08-24 stsp next = LIST_NEXT(cb, link);
131 1d126e2d 2019-08-24 stsp if (strcasecmp(cb->section, section) == 0 &&
132 1d126e2d 2019-08-24 stsp strcasecmp(cb->tag, tag) == 0) {
133 1d126e2d 2019-08-24 stsp LIST_REMOVE(cb, link);
134 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section,
135 1d126e2d 2019-08-24 stsp tag, cb->value));
136 1d126e2d 2019-08-24 stsp free(cb->section);
137 1d126e2d 2019-08-24 stsp free(cb->tag);
138 1d126e2d 2019-08-24 stsp free(cb->value);
139 1d126e2d 2019-08-24 stsp free(cb);
140 1d126e2d 2019-08-24 stsp return 0;
141 1d126e2d 2019-08-24 stsp }
142 1d126e2d 2019-08-24 stsp }
143 1d126e2d 2019-08-24 stsp return 1;
144 1d126e2d 2019-08-24 stsp }
145 1d126e2d 2019-08-24 stsp
146 1d126e2d 2019-08-24 stsp static int
147 1d126e2d 2019-08-24 stsp conf_remove_section_now(struct got_gitconfig *conf, char *section)
148 1d126e2d 2019-08-24 stsp {
149 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *cb, *next;
150 1d126e2d 2019-08-24 stsp int unseen = 1;
151 1d126e2d 2019-08-24 stsp
152 1d126e2d 2019-08-24 stsp for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb;
153 1d126e2d 2019-08-24 stsp cb = next) {
154 1d126e2d 2019-08-24 stsp next = LIST_NEXT(cb, link);
155 1d126e2d 2019-08-24 stsp if (strcasecmp(cb->section, section) == 0) {
156 1d126e2d 2019-08-24 stsp unseen = 0;
157 1d126e2d 2019-08-24 stsp LIST_REMOVE(cb, link);
158 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section,
159 1d126e2d 2019-08-24 stsp cb->tag, cb->value));
160 1d126e2d 2019-08-24 stsp free(cb->section);
161 1d126e2d 2019-08-24 stsp free(cb->tag);
162 1d126e2d 2019-08-24 stsp free(cb->value);
163 1d126e2d 2019-08-24 stsp free(cb);
164 1d126e2d 2019-08-24 stsp }
165 1d126e2d 2019-08-24 stsp }
166 1d126e2d 2019-08-24 stsp return unseen;
167 1d126e2d 2019-08-24 stsp }
168 1d126e2d 2019-08-24 stsp
169 1d126e2d 2019-08-24 stsp /*
170 1d126e2d 2019-08-24 stsp * Insert a tag-value combination from LINE (the equal sign is at POS)
171 1d126e2d 2019-08-24 stsp * into SECTION of our configuration database.
172 1d126e2d 2019-08-24 stsp */
173 1d126e2d 2019-08-24 stsp static int
174 1d126e2d 2019-08-24 stsp conf_set_now(struct got_gitconfig *conf, char *section, char *tag,
175 1d126e2d 2019-08-24 stsp char *value, int override, int is_default)
176 1d126e2d 2019-08-24 stsp {
177 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *node = 0;
178 1d126e2d 2019-08-24 stsp
179 1d126e2d 2019-08-24 stsp if (override)
180 1d126e2d 2019-08-24 stsp conf_remove_now(conf, section, tag);
181 1d126e2d 2019-08-24 stsp else if (got_gitconfig_get_str(conf, section, tag)) {
182 1d126e2d 2019-08-24 stsp if (!is_default)
183 68ce7771 2023-02-20 thomas LOG_DBG((LOG_MISC, 95,
184 300ea754 2021-01-05 stsp "conf_set_now: duplicate tag [%s]:%s, "
185 b6ac0d36 2023-02-20 thomas "ignoring...", section, tag));
186 1d126e2d 2019-08-24 stsp return 1;
187 1d126e2d 2019-08-24 stsp }
188 1d126e2d 2019-08-24 stsp node = calloc(1, sizeof *node);
189 1d126e2d 2019-08-24 stsp if (!node) {
190 1d126e2d 2019-08-24 stsp log_error("conf_set_now: calloc (1, %lu) failed",
191 1d126e2d 2019-08-24 stsp (unsigned long)sizeof *node);
192 1d126e2d 2019-08-24 stsp return 1;
193 1d126e2d 2019-08-24 stsp }
194 1d126e2d 2019-08-24 stsp node->section = node->tag = node->value = NULL;
195 1d126e2d 2019-08-24 stsp if ((node->section = strdup(section)) == NULL)
196 1d126e2d 2019-08-24 stsp goto fail;
197 1d126e2d 2019-08-24 stsp if ((node->tag = strdup(tag)) == NULL)
198 1d126e2d 2019-08-24 stsp goto fail;
199 1d126e2d 2019-08-24 stsp if ((node->value = strdup(value)) == NULL)
200 1d126e2d 2019-08-24 stsp goto fail;
201 1d126e2d 2019-08-24 stsp node->is_default = is_default;
202 1d126e2d 2019-08-24 stsp
203 1d126e2d 2019-08-24 stsp LIST_INSERT_HEAD(&conf->bindings[conf_hash(section)], node, link);
204 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "conf_set_now: [%s]:%s->%s", node->section,
205 1d126e2d 2019-08-24 stsp node->tag, node->value));
206 1d126e2d 2019-08-24 stsp return 0;
207 1d126e2d 2019-08-24 stsp fail:
208 1d126e2d 2019-08-24 stsp free(node->value);
209 1d126e2d 2019-08-24 stsp free(node->tag);
210 1d126e2d 2019-08-24 stsp free(node->section);
211 1d126e2d 2019-08-24 stsp free(node);
212 1d126e2d 2019-08-24 stsp return 1;
213 1d126e2d 2019-08-24 stsp }
214 1d126e2d 2019-08-24 stsp
215 1d126e2d 2019-08-24 stsp /*
216 1d126e2d 2019-08-24 stsp * Parse the line LINE of SZ bytes. Skip Comments, recognize section
217 1d126e2d 2019-08-24 stsp * headers and feed tag-value pairs into our configuration database.
218 1d126e2d 2019-08-24 stsp */
219 1d126e2d 2019-08-24 stsp static const struct got_error *
220 1d126e2d 2019-08-24 stsp conf_parse_line(char **section, struct got_gitconfig *conf, int trans,
221 1d126e2d 2019-08-24 stsp char *line, int ln, size_t sz)
222 1d126e2d 2019-08-24 stsp {
223 1d126e2d 2019-08-24 stsp char *val;
224 1d126e2d 2019-08-24 stsp size_t i;
225 1d126e2d 2019-08-24 stsp int j;
226 1d126e2d 2019-08-24 stsp
227 1d126e2d 2019-08-24 stsp /* '[section]' parsing... */
228 1d126e2d 2019-08-24 stsp if (*line == '[') {
229 1d126e2d 2019-08-24 stsp for (i = 1; i < sz; i++)
230 1d126e2d 2019-08-24 stsp if (line[i] == ']')
231 1d126e2d 2019-08-24 stsp break;
232 1d126e2d 2019-08-24 stsp free(*section);
233 1d126e2d 2019-08-24 stsp if (i == sz) {
234 1d126e2d 2019-08-24 stsp log_print("conf_parse_line: %d:"
235 1d126e2d 2019-08-24 stsp "unmatched ']', ignoring until next section", ln);
236 1d126e2d 2019-08-24 stsp *section = NULL;
237 1d126e2d 2019-08-24 stsp return NULL;
238 1d126e2d 2019-08-24 stsp }
239 fcbb06bf 2023-01-14 thomas *section = strndup(line + 1, i - 1);
240 1d126e2d 2019-08-24 stsp if (*section == NULL)
241 fcbb06bf 2023-01-14 thomas return got_error_from_errno("strndup");
242 1d126e2d 2019-08-24 stsp return NULL;
243 1d126e2d 2019-08-24 stsp }
244 40d0d6a4 2023-02-20 thomas while (sz > 0 && isspace((unsigned char)*line)) {
245 1d126e2d 2019-08-24 stsp line++;
246 40d0d6a4 2023-02-20 thomas sz--;
247 40d0d6a4 2023-02-20 thomas }
248 2cf27278 2023-02-23 thomas
249 2cf27278 2023-02-23 thomas /* Lines starting with '#' or ';' are comments. */
250 2cf27278 2023-02-23 thomas if (*line == '#' || *line == ';')
251 2cf27278 2023-02-23 thomas return NULL;
252 1d126e2d 2019-08-24 stsp
253 1d126e2d 2019-08-24 stsp /* Deal with assignments. */
254 1d126e2d 2019-08-24 stsp for (i = 0; i < sz; i++)
255 1d126e2d 2019-08-24 stsp if (line[i] == '=') {
256 1d126e2d 2019-08-24 stsp /* If no section, we are ignoring the lines. */
257 1d126e2d 2019-08-24 stsp if (!*section) {
258 1d126e2d 2019-08-24 stsp log_print("conf_parse_line: %d: ignoring line "
259 1d126e2d 2019-08-24 stsp "due to no section", ln);
260 1d126e2d 2019-08-24 stsp return NULL;
261 1d126e2d 2019-08-24 stsp }
262 1d126e2d 2019-08-24 stsp line[strcspn(line, " \t=")] = '\0';
263 1d126e2d 2019-08-24 stsp val = line + i + 1 + strspn(line + i + 1, " \t");
264 1d126e2d 2019-08-24 stsp /* Skip trailing whitespace, if any */
265 1d126e2d 2019-08-24 stsp for (j = sz - (val - line) - 1; j > 0 &&
266 1d126e2d 2019-08-24 stsp isspace((unsigned char)val[j]); j--)
267 1d126e2d 2019-08-24 stsp val[j] = '\0';
268 1d126e2d 2019-08-24 stsp /* XXX Perhaps should we not ignore errors? */
269 1d126e2d 2019-08-24 stsp got_gitconfig_set(conf, trans, *section, line, val,
270 1d126e2d 2019-08-24 stsp 0, 0);
271 1d126e2d 2019-08-24 stsp return NULL;
272 1d126e2d 2019-08-24 stsp }
273 1d126e2d 2019-08-24 stsp /* Other non-empty lines are weird. */
274 1d126e2d 2019-08-24 stsp i = strspn(line, " \t");
275 1d126e2d 2019-08-24 stsp if (line[i])
276 1d126e2d 2019-08-24 stsp log_print("conf_parse_line: %d: syntax error", ln);
277 1d126e2d 2019-08-24 stsp
278 1d126e2d 2019-08-24 stsp return NULL;
279 1d126e2d 2019-08-24 stsp }
280 1d126e2d 2019-08-24 stsp
281 1d126e2d 2019-08-24 stsp /* Parse the mapped configuration file. */
282 1d126e2d 2019-08-24 stsp static const struct got_error *
283 1d126e2d 2019-08-24 stsp conf_parse(struct got_gitconfig *conf, int trans, char *buf, size_t sz)
284 1d126e2d 2019-08-24 stsp {
285 1d126e2d 2019-08-24 stsp const struct got_error *err = NULL;
286 1d126e2d 2019-08-24 stsp char *cp = buf;
287 1d126e2d 2019-08-24 stsp char *bufend = buf + sz;
288 1d126e2d 2019-08-24 stsp char *line, *section = NULL;
289 1d126e2d 2019-08-24 stsp int ln = 1;
290 1d126e2d 2019-08-24 stsp
291 1d126e2d 2019-08-24 stsp line = cp;
292 1d126e2d 2019-08-24 stsp while (cp < bufend) {
293 1d126e2d 2019-08-24 stsp if (*cp == '\n') {
294 1d126e2d 2019-08-24 stsp /* Check for escaped newlines. */
295 1d126e2d 2019-08-24 stsp if (cp > buf && *(cp - 1) == '\\')
296 1d126e2d 2019-08-24 stsp *(cp - 1) = *cp = ' ';
297 1d126e2d 2019-08-24 stsp else {
298 1d126e2d 2019-08-24 stsp *cp = '\0';
299 1d126e2d 2019-08-24 stsp err = conf_parse_line(&section, conf, trans,
300 1d126e2d 2019-08-24 stsp line, ln, cp - line);
301 1d126e2d 2019-08-24 stsp if (err)
302 1d126e2d 2019-08-24 stsp return err;
303 1d126e2d 2019-08-24 stsp line = cp + 1;
304 1d126e2d 2019-08-24 stsp }
305 1d126e2d 2019-08-24 stsp ln++;
306 1d126e2d 2019-08-24 stsp }
307 1d126e2d 2019-08-24 stsp cp++;
308 1d126e2d 2019-08-24 stsp }
309 1d126e2d 2019-08-24 stsp if (cp != line)
310 1d126e2d 2019-08-24 stsp log_print("conf_parse: last line unterminated, ignored.");
311 1d126e2d 2019-08-24 stsp return NULL;
312 1d126e2d 2019-08-24 stsp }
313 1d126e2d 2019-08-24 stsp
314 1d126e2d 2019-08-24 stsp const struct got_error *
315 aba9c984 2019-09-08 stsp got_gitconfig_open(struct got_gitconfig **conf, int fd)
316 1d126e2d 2019-08-24 stsp {
317 16aeacf7 2020-11-26 stsp size_t i;
318 1d126e2d 2019-08-24 stsp
319 1d126e2d 2019-08-24 stsp *conf = calloc(1, sizeof(**conf));
320 1d126e2d 2019-08-24 stsp if (*conf == NULL)
321 1d126e2d 2019-08-24 stsp return got_error_from_errno("malloc");
322 1d126e2d 2019-08-24 stsp
323 1d126e2d 2019-08-24 stsp for (i = 0; i < nitems((*conf)->bindings); i++)
324 1d126e2d 2019-08-24 stsp LIST_INIT(&(*conf)->bindings[i]);
325 1d126e2d 2019-08-24 stsp TAILQ_INIT(&(*conf)->trans_queue);
326 aba9c984 2019-09-08 stsp return got_gitconfig_reinit(*conf, fd);
327 1d126e2d 2019-08-24 stsp }
328 1d126e2d 2019-08-24 stsp
329 1d126e2d 2019-08-24 stsp static void
330 1d126e2d 2019-08-24 stsp conf_clear(struct got_gitconfig *conf)
331 1d126e2d 2019-08-24 stsp {
332 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *cb;
333 16aeacf7 2020-11-26 stsp size_t i;
334 1d126e2d 2019-08-24 stsp
335 1d126e2d 2019-08-24 stsp if (conf->addr) {
336 1d126e2d 2019-08-24 stsp for (i = 0; i < nitems(conf->bindings); i++)
337 1d126e2d 2019-08-24 stsp for (cb = LIST_FIRST(&conf->bindings[i]); cb;
338 1d126e2d 2019-08-24 stsp cb = LIST_FIRST(&conf->bindings[i]))
339 1d126e2d 2019-08-24 stsp conf_remove_now(conf, cb->section, cb->tag);
340 1d126e2d 2019-08-24 stsp free(conf->addr);
341 1d126e2d 2019-08-24 stsp conf->addr = NULL;
342 1d126e2d 2019-08-24 stsp }
343 1d126e2d 2019-08-24 stsp }
344 1d126e2d 2019-08-24 stsp
345 1d126e2d 2019-08-24 stsp /* Execute all queued operations for this transaction. Cleanup. */
346 1d126e2d 2019-08-24 stsp static int
347 1d126e2d 2019-08-24 stsp conf_end(struct got_gitconfig *conf, int transaction, int commit)
348 1d126e2d 2019-08-24 stsp {
349 1d126e2d 2019-08-24 stsp struct got_gitconfig_trans *node, *next;
350 1d126e2d 2019-08-24 stsp
351 1d126e2d 2019-08-24 stsp for (node = TAILQ_FIRST(&conf->trans_queue); node; node = next) {
352 1d126e2d 2019-08-24 stsp next = TAILQ_NEXT(node, link);
353 1d126e2d 2019-08-24 stsp if (node->trans == transaction) {
354 1d126e2d 2019-08-24 stsp if (commit)
355 1d126e2d 2019-08-24 stsp switch (node->op) {
356 1d126e2d 2019-08-24 stsp case CONF_SET:
357 1d126e2d 2019-08-24 stsp conf_set_now(conf, node->section,
358 1d126e2d 2019-08-24 stsp node->tag, node->value,
359 1d126e2d 2019-08-24 stsp node->override, node->is_default);
360 1d126e2d 2019-08-24 stsp break;
361 1d126e2d 2019-08-24 stsp case CONF_REMOVE:
362 1d126e2d 2019-08-24 stsp conf_remove_now(conf, node->section,
363 1d126e2d 2019-08-24 stsp node->tag);
364 1d126e2d 2019-08-24 stsp break;
365 1d126e2d 2019-08-24 stsp case CONF_REMOVE_SECTION:
366 1d126e2d 2019-08-24 stsp conf_remove_section_now(conf, node->section);
367 1d126e2d 2019-08-24 stsp break;
368 1d126e2d 2019-08-24 stsp default:
369 1d126e2d 2019-08-24 stsp log_print("got_gitconfig_end: unknown "
370 1d126e2d 2019-08-24 stsp "operation: %d", node->op);
371 1d126e2d 2019-08-24 stsp }
372 1d126e2d 2019-08-24 stsp TAILQ_REMOVE(&conf->trans_queue, node, link);
373 1d126e2d 2019-08-24 stsp free(node->section);
374 1d126e2d 2019-08-24 stsp free(node->tag);
375 1d126e2d 2019-08-24 stsp free(node->value);
376 1d126e2d 2019-08-24 stsp free(node);
377 1d126e2d 2019-08-24 stsp }
378 1d126e2d 2019-08-24 stsp }
379 1d126e2d 2019-08-24 stsp return 0;
380 1d126e2d 2019-08-24 stsp }
381 1d126e2d 2019-08-24 stsp
382 1d126e2d 2019-08-24 stsp
383 1d126e2d 2019-08-24 stsp void
384 1d126e2d 2019-08-24 stsp got_gitconfig_close(struct got_gitconfig *conf)
385 1d126e2d 2019-08-24 stsp {
386 1d126e2d 2019-08-24 stsp conf_clear(conf);
387 1d126e2d 2019-08-24 stsp free(conf);
388 1d126e2d 2019-08-24 stsp }
389 1d126e2d 2019-08-24 stsp
390 1d126e2d 2019-08-24 stsp static int
391 1d126e2d 2019-08-24 stsp conf_begin(struct got_gitconfig *conf)
392 1d126e2d 2019-08-24 stsp {
393 1d126e2d 2019-08-24 stsp return ++conf->seq;
394 1d126e2d 2019-08-24 stsp }
395 1d126e2d 2019-08-24 stsp
396 1d126e2d 2019-08-24 stsp /* Open the config file and map it into our address space, then parse it. */
397 1d126e2d 2019-08-24 stsp const struct got_error *
398 aba9c984 2019-09-08 stsp got_gitconfig_reinit(struct got_gitconfig *conf, int fd)
399 1d126e2d 2019-08-24 stsp {
400 1d126e2d 2019-08-24 stsp const struct got_error *err = NULL;
401 aba9c984 2019-09-08 stsp int trans;
402 1d126e2d 2019-08-24 stsp size_t sz;
403 1d126e2d 2019-08-24 stsp char *new_conf_addr = 0;
404 1d126e2d 2019-08-24 stsp struct stat st;
405 1d126e2d 2019-08-24 stsp
406 1d126e2d 2019-08-24 stsp if (fstat(fd, &st)) {
407 aba9c984 2019-09-08 stsp err = got_error_from_errno("fstat");
408 1d126e2d 2019-08-24 stsp goto fail;
409 1d126e2d 2019-08-24 stsp }
410 1d126e2d 2019-08-24 stsp
411 1d126e2d 2019-08-24 stsp sz = st.st_size;
412 1d126e2d 2019-08-24 stsp new_conf_addr = malloc(sz);
413 1d126e2d 2019-08-24 stsp if (new_conf_addr == NULL) {
414 1d126e2d 2019-08-24 stsp err = got_error_from_errno("malloc");
415 1d126e2d 2019-08-24 stsp goto fail;
416 1d126e2d 2019-08-24 stsp }
417 1d126e2d 2019-08-24 stsp /* XXX I assume short reads won't happen here. */
418 1d126e2d 2019-08-24 stsp if (read(fd, new_conf_addr, sz) != (int)sz) {
419 1d126e2d 2019-08-24 stsp err = got_error_from_errno("read");
420 1d126e2d 2019-08-24 stsp goto fail;
421 1d126e2d 2019-08-24 stsp }
422 1d126e2d 2019-08-24 stsp
423 1d126e2d 2019-08-24 stsp trans = conf_begin(conf);
424 1d126e2d 2019-08-24 stsp
425 1d126e2d 2019-08-24 stsp err = conf_parse(conf, trans, new_conf_addr, sz);
426 1d126e2d 2019-08-24 stsp if (err)
427 1d126e2d 2019-08-24 stsp goto fail;
428 1d126e2d 2019-08-24 stsp
429 1d126e2d 2019-08-24 stsp /* Free potential existing configuration. */
430 1d126e2d 2019-08-24 stsp conf_clear(conf);
431 1d126e2d 2019-08-24 stsp conf_end(conf, trans, 1);
432 1d126e2d 2019-08-24 stsp conf->addr = new_conf_addr;
433 1d126e2d 2019-08-24 stsp return NULL;
434 1d126e2d 2019-08-24 stsp
435 1d126e2d 2019-08-24 stsp fail:
436 1d126e2d 2019-08-24 stsp free(new_conf_addr);
437 1d126e2d 2019-08-24 stsp return err;
438 1d126e2d 2019-08-24 stsp }
439 1d126e2d 2019-08-24 stsp
440 1d126e2d 2019-08-24 stsp /*
441 1d126e2d 2019-08-24 stsp * Return the numeric value denoted by TAG in section SECTION or DEF
442 1d126e2d 2019-08-24 stsp * if that tag does not exist.
443 1d126e2d 2019-08-24 stsp */
444 1d126e2d 2019-08-24 stsp int
445 49d691e8 2021-09-25 thomas.ad got_gitconfig_get_num(struct got_gitconfig *conf, const char *section,
446 49d691e8 2021-09-25 thomas.ad const char *tag, int def)
447 1d126e2d 2019-08-24 stsp {
448 1d126e2d 2019-08-24 stsp char *value = got_gitconfig_get_str(conf, section, tag);
449 1d126e2d 2019-08-24 stsp
450 1d126e2d 2019-08-24 stsp if (value)
451 1d126e2d 2019-08-24 stsp return atoi(value);
452 1d126e2d 2019-08-24 stsp return def;
453 1d126e2d 2019-08-24 stsp }
454 1d126e2d 2019-08-24 stsp
455 1d126e2d 2019-08-24 stsp /* Validate X according to the range denoted by TAG in section SECTION. */
456 1d126e2d 2019-08-24 stsp int
457 1d126e2d 2019-08-24 stsp got_gitconfig_match_num(struct got_gitconfig *conf, char *section, char *tag,
458 1d126e2d 2019-08-24 stsp int x)
459 1d126e2d 2019-08-24 stsp {
460 1d126e2d 2019-08-24 stsp char *value = got_gitconfig_get_str(conf, section, tag);
461 1d126e2d 2019-08-24 stsp int val, min, max, n;
462 1d126e2d 2019-08-24 stsp
463 1d126e2d 2019-08-24 stsp if (!value)
464 1d126e2d 2019-08-24 stsp return 0;
465 1d126e2d 2019-08-24 stsp n = sscanf(value, "%d,%d:%d", &val, &min, &max);
466 1d126e2d 2019-08-24 stsp switch (n) {
467 1d126e2d 2019-08-24 stsp case 1:
468 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "got_gitconfig_match_num: %s:%s %d==%d?",
469 1d126e2d 2019-08-24 stsp section, tag, val, x));
470 1d126e2d 2019-08-24 stsp return x == val;
471 1d126e2d 2019-08-24 stsp case 3:
472 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "got_gitconfig_match_num: %s:%s %d<=%d<=%d?",
473 1d126e2d 2019-08-24 stsp section, tag, min, x, max));
474 1d126e2d 2019-08-24 stsp return min <= x && max >= x;
475 1d126e2d 2019-08-24 stsp default:
476 1d126e2d 2019-08-24 stsp log_error("got_gitconfig_match_num: section %s tag %s: invalid number "
477 1d126e2d 2019-08-24 stsp "spec %s", section, tag, value);
478 1d126e2d 2019-08-24 stsp }
479 1d126e2d 2019-08-24 stsp return 0;
480 1d126e2d 2019-08-24 stsp }
481 1d126e2d 2019-08-24 stsp
482 1d126e2d 2019-08-24 stsp /* Return the string value denoted by TAG in section SECTION. */
483 1d126e2d 2019-08-24 stsp char *
484 49d691e8 2021-09-25 thomas.ad got_gitconfig_get_str(struct got_gitconfig *conf, const char *section,
485 49d691e8 2021-09-25 thomas.ad const char *tag)
486 1d126e2d 2019-08-24 stsp {
487 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *cb;
488 1d126e2d 2019-08-24 stsp
489 1d126e2d 2019-08-24 stsp for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb;
490 1d126e2d 2019-08-24 stsp cb = LIST_NEXT(cb, link))
491 1d126e2d 2019-08-24 stsp if (strcasecmp(section, cb->section) == 0 &&
492 1d126e2d 2019-08-24 stsp strcasecmp(tag, cb->tag) == 0) {
493 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95, "got_gitconfig_get_str: [%s]:%s->%s",
494 1d126e2d 2019-08-24 stsp section, tag, cb->value));
495 1d126e2d 2019-08-24 stsp return cb->value;
496 1d126e2d 2019-08-24 stsp }
497 1d126e2d 2019-08-24 stsp LOG_DBG((LOG_MISC, 95,
498 1d126e2d 2019-08-24 stsp "got_gitconfig_get_str: configuration value not found [%s]:%s", section,
499 1d126e2d 2019-08-24 stsp tag));
500 1d126e2d 2019-08-24 stsp return 0;
501 1d126e2d 2019-08-24 stsp }
502 cd95becd 2019-11-29 stsp
503 cd95becd 2019-11-29 stsp const struct got_error *
504 cd95becd 2019-11-29 stsp got_gitconfig_get_section_list(struct got_gitconfig_list **sections,
505 cd95becd 2019-11-29 stsp struct got_gitconfig *conf)
506 cd95becd 2019-11-29 stsp {
507 cd95becd 2019-11-29 stsp const struct got_error *err = NULL;
508 cd95becd 2019-11-29 stsp struct got_gitconfig_list *list = NULL;
509 cd95becd 2019-11-29 stsp struct got_gitconfig_list_node *node = 0;
510 cd95becd 2019-11-29 stsp struct got_gitconfig_binding *cb;
511 16aeacf7 2020-11-26 stsp size_t i;
512 cd95becd 2019-11-29 stsp
513 cd95becd 2019-11-29 stsp *sections = NULL;
514 1d126e2d 2019-08-24 stsp
515 cd95becd 2019-11-29 stsp list = malloc(sizeof *list);
516 cd95becd 2019-11-29 stsp if (!list)
517 cd95becd 2019-11-29 stsp return got_error_from_errno("malloc");
518 cd95becd 2019-11-29 stsp TAILQ_INIT(&list->fields);
519 cd95becd 2019-11-29 stsp list->cnt = 0;
520 cd95becd 2019-11-29 stsp for (i = 0; i < nitems(conf->bindings); i++) {
521 cd95becd 2019-11-29 stsp for (cb = LIST_FIRST(&conf->bindings[i]); cb;
522 cd95becd 2019-11-29 stsp cb = LIST_NEXT(cb, link)) {
523 83310ac9 2020-03-20 stsp int section_present = 0;
524 83310ac9 2020-03-20 stsp TAILQ_FOREACH(node, &list->fields, link) {
525 83310ac9 2020-03-20 stsp if (strcmp(node->field, cb->section) == 0) {
526 83310ac9 2020-03-20 stsp section_present = 1;
527 83310ac9 2020-03-20 stsp break;
528 83310ac9 2020-03-20 stsp }
529 83310ac9 2020-03-20 stsp }
530 83310ac9 2020-03-20 stsp if (section_present)
531 83310ac9 2020-03-20 stsp continue;
532 cd95becd 2019-11-29 stsp list->cnt++;
533 cd95becd 2019-11-29 stsp node = calloc(1, sizeof *node);
534 cd95becd 2019-11-29 stsp if (!node) {
535 cd95becd 2019-11-29 stsp err = got_error_from_errno("calloc");
536 cd95becd 2019-11-29 stsp goto cleanup;
537 cd95becd 2019-11-29 stsp }
538 cd95becd 2019-11-29 stsp node->field = strdup(cb->section);
539 cd95becd 2019-11-29 stsp if (!node->field) {
540 cd95becd 2019-11-29 stsp err = got_error_from_errno("strdup");
541 cd95becd 2019-11-29 stsp goto cleanup;
542 cd95becd 2019-11-29 stsp }
543 cd95becd 2019-11-29 stsp TAILQ_INSERT_TAIL(&list->fields, node, link);
544 cd95becd 2019-11-29 stsp }
545 cd95becd 2019-11-29 stsp }
546 cd95becd 2019-11-29 stsp
547 cd95becd 2019-11-29 stsp *sections = list;
548 cd95becd 2019-11-29 stsp return NULL;
549 cd95becd 2019-11-29 stsp
550 cd95becd 2019-11-29 stsp cleanup:
551 cd95becd 2019-11-29 stsp free(node);
552 cd95becd 2019-11-29 stsp if (list)
553 cd95becd 2019-11-29 stsp got_gitconfig_free_list(list);
554 cd95becd 2019-11-29 stsp return err;
555 cd95becd 2019-11-29 stsp }
556 cd95becd 2019-11-29 stsp
557 1d126e2d 2019-08-24 stsp /*
558 1d126e2d 2019-08-24 stsp * Build a list of string values out of the comma separated value denoted by
559 1d126e2d 2019-08-24 stsp * TAG in SECTION.
560 1d126e2d 2019-08-24 stsp */
561 1d126e2d 2019-08-24 stsp struct got_gitconfig_list *
562 1d126e2d 2019-08-24 stsp got_gitconfig_get_list(struct got_gitconfig *conf, char *section, char *tag)
563 1d126e2d 2019-08-24 stsp {
564 1d126e2d 2019-08-24 stsp char *liststr = 0, *p, *field, *t;
565 1d126e2d 2019-08-24 stsp struct got_gitconfig_list *list = 0;
566 1d126e2d 2019-08-24 stsp struct got_gitconfig_list_node *node = 0;
567 1d126e2d 2019-08-24 stsp
568 1d126e2d 2019-08-24 stsp list = malloc(sizeof *list);
569 1d126e2d 2019-08-24 stsp if (!list)
570 1d126e2d 2019-08-24 stsp goto cleanup;
571 1d126e2d 2019-08-24 stsp TAILQ_INIT(&list->fields);
572 1d126e2d 2019-08-24 stsp list->cnt = 0;
573 1d126e2d 2019-08-24 stsp liststr = got_gitconfig_get_str(conf, section, tag);
574 1d126e2d 2019-08-24 stsp if (!liststr)
575 1d126e2d 2019-08-24 stsp goto cleanup;
576 1d126e2d 2019-08-24 stsp liststr = strdup(liststr);
577 1d126e2d 2019-08-24 stsp if (!liststr)
578 1d126e2d 2019-08-24 stsp goto cleanup;
579 1d126e2d 2019-08-24 stsp p = liststr;
580 1d126e2d 2019-08-24 stsp while ((field = strsep(&p, ",")) != NULL) {
581 1d126e2d 2019-08-24 stsp /* Skip leading whitespace */
582 1d126e2d 2019-08-24 stsp while (isspace((unsigned char)*field))
583 1d126e2d 2019-08-24 stsp field++;
584 1d126e2d 2019-08-24 stsp /* Skip trailing whitespace */
585 1d126e2d 2019-08-24 stsp if (p)
586 1d126e2d 2019-08-24 stsp for (t = p - 1; t > field && isspace((unsigned char)*t); t--)
587 1d126e2d 2019-08-24 stsp *t = '\0';
588 1d126e2d 2019-08-24 stsp if (*field == '\0') {
589 1d126e2d 2019-08-24 stsp log_print("got_gitconfig_get_list: empty field, ignoring...");
590 1d126e2d 2019-08-24 stsp continue;
591 1d126e2d 2019-08-24 stsp }
592 1d126e2d 2019-08-24 stsp list->cnt++;
593 1d126e2d 2019-08-24 stsp node = calloc(1, sizeof *node);
594 1d126e2d 2019-08-24 stsp if (!node)
595 1d126e2d 2019-08-24 stsp goto cleanup;
596 1d126e2d 2019-08-24 stsp node->field = strdup(field);
597 1d126e2d 2019-08-24 stsp if (!node->field)
598 1d126e2d 2019-08-24 stsp goto cleanup;
599 1d126e2d 2019-08-24 stsp TAILQ_INSERT_TAIL(&list->fields, node, link);
600 1d126e2d 2019-08-24 stsp }
601 1d126e2d 2019-08-24 stsp free(liststr);
602 1d126e2d 2019-08-24 stsp return list;
603 1d126e2d 2019-08-24 stsp
604 1d126e2d 2019-08-24 stsp cleanup:
605 1d126e2d 2019-08-24 stsp free(node);
606 1d126e2d 2019-08-24 stsp if (list)
607 1d126e2d 2019-08-24 stsp got_gitconfig_free_list(list);
608 1d126e2d 2019-08-24 stsp free(liststr);
609 1d126e2d 2019-08-24 stsp return 0;
610 1d126e2d 2019-08-24 stsp }
611 1d126e2d 2019-08-24 stsp
612 1d126e2d 2019-08-24 stsp struct got_gitconfig_list *
613 49d691e8 2021-09-25 thomas.ad got_gitconfig_get_tag_list(struct got_gitconfig *conf, const char *section)
614 1d126e2d 2019-08-24 stsp {
615 1d126e2d 2019-08-24 stsp struct got_gitconfig_list *list = 0;
616 1d126e2d 2019-08-24 stsp struct got_gitconfig_list_node *node = 0;
617 1d126e2d 2019-08-24 stsp struct got_gitconfig_binding *cb;
618 1d126e2d 2019-08-24 stsp
619 1d126e2d 2019-08-24 stsp list = malloc(sizeof *list);
620 1d126e2d 2019-08-24 stsp if (!list)
621 1d126e2d 2019-08-24 stsp goto cleanup;
622 1d126e2d 2019-08-24 stsp TAILQ_INIT(&list->fields);
623 1d126e2d 2019-08-24 stsp list->cnt = 0;
624 1d126e2d 2019-08-24 stsp for (cb = LIST_FIRST(&conf->bindings[conf_hash(section)]); cb;
625 1d126e2d 2019-08-24 stsp cb = LIST_NEXT(cb, link))
626 1d126e2d 2019-08-24 stsp if (strcasecmp(section, cb->section) == 0) {
627 1d126e2d 2019-08-24 stsp list->cnt++;
628 1d126e2d 2019-08-24 stsp node = calloc(1, sizeof *node);
629 1d126e2d 2019-08-24 stsp if (!node)
630 1d126e2d 2019-08-24 stsp goto cleanup;
631 1d126e2d 2019-08-24 stsp node->field = strdup(cb->tag);
632 1d126e2d 2019-08-24 stsp if (!node->field)
633 1d126e2d 2019-08-24 stsp goto cleanup;
634 1d126e2d 2019-08-24 stsp TAILQ_INSERT_TAIL(&list->fields, node, link);
635 1d126e2d 2019-08-24 stsp }
636 1d126e2d 2019-08-24 stsp return list;
637 1d126e2d 2019-08-24 stsp
638 1d126e2d 2019-08-24 stsp cleanup:
639 1d126e2d 2019-08-24 stsp free(node);
640 1d126e2d 2019-08-24 stsp if (list)
641 1d126e2d 2019-08-24 stsp got_gitconfig_free_list(list);
642 1d126e2d 2019-08-24 stsp return 0;
643 1d126e2d 2019-08-24 stsp }
644 1d126e2d 2019-08-24 stsp
645 1d126e2d 2019-08-24 stsp void
646 1d126e2d 2019-08-24 stsp got_gitconfig_free_list(struct got_gitconfig_list *list)
647 1d126e2d 2019-08-24 stsp {
648 1d126e2d 2019-08-24 stsp struct got_gitconfig_list_node *node = TAILQ_FIRST(&list->fields);
649 1d126e2d 2019-08-24 stsp
650 1d126e2d 2019-08-24 stsp while (node) {
651 1d126e2d 2019-08-24 stsp TAILQ_REMOVE(&list->fields, node, link);
652 1d126e2d 2019-08-24 stsp free(node->field);
653 1d126e2d 2019-08-24 stsp free(node);
654 1d126e2d 2019-08-24 stsp node = TAILQ_FIRST(&list->fields);
655 1d126e2d 2019-08-24 stsp }
656 1d126e2d 2019-08-24 stsp free(list);
657 1d126e2d 2019-08-24 stsp }
658 1d126e2d 2019-08-24 stsp
659 1d126e2d 2019-08-24 stsp static int
660 1d126e2d 2019-08-24 stsp got_gitconfig_trans_node(struct got_gitconfig *conf, int transaction,
661 1d126e2d 2019-08-24 stsp enum got_gitconfig_op op, char *section, char *tag, char *value,
662 1d126e2d 2019-08-24 stsp int override, int is_default)
663 1d126e2d 2019-08-24 stsp {
664 1d126e2d 2019-08-24 stsp struct got_gitconfig_trans *node;
665 1d126e2d 2019-08-24 stsp
666 1d126e2d 2019-08-24 stsp node = calloc(1, sizeof *node);
667 1d126e2d 2019-08-24 stsp if (!node) {
668 1d126e2d 2019-08-24 stsp log_error("got_gitconfig_trans_node: calloc (1, %lu) failed",
669 1d126e2d 2019-08-24 stsp (unsigned long)sizeof *node);
670 1d126e2d 2019-08-24 stsp return 1;
671 1d126e2d 2019-08-24 stsp }
672 1d126e2d 2019-08-24 stsp node->trans = transaction;
673 1d126e2d 2019-08-24 stsp node->op = op;
674 1d126e2d 2019-08-24 stsp node->override = override;
675 1d126e2d 2019-08-24 stsp node->is_default = is_default;
676 1d126e2d 2019-08-24 stsp if (section && (node->section = strdup(section)) == NULL)
677 1d126e2d 2019-08-24 stsp goto fail;
678 1d126e2d 2019-08-24 stsp if (tag && (node->tag = strdup(tag)) == NULL)
679 1d126e2d 2019-08-24 stsp goto fail;
680 1d126e2d 2019-08-24 stsp if (value && (node->value = strdup(value)) == NULL)
681 1d126e2d 2019-08-24 stsp goto fail;
682 1d126e2d 2019-08-24 stsp TAILQ_INSERT_TAIL(&conf->trans_queue, node, link);
683 1d126e2d 2019-08-24 stsp return 0;
684 1d126e2d 2019-08-24 stsp
685 1d126e2d 2019-08-24 stsp fail:
686 1d126e2d 2019-08-24 stsp free(node->section);
687 1d126e2d 2019-08-24 stsp free(node->tag);
688 1d126e2d 2019-08-24 stsp free(node->value);
689 1d126e2d 2019-08-24 stsp free(node);
690 1d126e2d 2019-08-24 stsp return 1;
691 1d126e2d 2019-08-24 stsp }
692 1d126e2d 2019-08-24 stsp
693 1d126e2d 2019-08-24 stsp /* Queue a set operation. */
694 1d126e2d 2019-08-24 stsp int
695 1d126e2d 2019-08-24 stsp got_gitconfig_set(struct got_gitconfig *conf, int transaction, char *section,
696 1d126e2d 2019-08-24 stsp char *tag, char *value, int override, int is_default)
697 1d126e2d 2019-08-24 stsp {
698 1d126e2d 2019-08-24 stsp return got_gitconfig_trans_node(conf, transaction, CONF_SET, section,
699 1d126e2d 2019-08-24 stsp tag, value, override, is_default);
700 1d126e2d 2019-08-24 stsp }
701 1d126e2d 2019-08-24 stsp
702 1d126e2d 2019-08-24 stsp /* Queue a remove operation. */
703 1d126e2d 2019-08-24 stsp int
704 1d126e2d 2019-08-24 stsp got_gitconfig_remove(struct got_gitconfig *conf, int transaction,
705 1d126e2d 2019-08-24 stsp char *section, char *tag)
706 1d126e2d 2019-08-24 stsp {
707 1d126e2d 2019-08-24 stsp return got_gitconfig_trans_node(conf, transaction, CONF_REMOVE,
708 1d126e2d 2019-08-24 stsp section, tag, NULL, 0, 0);
709 1d126e2d 2019-08-24 stsp }
710 1d126e2d 2019-08-24 stsp
711 1d126e2d 2019-08-24 stsp /* Queue a remove section operation. */
712 1d126e2d 2019-08-24 stsp int
713 1d126e2d 2019-08-24 stsp got_gitconfig_remove_section(struct got_gitconfig *conf, int transaction,
714 1d126e2d 2019-08-24 stsp char *section)
715 1d126e2d 2019-08-24 stsp {
716 1d126e2d 2019-08-24 stsp return got_gitconfig_trans_node(conf, transaction, CONF_REMOVE_SECTION,
717 1d126e2d 2019-08-24 stsp section, NULL, NULL, 0, 0);
718 1d126e2d 2019-08-24 stsp }