Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * trigdeferred.c - parsing of triggers/Unincorp (was …/Deferred)
4 : : *
5 : : * Copyright © 2007 Canonical Ltd
6 : : * written by Ian Jackson <ijackson@chiark.greenend.org.uk>
7 : : * Copyright © 2008-2016 Guillem Jover <guillem@debian.org>
8 : : *
9 : : * This is free software; you can redistribute it and/or modify
10 : : * it under the terms of the GNU General Public License as published by
11 : : * the Free Software Foundation; either version 2 of the License, or
12 : : * (at your option) any later version.
13 : : *
14 : : * This is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : : * GNU General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU General Public License
20 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : : */
22 : :
23 : : #include <config.h>
24 : : #include <compat.h>
25 : :
26 : : #include <sys/stat.h>
27 : :
28 : : #include <errno.h>
29 : : #include <fcntl.h>
30 : : #include <limits.h>
31 : : #include <stdlib.h>
32 : :
33 : : #include <dpkg/i18n.h>
34 : : #include <dpkg/dpkg.h>
35 : : #include <dpkg/dpkg-db.h>
36 : : #include <dpkg/c-ctype.h>
37 : : #include <dpkg/file.h>
38 : : #include <dpkg/dir.h>
39 : : #include <dpkg/trigdeferred.h>
40 : : #include <dpkg/triglib.h>
41 : :
42 : : static struct varbuf fn, newfn;
43 : :
44 : : static const struct trigdefmeths *trigdef;
45 : :
46 : : /*---------- Deferred file handling ----------*/
47 : :
48 : : static char *triggersdir;
49 : : static int lock_fd = -1;
50 : : static FILE *old_deferred;
51 : : static FILE *trig_new_deferred;
52 : :
53 : : static void
54 : 95 : constructfn(struct varbuf *vb, const char *dir, const char *tail)
55 : : {
56 : 95 : varbuf_reset(vb);
57 : 95 : varbuf_add_dir(vb, dir);
58 : 95 : varbuf_add_str(vb, tail);
59 : 95 : }
60 : :
61 : : /**
62 : : * Start processing of the triggers deferred file.
63 : : *
64 : : * @retval -1 Lock ENOENT with O_CREAT (directory does not exist).
65 : : * @retval -2 Unincorp empty, TDUF_WRITE_IF_EMPTY unset.
66 : : * @retval -3 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT unset.
67 : : * @retval 1 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT set.
68 : : * @retval 2 Ok.
69 : : *
70 : : * For positive return values the caller must call trigdef_update_done!
71 : : */
72 : : enum trigdef_update_status
73 : 81 : trigdef_update_start(enum trigdef_update_flags uf)
74 : : {
75 : 81 : free(triggersdir);
76 : 81 : triggersdir = dpkg_db_get_path(TRIGGERSDIR);
77 : :
78 [ + + ]: 81 : if (uf & TDUF_WRITE) {
79 : 7 : constructfn(&fn, triggersdir, TRIGGERSLOCKFILE);
80 [ + - ]: 7 : if (lock_fd < 0) {
81 : 7 : lock_fd = open(fn.buf, O_RDWR | O_CREAT | O_TRUNC, 0600);
82 [ - + ]: 7 : if (lock_fd < 0) {
83 [ # # # # ]: 0 : if (!(errno == ENOENT && (uf & TDUF_NO_LOCK_OK)))
84 : 0 : ohshite(_("unable to open/create "
85 : : "triggers lock file '%.250s'"),
86 : : fn.buf);
87 : 0 : return TDUS_ERROR_NO_DIR;
88 : : }
89 : : }
90 : :
91 : 7 : file_lock(&lock_fd, FILE_LOCK_WAIT, fn.buf,
92 : 7 : _("triggers database lock"));
93 : : }
94 : :
95 : 81 : constructfn(&fn, triggersdir, TRIGGERSDEFERREDFILE);
96 : :
97 [ - + ]: 81 : if (old_deferred)
98 : 0 : fclose(old_deferred);
99 : 81 : old_deferred = fopen(fn.buf, "r");
100 [ + + ]: 81 : if (!old_deferred) {
101 [ - + ]: 74 : if (errno != ENOENT)
102 : 0 : ohshite(_("unable to open triggers deferred file '%.250s'"),
103 : : fn.buf);
104 [ + - ]: 74 : if (!(uf & TDUF_WRITE_IF_ENOENT)) {
105 [ - + ]: 74 : if (uf & TDUF_WRITE)
106 : 0 : pop_cleanup(ehflag_normaltidy);
107 : 74 : return TDUS_ERROR_NO_DEFERRED;
108 : : }
109 : : } else {
110 : : struct stat stab;
111 : : int rc;
112 : :
113 : 7 : setcloexec(fileno(old_deferred), fn.buf);
114 : :
115 : 7 : rc = fstat(fileno(old_deferred), &stab);
116 [ - + ]: 7 : if (rc < 0)
117 : 0 : ohshite(_("unable to stat triggers deferred file '%.250s'"),
118 : : fn.buf);
119 : :
120 [ - + - - ]: 7 : if (stab.st_size == 0 && !(uf & TDUF_WRITE_IF_EMPTY)) {
121 [ # # ]: 0 : if (uf & TDUF_WRITE)
122 : 0 : pop_cleanup(ehflag_normaltidy);
123 : 0 : return TDUS_ERROR_EMPTY_DEFERRED;
124 : : }
125 : : }
126 : :
127 [ + - ]: 7 : if (uf & TDUF_WRITE) {
128 : 7 : constructfn(&newfn, triggersdir, TRIGGERSDEFERREDFILE ".new");
129 [ - + ]: 7 : if (trig_new_deferred)
130 : 0 : fclose(trig_new_deferred);
131 : 7 : trig_new_deferred = fopen(newfn.buf, "w");
132 [ - + ]: 7 : if (!trig_new_deferred)
133 : 0 : ohshite(_("unable to open/create new triggers deferred file '%.250s'"),
134 : : newfn.buf);
135 : :
136 : 7 : setcloexec(fileno(trig_new_deferred), newfn.buf);
137 : : }
138 : :
139 [ - + ]: 7 : if (!old_deferred)
140 : 0 : return TDUS_NO_DEFERRED;
141 : :
142 : 7 : return TDUS_OK;
143 : : }
144 : :
145 : : void
146 : 81 : trigdef_set_methods(const struct trigdefmeths *methods)
147 : : {
148 : 81 : trigdef = methods;
149 : 81 : }
150 : :
151 : : void
152 : 0 : trigdef_update_printf(const char *format, ...)
153 : : {
154 : : va_list ap;
155 : :
156 : 0 : va_start(ap, format);
157 : 0 : vfprintf(trig_new_deferred, format, ap);
158 : 0 : va_end(ap);
159 : 0 : }
160 : :
161 : : static void
162 : 4 : trigdef_parse_error(int line_num, const char *line, const char *ptr)
163 : : {
164 : 4 : ohshit(_("syntax error in triggers deferred file '%.250s' at "
165 : : "line %d character %zd '%s'"),
166 : 4 : fn.buf, line_num, ptr - line + 1, ptr);
167 : : }
168 : :
169 : : /* Trim leading space. */
170 : : static char *
171 : 27 : trigdef_skip_whitespace(char *ptr)
172 : : {
173 [ + + ]: 60 : while (*ptr) {
174 [ + + ]: 59 : if (!c_iswhite(*ptr))
175 : 26 : break;
176 : 33 : ptr++;
177 : : }
178 : :
179 : 27 : return ptr;
180 : : }
181 : :
182 : : int
183 : 7 : trigdef_parse(void)
184 : : {
185 : : char line[_POSIX2_LINE_MAX];
186 : : char *ptr, *ptr_ini;
187 : 7 : int line_num = 0;
188 : :
189 [ + + ]: 14 : while (fgets_checked(line, sizeof(line), old_deferred, fn.buf) > 0) {
190 : 12 : line_num++;
191 : :
192 : 12 : ptr = trigdef_skip_whitespace(line);
193 : :
194 : : /* Skip comments and empty lines. */
195 [ + + + + ]: 12 : if (*ptr == '\0' || *ptr == '#')
196 : 3 : continue;
197 : :
198 : : /* Parse the trigger directive. */
199 : 9 : ptr_ini = ptr;
200 [ + - ]: 104 : while (*ptr) {
201 [ + + + - ]: 104 : if (*ptr < 0x21 || *ptr > 0x7e)
202 : : break;
203 : 95 : ptr++;
204 : : }
205 : :
206 [ + - + + ]: 9 : if (*ptr == '\0' || ptr_ini == ptr)
207 : 1 : trigdef_parse_error(line_num, line, ptr);
208 : 8 : *ptr++ = '\0';
209 : :
210 : : /* Set the trigger directive. */
211 : 8 : trigdef->trig_begin(ptr_ini);
212 : :
213 : : /* Parse the package names. */
214 [ + + ]: 19 : while (*ptr) {
215 : 15 : ptr = trigdef_skip_whitespace(ptr);
216 : :
217 : 15 : ptr_ini = ptr;
218 [ + - ]: 15 : if (*ptr == '\0' ||
219 [ + + + + : 15 : !(c_isdigit(*ptr) || c_islower(*ptr) || *ptr == '-'))
+ + ]
220 : 3 : trigdef_parse_error(line_num, line, ptr);
221 : :
222 [ + + ]: 55 : while (*++ptr) {
223 [ + + + + ]: 50 : if (!c_isdigit(*ptr) && !c_islower(*ptr) &&
224 [ + + + + ]: 17 : *ptr != '-' && *ptr != ':' &&
225 [ + + + + ]: 9 : *ptr != '+' && *ptr != '.')
226 : 7 : break;
227 : : }
228 : :
229 [ + + + - : 12 : if (*ptr != '\0' && *ptr != '#' && !c_iswhite(*ptr))
- + ]
230 : 0 : trigdef_parse_error(line_num, line, ptr);
231 : 12 : *ptr++ = '\0';
232 : :
233 [ + + + + ]: 12 : if (ptr_ini[0] == '-' && ptr_ini[1])
234 : 1 : ohshit(_("invalid package name '%.250s' in "
235 : : "triggers deferred file '%.250s'"),
236 : : ptr_ini, fn.buf);
237 : :
238 : : /* Set the package name. */
239 : 11 : trigdef->package(ptr_ini);
240 : : }
241 : :
242 : 4 : trigdef->trig_end();
243 : : }
244 : :
245 : 1 : return 0;
246 : : }
247 : :
248 : : void
249 : 1 : trigdef_process_done(void)
250 : : {
251 [ + - ]: 1 : if (old_deferred) {
252 [ - + ]: 1 : if (ferror(old_deferred))
253 : 0 : ohshite(_("error reading triggers deferred file '%.250s'"),
254 : : fn.buf);
255 : 1 : fclose(old_deferred);
256 : 1 : old_deferred = NULL;
257 : : }
258 : :
259 [ + - ]: 1 : if (trig_new_deferred) {
260 : : int rc;
261 : :
262 [ - + ]: 1 : if (ferror(trig_new_deferred))
263 : 0 : ohshite(_("unable to write new triggers deferred "
264 : : "file '%.250s'"), newfn.buf);
265 : 1 : rc = fclose(trig_new_deferred);
266 : 1 : trig_new_deferred = NULL;
267 [ - + ]: 1 : if (rc)
268 : 0 : ohshite(_("unable to close new triggers deferred "
269 : : "file '%.250s'"), newfn.buf);
270 : :
271 [ - + ]: 1 : if (rename(newfn.buf, fn.buf))
272 : 0 : ohshite(_("unable to install new triggers deferred "
273 : : "file '%.250s'"), fn.buf);
274 : :
275 : 1 : dir_sync_path(triggersdir);
276 : : }
277 : :
278 : 1 : free(triggersdir);
279 : 1 : triggersdir = NULL;
280 : :
281 : : /* Unlock. */
282 [ + - ]: 1 : if (lock_fd >= 0)
283 : 1 : pop_cleanup(ehflag_normaltidy);
284 : 1 : }
|