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 : varbuf_end_str(vb);
60 : 95 : }
61 : :
62 : : /**
63 : : * Start processing of the triggers deferred file.
64 : : *
65 : : * @retval -1 Lock ENOENT with O_CREAT (directory does not exist).
66 : : * @retval -2 Unincorp empty, TDUF_WRITE_IF_EMPTY unset.
67 : : * @retval -3 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT unset.
68 : : * @retval 1 Unincorp ENOENT, TDUF_WRITE_IF_ENOENT set.
69 : : * @retval 2 Ok.
70 : : *
71 : : * For positive return values the caller must call trigdef_update_done!
72 : : */
73 : : enum trigdef_update_status
74 : 81 : trigdef_update_start(enum trigdef_update_flags uf)
75 : : {
76 : 81 : free(triggersdir);
77 : 81 : triggersdir = dpkg_db_get_path(TRIGGERSDIR);
78 : :
79 [ + + ]: 81 : if (uf & TDUF_WRITE) {
80 : 7 : constructfn(&fn, triggersdir, TRIGGERSLOCKFILE);
81 [ + - ]: 7 : if (lock_fd == -1) {
82 : 7 : lock_fd = open(fn.buf, O_RDWR | O_CREAT | O_TRUNC, 0600);
83 [ - + ]: 7 : if (lock_fd == -1) {
84 [ # # # # ]: 0 : if (!(errno == ENOENT && (uf & TDUF_NO_LOCK_OK)))
85 : 0 : ohshite(_("unable to open/create "
86 : : "triggers lock file '%.250s'"),
87 : : fn.buf);
88 : 0 : return TDUS_ERROR_NO_DIR;
89 : : }
90 : : }
91 : :
92 : 7 : file_lock(&lock_fd, FILE_LOCK_WAIT, fn.buf,
93 : 7 : _("triggers database lock"));
94 : : }
95 : :
96 : 81 : constructfn(&fn, triggersdir, TRIGGERSDEFERREDFILE);
97 : :
98 [ - + ]: 81 : if (old_deferred)
99 : 0 : fclose(old_deferred);
100 : 81 : old_deferred = fopen(fn.buf, "r");
101 [ + + ]: 81 : if (!old_deferred) {
102 [ - + ]: 74 : if (errno != ENOENT)
103 : 0 : ohshite(_("unable to open triggers deferred file '%.250s'"),
104 : : fn.buf);
105 [ + - ]: 74 : if (!(uf & TDUF_WRITE_IF_ENOENT)) {
106 [ - + ]: 74 : if (uf & TDUF_WRITE)
107 : 0 : pop_cleanup(ehflag_normaltidy);
108 : 74 : return TDUS_ERROR_NO_DEFERRED;
109 : : }
110 : : } else {
111 : : struct stat stab;
112 : : int rc;
113 : :
114 : 7 : setcloexec(fileno(old_deferred), fn.buf);
115 : :
116 : 7 : rc = fstat(fileno(old_deferred), &stab);
117 [ - + ]: 7 : if (rc < 0)
118 : 0 : ohshite(_("unable to stat triggers deferred file '%.250s'"),
119 : : fn.buf);
120 : :
121 [ - + - - ]: 7 : if (stab.st_size == 0 && !(uf & TDUF_WRITE_IF_EMPTY)) {
122 [ # # ]: 0 : if (uf & TDUF_WRITE)
123 : 0 : pop_cleanup(ehflag_normaltidy);
124 : 0 : return TDUS_ERROR_EMPTY_DEFERRED;
125 : : }
126 : : }
127 : :
128 [ + - ]: 7 : if (uf & TDUF_WRITE) {
129 : 7 : constructfn(&newfn, triggersdir, TRIGGERSDEFERREDFILE ".new");
130 [ - + ]: 7 : if (trig_new_deferred)
131 : 0 : fclose(trig_new_deferred);
132 : 7 : trig_new_deferred = fopen(newfn.buf, "w");
133 [ - + ]: 7 : if (!trig_new_deferred)
134 : 0 : ohshite(_("unable to open/create new triggers deferred file '%.250s'"),
135 : : newfn.buf);
136 : :
137 : 7 : setcloexec(fileno(trig_new_deferred), newfn.buf);
138 : : }
139 : :
140 [ - + ]: 7 : if (!old_deferred)
141 : 0 : return TDUS_NO_DEFERRED;
142 : :
143 : 7 : return TDUS_OK;
144 : : }
145 : :
146 : : void
147 : 81 : trigdef_set_methods(const struct trigdefmeths *methods)
148 : : {
149 : 81 : trigdef = methods;
150 : 81 : }
151 : :
152 : : void
153 : 0 : trigdef_update_printf(const char *format, ...)
154 : : {
155 : : va_list ap;
156 : :
157 : 0 : va_start(ap, format);
158 : 0 : vfprintf(trig_new_deferred, format, ap);
159 : 0 : va_end(ap);
160 : 0 : }
161 : :
162 : : static void
163 : 4 : trigdef_parse_error(int line_num, const char *line, const char *ptr)
164 : : {
165 : 4 : ohshit(_("syntax error in triggers deferred file '%.250s' at "
166 : : "line %d character %zd '%s'"),
167 : 4 : fn.buf, line_num, ptr - line + 1, ptr);
168 : : }
169 : :
170 : : /* Trim leading space. */
171 : : static char *
172 : 27 : trigdef_skip_whitespace(char *ptr)
173 : : {
174 [ + + ]: 60 : while (*ptr) {
175 [ + + ]: 59 : if (!c_iswhite(*ptr))
176 : 26 : break;
177 : 33 : ptr++;
178 : : }
179 : :
180 : 27 : return ptr;
181 : : }
182 : :
183 : : int
184 : 7 : trigdef_parse(void)
185 : : {
186 : : char line[_POSIX2_LINE_MAX];
187 : : char *ptr, *ptr_ini;
188 : 7 : int line_num = 0;
189 : :
190 [ + + ]: 14 : while (fgets_checked(line, sizeof(line), old_deferred, fn.buf) > 0) {
191 : 12 : line_num++;
192 : :
193 : 12 : ptr = trigdef_skip_whitespace(line);
194 : :
195 : : /* Skip comments and empty lines. */
196 [ + + + + ]: 12 : if (*ptr == '\0' || *ptr == '#')
197 : 3 : continue;
198 : :
199 : : /* Parse the trigger directive. */
200 : 9 : ptr_ini = ptr;
201 [ + - ]: 104 : while (*ptr) {
202 [ + + + - ]: 104 : if (*ptr < 0x21 || *ptr > 0x7e)
203 : : break;
204 : 95 : ptr++;
205 : : }
206 : :
207 [ + - + + ]: 9 : if (*ptr == '\0' || ptr_ini == ptr)
208 : 1 : trigdef_parse_error(line_num, line, ptr);
209 : 8 : *ptr++ = '\0';
210 : :
211 : : /* Set the trigger directive. */
212 : 8 : trigdef->trig_begin(ptr_ini);
213 : :
214 : : /* Parse the package names. */
215 [ + + ]: 19 : while (*ptr) {
216 : 15 : ptr = trigdef_skip_whitespace(ptr);
217 : :
218 : 15 : ptr_ini = ptr;
219 [ + - ]: 15 : if (*ptr == '\0' ||
220 [ + + + + : 15 : !(c_isdigit(*ptr) || c_islower(*ptr) || *ptr == '-'))
+ + ]
221 : 3 : trigdef_parse_error(line_num, line, ptr);
222 : :
223 [ + + ]: 55 : while (*++ptr) {
224 [ + + + + ]: 50 : if (!c_isdigit(*ptr) && !c_islower(*ptr) &&
225 [ + + + + ]: 17 : *ptr != '-' && *ptr != ':' &&
226 [ + + + + ]: 9 : *ptr != '+' && *ptr != '.')
227 : 7 : break;
228 : : }
229 : :
230 [ + + + - : 12 : if (*ptr != '\0' && *ptr != '#' && !c_iswhite(*ptr))
- + ]
231 : 0 : trigdef_parse_error(line_num, line, ptr);
232 : 12 : *ptr++ = '\0';
233 : :
234 [ + + + + ]: 12 : if (ptr_ini[0] == '-' && ptr_ini[1])
235 : 1 : ohshit(_("invalid package name '%.250s' in "
236 : : "triggers deferred file '%.250s'"),
237 : : ptr_ini, fn.buf);
238 : :
239 : : /* Set the package name. */
240 : 11 : trigdef->package(ptr_ini);
241 : : }
242 : :
243 : 4 : trigdef->trig_end();
244 : : }
245 : :
246 : 1 : return 0;
247 : : }
248 : :
249 : : void
250 : 1 : trigdef_process_done(void)
251 : : {
252 : : int r;
253 : :
254 [ + - ]: 1 : if (old_deferred) {
255 [ - + ]: 1 : if (ferror(old_deferred))
256 : 0 : ohshite(_("error reading triggers deferred file '%.250s'"),
257 : : fn.buf);
258 : 1 : fclose(old_deferred);
259 : 1 : old_deferred = NULL;
260 : : }
261 : :
262 [ + - ]: 1 : if (trig_new_deferred) {
263 [ - + ]: 1 : if (ferror(trig_new_deferred))
264 : 0 : ohshite(_("unable to write new triggers deferred "
265 : : "file '%.250s'"), newfn.buf);
266 : 1 : r = fclose(trig_new_deferred);
267 : 1 : trig_new_deferred = NULL;
268 [ - + ]: 1 : if (r)
269 : 0 : ohshite(_("unable to close new triggers deferred "
270 : : "file '%.250s'"), newfn.buf);
271 : :
272 [ - + ]: 1 : if (rename(newfn.buf, fn.buf))
273 : 0 : ohshite(_("unable to install new triggers deferred "
274 : : "file '%.250s'"), fn.buf);
275 : :
276 : 1 : dir_sync_path(triggersdir);
277 : : }
278 : :
279 : 1 : free(triggersdir);
280 : 1 : triggersdir = NULL;
281 : :
282 : : /* Unlock. */
283 [ + - ]: 1 : if (lock_fd >= 0)
284 : 1 : pop_cleanup(ehflag_normaltidy);
285 : 1 : }
|