Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * dbmodify.c - routines for managing dpkg database updates
4 : : *
5 : : * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2001 Wichert Akkerman <wichert@debian.org>
7 : : * Copyright © 2006-2014 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 : : #include <sys/types.h>
28 : : #include <sys/wait.h>
29 : :
30 : : #include <errno.h>
31 : : #include <limits.h>
32 : : #include <string.h>
33 : : #include <time.h>
34 : : #include <fcntl.h>
35 : : #include <dirent.h>
36 : : #include <unistd.h>
37 : : #include <stdbool.h>
38 : : #include <stdlib.h>
39 : : #include <stdio.h>
40 : :
41 : : #include <dpkg/i18n.h>
42 : : #include <dpkg/c-ctype.h>
43 : : #include <dpkg/dpkg.h>
44 : : #include <dpkg/dpkg-db.h>
45 : : #include <dpkg/file.h>
46 : : #include <dpkg/dir.h>
47 : : #include <dpkg/triglib.h>
48 : :
49 : : static bool db_initialized;
50 : :
51 : : static enum modstatdb_rw cstatus=-1, cflags=0;
52 : : static char *lockfile;
53 : : static char *frontendlockfile;
54 : : static char *statusfile, *availablefile;
55 : : static char *importanttmpfile=NULL;
56 : : static FILE *importanttmp;
57 : : static int nextupdate;
58 : : static char *updatesdir;
59 : : static int updateslength;
60 : : static struct varbuf updatefn;
61 : : static struct varbuf_state updatefn_state;
62 : : static struct varbuf uvb;
63 : :
64 : 0 : static int ulist_select(const struct dirent *de) {
65 : : const char *p;
66 : : int l;
67 [ # # ]: 0 : for (p= de->d_name, l=0; *p; p++, l++)
68 [ # # ]: 0 : if (!c_isdigit(*p))
69 : 0 : return 0;
70 [ # # ]: 0 : if (l > IMPORTANTMAXLEN)
71 : 0 : ohshit(_("updates directory contains file '%.250s' whose name is too long "
72 : 0 : "(length=%d, max=%d)"), de->d_name, l, IMPORTANTMAXLEN);
73 [ # # ]: 0 : if (updateslength < 0)
74 : 0 : updateslength = l;
75 [ # # ]: 0 : else if (l != updateslength)
76 : 0 : ohshit(_("updates directory contains files with different length names "
77 : : "(both %d and %d)"), l, updateslength);
78 : 0 : return 1;
79 : : }
80 : :
81 : 74 : static void cleanupdates(void) {
82 : : struct dirent **cdlist;
83 : : int cdn;
84 : :
85 : 74 : parsedb(statusfile, pdb_parse_status, NULL);
86 : :
87 : 74 : updateslength= -1;
88 : 74 : cdn = scandir(updatesdir, &cdlist, &ulist_select, alphasort);
89 [ + - ]: 74 : if (cdn < 0) {
90 [ + - ]: 74 : if (errno == ENOENT) {
91 [ - + - - ]: 74 : if (cstatus >= msdbrw_write &&
92 : 0 : dir_make_path(updatesdir, 0755) < 0)
93 : 0 : ohshite(_("cannot create the dpkg updates directory %s"),
94 : : updatesdir);
95 : 74 : return;
96 : : }
97 : 0 : ohshite(_("cannot scan updates directory '%.255s'"), updatesdir);
98 : : }
99 : :
100 [ # # ]: 0 : if (cdn) {
101 : : int i;
102 : :
103 [ # # ]: 0 : for (i=0; i<cdn; i++) {
104 : 0 : varbuf_rollback(&updatefn_state);
105 : 0 : varbuf_add_str(&updatefn, cdlist[i]->d_name);
106 : 0 : parsedb(updatefn.buf, pdb_parse_update, NULL);
107 : : }
108 : :
109 [ # # ]: 0 : if (cstatus >= msdbrw_write) {
110 : 0 : writedb(statusfile, wdb_must_sync);
111 : :
112 [ # # ]: 0 : for (i=0; i<cdn; i++) {
113 : 0 : varbuf_rollback(&updatefn_state);
114 : 0 : varbuf_add_str(&updatefn, cdlist[i]->d_name);
115 [ # # ]: 0 : if (unlink(updatefn.buf))
116 : 0 : ohshite(_("failed to remove incorporated update file %.255s"),
117 : : updatefn.buf);
118 : : }
119 : :
120 : 0 : dir_sync_path(updatesdir);
121 : : }
122 : :
123 [ # # ]: 0 : for (i = 0; i < cdn; i++)
124 : 0 : free(cdlist[i]);
125 : : }
126 : 0 : free(cdlist);
127 : :
128 : 0 : nextupdate= 0;
129 : : }
130 : :
131 : 0 : static void createimptmp(void) {
132 : : int i;
133 : :
134 : 0 : onerr_abort++;
135 : :
136 : 0 : importanttmp= fopen(importanttmpfile,"w");
137 [ # # ]: 0 : if (!importanttmp)
138 : 0 : ohshite(_("unable to create '%.255s'"), importanttmpfile);
139 : 0 : setcloexec(fileno(importanttmp),importanttmpfile);
140 [ # # ]: 0 : for (i=0; i<512; i++) fputs("#padding\n",importanttmp);
141 [ # # ]: 0 : if (ferror(importanttmp))
142 : 0 : ohshite(_("unable to fill %.250s with padding"),importanttmpfile);
143 [ # # ]: 0 : if (fflush(importanttmp))
144 : 0 : ohshite(_("unable to flush %.250s after padding"), importanttmpfile);
145 [ # # ]: 0 : if (fseek(importanttmp,0,SEEK_SET))
146 : 0 : ohshite(_("unable to seek to start of %.250s after padding"),
147 : : importanttmpfile);
148 : :
149 : 0 : onerr_abort--;
150 : 0 : }
151 : :
152 : : static const struct fni {
153 : : const char *suffix;
154 : : char **store;
155 : : } fnis[] = {
156 : : {
157 : : .suffix = LOCKFILE,
158 : : .store = &lockfile,
159 : : }, {
160 : : .suffix = FRONTENDLOCKFILE,
161 : : .store = &frontendlockfile,
162 : : }, {
163 : : .suffix = STATUSFILE,
164 : : .store = &statusfile,
165 : : }, {
166 : : .suffix = AVAILFILE,
167 : : .store = &availablefile,
168 : : }, {
169 : : .suffix = UPDATESDIR,
170 : : .store = &updatesdir,
171 : : }, {
172 : : .suffix = UPDATESDIR "/" IMPORTANTTMP,
173 : : .store = &importanttmpfile,
174 : : }, {
175 : : .suffix = NULL,
176 : : .store = NULL,
177 : : }
178 : : };
179 : :
180 : : void
181 : 74 : modstatdb_init(void)
182 : : {
183 : : const struct fni *fnip;
184 : :
185 [ - + ]: 74 : if (db_initialized)
186 : 0 : return;
187 : :
188 [ + + ]: 518 : for (fnip = fnis; fnip->suffix; fnip++) {
189 : 444 : free(*fnip->store);
190 : 444 : *fnip->store = dpkg_db_get_path(fnip->suffix);
191 : : }
192 : :
193 : 74 : varbuf_init(&updatefn, strlen(updatesdir) + 1 + IMPORTANTMAXLEN);
194 : 74 : varbuf_add_dir(&updatefn, updatesdir);
195 : 74 : varbuf_snapshot(&updatefn, &updatefn_state);
196 : :
197 : 74 : db_initialized = true;
198 : : }
199 : :
200 : : void
201 : 52 : modstatdb_done(void)
202 : : {
203 : : const struct fni *fnip;
204 : :
205 [ - + ]: 52 : if (!db_initialized)
206 : 0 : return;
207 : :
208 [ + + ]: 364 : for (fnip = fnis; fnip->suffix; fnip++) {
209 : 312 : free(*fnip->store);
210 : 312 : *fnip->store = NULL;
211 : : }
212 : 52 : varbuf_destroy(&updatefn);
213 : :
214 : 52 : db_initialized = false;
215 : : }
216 : :
217 : : static int dblockfd = -1;
218 : : static int frontendlockfd = -1;
219 : :
220 : : bool
221 : 0 : modstatdb_is_locked(void)
222 : : {
223 : : int lockfd;
224 : : bool locked;
225 : :
226 [ # # ]: 0 : if (dblockfd < 0) {
227 : 0 : lockfd = open(lockfile, O_RDONLY);
228 [ # # ]: 0 : if (lockfd < 0) {
229 [ # # ]: 0 : if (errno == ENOENT)
230 : 0 : return false;
231 : 0 : ohshite(_("unable to check lock file for dpkg database directory %s"),
232 : : dpkg_db_get_dir());
233 : : }
234 : : } else {
235 : 0 : lockfd = dblockfd;
236 : : }
237 : :
238 : 0 : locked = file_is_locked(lockfd, lockfile);
239 : :
240 : : /* We only close the file if there was no lock open, otherwise we would
241 : : * release the existing lock on close. */
242 [ # # ]: 0 : if (dblockfd < 0)
243 : 0 : close(lockfd);
244 : :
245 : 0 : return locked;
246 : : }
247 : :
248 : : bool
249 : 0 : modstatdb_can_lock(void)
250 : : {
251 [ # # ]: 0 : if (dblockfd >= 0)
252 : 0 : return true;
253 : :
254 [ # # ]: 0 : if (getenv("DPKG_FRONTEND_LOCKED") == NULL) {
255 : 0 : frontendlockfd = open(frontendlockfile, O_RDWR | O_CREAT | O_TRUNC, 0660);
256 [ # # ]: 0 : if (frontendlockfd < 0) {
257 [ # # # # ]: 0 : if (errno == EACCES || errno == EPERM)
258 : 0 : return false;
259 : : else
260 : 0 : ohshite(_("unable to open/create dpkg frontend lock for directory %s"),
261 : : dpkg_db_get_dir());
262 : : }
263 : : } else {
264 : 0 : frontendlockfd = -1;
265 : : }
266 : :
267 : 0 : dblockfd = open(lockfile, O_RDWR | O_CREAT | O_TRUNC, 0660);
268 [ # # ]: 0 : if (dblockfd < 0) {
269 [ # # # # ]: 0 : if (errno == EACCES || errno == EPERM)
270 : 0 : return false;
271 : : else
272 : 0 : ohshite(_("unable to open/create dpkg database lock file for directory %s"),
273 : : dpkg_db_get_dir());
274 : : }
275 : :
276 : 0 : return true;
277 : : }
278 : :
279 : : void
280 : 0 : modstatdb_lock(void)
281 : : {
282 [ # # ]: 0 : if (!modstatdb_can_lock())
283 : 0 : ohshit(_("you do not have permission to lock the dpkg database directory %s"),
284 : : dpkg_db_get_dir());
285 : :
286 [ # # ]: 0 : if (frontendlockfd >= 0)
287 : 0 : file_lock(&frontendlockfd, FILE_LOCK_NOWAIT, frontendlockfile,
288 : 0 : _("dpkg frontend lock"));
289 : 0 : file_lock(&dblockfd, FILE_LOCK_NOWAIT, lockfile,
290 : 0 : _("dpkg database lock"));
291 : 0 : }
292 : :
293 : : void
294 : 0 : modstatdb_unlock(void)
295 : : {
296 : : /* Unlock. */
297 : 0 : pop_cleanup(ehflag_normaltidy);
298 [ # # ]: 0 : if (frontendlockfd >= 0)
299 : 0 : pop_cleanup(ehflag_normaltidy);
300 : :
301 : 0 : dblockfd = -1;
302 : 0 : frontendlockfd = -1;
303 : 0 : }
304 : :
305 : : enum modstatdb_rw
306 : 74 : modstatdb_open(enum modstatdb_rw readwritereq)
307 : : {
308 : 74 : bool db_can_access = false;
309 : :
310 : 74 : modstatdb_init();
311 : :
312 : 74 : cflags = readwritereq & msdbrw_available_mask;
313 : 74 : readwritereq &= ~msdbrw_available_mask;
314 : :
315 [ - - + - ]: 74 : switch (readwritereq) {
316 : 0 : case msdbrw_needsuperuser:
317 : : case msdbrw_needsuperuserlockonly:
318 [ # # # # ]: 0 : if (getuid() || geteuid())
319 : 0 : ohshit(_("requested operation requires superuser privilege"));
320 : : /* Fall through. */
321 : : case msdbrw_write: case msdbrw_writeifposs:
322 : 0 : db_can_access = access(dpkg_db_get_dir(), W_OK) == 0;
323 [ # # # # ]: 0 : if (!db_can_access && errno == ENOENT) {
324 [ # # ]: 0 : if (dir_make_path(dpkg_db_get_dir(), 0755) == 0)
325 : 0 : db_can_access = true;
326 [ # # ]: 0 : else if (readwritereq >= msdbrw_write)
327 : 0 : ohshite(_("cannot create the dpkg database directory %s"),
328 : : dpkg_db_get_dir());
329 [ # # ]: 0 : else if (errno == EROFS)
330 : : /* If we cannot create the directory on read-only modes on read-only
331 : : * filesystems, make it look like an access error to be skipped. */
332 : 0 : errno = EACCES;
333 : : }
334 : :
335 [ # # ]: 0 : if (!db_can_access) {
336 [ # # ]: 0 : if (errno != EACCES)
337 : 0 : ohshite(_("unable to access the dpkg database directory %s"),
338 : : dpkg_db_get_dir());
339 [ # # ]: 0 : else if (readwritereq >= msdbrw_write)
340 : 0 : ohshit(_("required read/write access to the dpkg database directory %s"),
341 : : dpkg_db_get_dir());
342 : 0 : cstatus= msdbrw_readonly;
343 : : } else {
344 : 0 : modstatdb_lock();
345 : 0 : cstatus= (readwritereq == msdbrw_needsuperuserlockonly ?
346 [ # # ]: 0 : msdbrw_needsuperuserlockonly :
347 : : msdbrw_write);
348 : : }
349 : 0 : break;
350 : 74 : case msdbrw_readonly:
351 : 74 : cstatus= msdbrw_readonly; break;
352 : 0 : default:
353 : 0 : internerr("unknown modstatdb_rw '%d'", readwritereq);
354 : : }
355 : :
356 : 74 : dpkg_arch_load_list();
357 : :
358 [ + - ]: 74 : if (cstatus != msdbrw_needsuperuserlockonly) {
359 : 74 : cleanupdates();
360 [ - + ]: 74 : if (cflags >= msdbrw_available_readonly)
361 : 0 : parsedb(availablefile, pdb_parse_available, NULL);
362 : : }
363 : :
364 [ - + ]: 74 : if (cstatus >= msdbrw_write) {
365 : 0 : createimptmp();
366 : 0 : varbuf_init(&uvb, 10240);
367 : : }
368 : :
369 : 74 : trig_fixup_awaiters(cstatus);
370 : 74 : trig_incorporate(cstatus);
371 : :
372 : 74 : return cstatus;
373 : : }
374 : :
375 : : enum modstatdb_rw
376 : 0 : modstatdb_get_status(void)
377 : : {
378 : 0 : return cstatus;
379 : : }
380 : :
381 : 0 : void modstatdb_checkpoint(void) {
382 : : int i;
383 : :
384 [ # # ]: 0 : if (cstatus < msdbrw_write)
385 : 0 : internerr("modstatdb status '%d' is not writable", cstatus);
386 : :
387 : 0 : writedb(statusfile, wdb_must_sync);
388 : :
389 [ # # ]: 0 : for (i=0; i<nextupdate; i++) {
390 : 0 : varbuf_rollback(&updatefn_state);
391 : 0 : varbuf_printf(&updatefn, IMPORTANTFMT, i);
392 : :
393 : : /* Have we made a real mess? */
394 [ # # ]: 0 : if (varbuf_rollback_len(&updatefn_state) > IMPORTANTMAXLEN)
395 : 0 : internerr("modstatdb update entry name '%s' longer than %d",
396 : : varbuf_rollback_start(&updatefn_state), IMPORTANTMAXLEN);
397 : :
398 [ # # ]: 0 : if (unlink(updatefn.buf))
399 : 0 : ohshite(_("failed to remove my own update file %.255s"), updatefn.buf);
400 : : }
401 : :
402 : 0 : dir_sync_path(updatesdir);
403 : :
404 : 0 : nextupdate= 0;
405 : 0 : }
406 : :
407 : 52 : void modstatdb_shutdown(void) {
408 [ - + ]: 52 : if (cflags >= msdbrw_available_write)
409 : 0 : writedb(availablefile, wdb_dump_available);
410 : :
411 [ - - + ]: 52 : switch (cstatus) {
412 : 0 : case msdbrw_write:
413 : 0 : modstatdb_checkpoint();
414 : : /* Tidy up a bit, but don't worry too much about failure. */
415 : 0 : fclose(importanttmp);
416 : 0 : (void)unlink(importanttmpfile);
417 : 0 : varbuf_destroy(&uvb);
418 : : /* Fall through. */
419 : 0 : case msdbrw_needsuperuserlockonly:
420 : 0 : modstatdb_unlock();
421 : 52 : default:
422 : 52 : break;
423 : : }
424 : :
425 : 52 : pkg_hash_reset();
426 : :
427 : 52 : modstatdb_done();
428 : 52 : }
429 : :
430 : : static void
431 : 0 : modstatdb_note_core(struct pkginfo *pkg)
432 : : {
433 [ # # ]: 0 : if (cstatus < msdbrw_write)
434 : 0 : internerr("modstatdb status '%d' is not writable", cstatus);
435 : :
436 : 0 : varbuf_reset(&uvb);
437 : 0 : varbuf_stanza(&uvb, pkg, &pkg->installed);
438 : :
439 [ # # ]: 0 : if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used)
440 : 0 : ohshite(_("unable to write updated status of '%.250s'"),
441 : : pkg_name(pkg, pnaw_nonambig));
442 [ # # ]: 0 : if (fflush(importanttmp))
443 : 0 : ohshite(_("unable to flush updated status of '%.250s'"),
444 : : pkg_name(pkg, pnaw_nonambig));
445 [ # # ]: 0 : if (ftruncate(fileno(importanttmp), uvb.used))
446 : 0 : ohshite(_("unable to truncate for updated status of '%.250s'"),
447 : : pkg_name(pkg, pnaw_nonambig));
448 [ # # ]: 0 : if (fsync(fileno(importanttmp)))
449 : 0 : ohshite(_("unable to fsync updated status of '%.250s'"),
450 : : pkg_name(pkg, pnaw_nonambig));
451 [ # # ]: 0 : if (fclose(importanttmp))
452 : 0 : ohshite(_("unable to close updated status of '%.250s'"),
453 : : pkg_name(pkg, pnaw_nonambig));
454 : 0 : varbuf_rollback(&updatefn_state);
455 : 0 : varbuf_printf(&updatefn, IMPORTANTFMT, nextupdate);
456 [ # # ]: 0 : if (rename(importanttmpfile, updatefn.buf))
457 : 0 : ohshite(_("unable to install updated status of '%.250s'"),
458 : : pkg_name(pkg, pnaw_nonambig));
459 : :
460 : 0 : dir_sync_path(updatesdir);
461 : :
462 : : /* Have we made a real mess? */
463 [ # # ]: 0 : if (varbuf_rollback_len(&updatefn_state) > IMPORTANTMAXLEN)
464 : 0 : internerr("modstatdb update entry name '%s' longer than %d",
465 : : varbuf_rollback_start(&updatefn_state), IMPORTANTMAXLEN);
466 : :
467 : 0 : nextupdate++;
468 : :
469 [ # # ]: 0 : if (nextupdate > MAXUPDATES) {
470 : 0 : modstatdb_checkpoint();
471 : 0 : nextupdate = 0;
472 : : }
473 : :
474 : 0 : createimptmp();
475 : 0 : }
476 : :
477 : : /*
478 : : * Note: If anyone wants to set some triggers-pending, they must also
479 : : * set status appropriately, or we will undo it. That is, it is legal
480 : : * to call this when pkg->status and pkg->trigpend_head disagree and
481 : : * in that case pkg->status takes precedence and pkg->trigpend_head
482 : : * will be adjusted.
483 : : */
484 : 0 : void modstatdb_note(struct pkginfo *pkg) {
485 : : struct trigaw *ta;
486 : :
487 : 0 : onerr_abort++;
488 : :
489 : : /* Clear pending triggers here so that only code that sets the status
490 : : * to interesting (for triggers) values has to care about triggers. */
491 [ # # ]: 0 : if (pkg->status != PKG_STAT_TRIGGERSPENDING &&
492 [ # # ]: 0 : pkg->status != PKG_STAT_TRIGGERSAWAITED)
493 : 0 : pkg->trigpend_head = NULL;
494 : :
495 [ # # ]: 0 : if (pkg->status <= PKG_STAT_CONFIGFILES) {
496 [ # # ]: 0 : for (ta = pkg->trigaw.head; ta; ta = ta->sameaw.next)
497 : 0 : ta->aw = NULL;
498 : 0 : pkg->trigaw.head = pkg->trigaw.tail = NULL;
499 : : }
500 : :
501 [ # # ]: 0 : if (pkg->status_dirty) {
502 : 0 : log_message("status %s %s %s", pkg_status_name(pkg),
503 : : pkg_name(pkg, pnaw_always),
504 : 0 : versiondescribe_c(&pkg->installed.version, vdew_nonambig));
505 : 0 : statusfd_send("status: %s: %s", pkg_name(pkg, pnaw_nonambig),
506 : : pkg_status_name(pkg));
507 : :
508 : 0 : pkg->status_dirty = false;
509 : : }
510 : :
511 [ # # ]: 0 : if (cstatus >= msdbrw_write)
512 : 0 : modstatdb_note_core(pkg);
513 : :
514 [ # # # # ]: 0 : if (!pkg->trigpend_head && pkg->othertrigaw_head) {
515 : : /* Automatically remove us from other packages' Triggers-Awaited.
516 : : * We do this last because we want to maximize our chances of
517 : : * successfully recording the status of the package we were
518 : : * pointed at by our caller, although there is some risk of
519 : : * leaving us in a slightly odd situation which is cleared up
520 : : * by the trigger handling logic in deppossi_ok_found. */
521 : 0 : trig_clear_awaiters(pkg);
522 : : }
523 : :
524 : 0 : onerr_abort--;
525 : 0 : }
526 : :
527 : : void
528 : 0 : modstatdb_note_ifwrite(struct pkginfo *pkg)
529 : : {
530 [ # # ]: 0 : if (cstatus >= msdbrw_write)
531 : 0 : modstatdb_note(pkg);
532 : 0 : }
533 : :
|