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