chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / src / statdb.c
1 /*
2  * dpkg - main program for package management
3  * statdb.c - management of database of ownership and mode of files
4  *
5  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6  * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
7  * Copyright © 2008-2012 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/types.h>
27 #include <sys/stat.h>
28
29 #include <errno.h>
30 #include <string.h>
31 #include <pwd.h>
32 #include <grp.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36
37 #include <dpkg/i18n.h>
38 #include <dpkg/dpkg.h>
39 #include <dpkg/dpkg-db.h>
40 #include <dpkg/fdio.h>
41
42 #include "filesdb.h"
43 #include "main.h"
44
45 static char *statoverridename;
46
47 uid_t
48 statdb_parse_uid(const char *str)
49 {
50         char *endptr;
51         uid_t uid;
52
53         if (str[0] == '#') {
54                 long int value;
55
56                 errno = 0;
57                 value = strtol(str + 1, &endptr, 10);
58                 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
59                         ohshit(_("invalid statoverride uid %s"), str);
60                 uid = (uid_t)value;
61         } else {
62                 struct passwd *pw = getpwnam(str);
63
64                 if (pw == NULL)
65                         uid = (uid_t)-1;
66                 else
67                         uid = pw->pw_uid;
68         }
69
70         return uid;
71 }
72
73 gid_t
74 statdb_parse_gid(const char *str)
75 {
76         char *endptr;
77         gid_t gid;
78
79         if (str[0] == '#') {
80                 long int value;
81
82                 errno = 0;
83                 value = strtol(str + 1, &endptr, 10);
84                 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
85                         ohshit(_("invalid statoverride gid %s"), str);
86                 gid = (gid_t)value;
87         } else {
88                 struct group *gr = getgrnam(str);
89
90                 if (gr == NULL)
91                         gid = (gid_t)-1;
92                 else
93                         gid = gr->gr_gid;
94         }
95
96         return gid;
97 }
98
99 mode_t
100 statdb_parse_mode(const char *str)
101 {
102         char *endptr;
103         long int mode;
104
105         mode = strtol(str, &endptr, 8);
106         if (str == endptr || *endptr || mode < 0 || mode > 07777)
107                 ohshit(_("invalid statoverride mode %s"), str);
108
109         return (mode_t)mode;
110 }
111
112 void
113 ensure_statoverrides(enum statdb_parse_flags flags)
114 {
115         static struct stat sb_prev;
116         struct stat sb_next;
117         static FILE *file_prev;
118         FILE *file;
119         char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
120         struct file_stat *fso;
121         struct filenamenode *fnn;
122         struct fileiterator *iter;
123
124         if (statoverridename == NULL)
125                 statoverridename = dpkg_db_get_path(STATOVERRIDEFILE);
126
127         onerr_abort++;
128
129         file = fopen(statoverridename, "r");
130         if (!file) {
131                 if (errno != ENOENT)
132                         ohshite(_("failed to open statoverride file"));
133         } else {
134                 setcloexec(fileno(file), statoverridename);
135
136                 if (fstat(fileno(file), &sb_next))
137                         ohshite(_("failed to fstat statoverride file"));
138
139                 /*
140                  * We need to keep the database file open so that the
141                  * filesystem cannot reuse the inode number (f.ex. during
142                  * multiple dpkg-statoverride invocations in a maintainer
143                  * script), otherwise the following check might turn true,
144                  * and we would skip reloading a modified database.
145                  */
146                 if (file_prev &&
147                     sb_prev.st_dev == sb_next.st_dev &&
148                     sb_prev.st_ino == sb_next.st_ino) {
149                         fclose(file);
150                         onerr_abort--;
151                         debug(dbg_general, "%s: same, skipping", __func__);
152                         return;
153                 }
154                 sb_prev = sb_next;
155         }
156         if (file_prev)
157                 fclose(file_prev);
158         file_prev = file;
159
160         /* Reset statoverride information. */
161         iter = files_db_iter_new();
162         while ((fnn = files_db_iter_next(iter)))
163                 fnn->statoverride = NULL;
164         files_db_iter_free(iter);
165
166         if (!file) {
167                 onerr_abort--;
168                 debug(dbg_general, "%s: none, resetting", __func__);
169                 return;
170         }
171         debug(dbg_general, "%s: new, (re)loading", __func__);
172
173         /* If the statoverride list is empty we don't need to bother
174          * reading it. */
175         if (!sb_next.st_size) {
176                 onerr_abort--;
177                 return;
178         }
179
180         loaded_list = m_malloc(sb_next.st_size);
181         loaded_list_end = loaded_list + sb_next.st_size;
182
183         if (fd_read(fileno(file), loaded_list, sb_next.st_size) < 0)
184                 ohshite(_("reading statoverride file '%.250s'"), statoverridename);
185
186         thisline = loaded_list;
187         while (thisline < loaded_list_end) {
188                 fso = nfmalloc(sizeof(struct file_stat));
189
190                 ptr = memchr(thisline, '\n', loaded_list_end - thisline);
191                 if (ptr == NULL)
192                         ohshit(_("statoverride file is missing final newline"));
193                 /* Where to start next time around. */
194                 nextline = ptr + 1;
195                 if (ptr == thisline)
196                         ohshit(_("statoverride file contains empty line"));
197                 *ptr = '\0';
198
199                 /* Extract the uid. */
200                 ptr = memchr(thisline, ' ', nextline - thisline);
201                 if (ptr == NULL)
202                         ohshit(_("syntax error in statoverride file"));
203                 *ptr = '\0';
204
205                 fso->uid = statdb_parse_uid(thisline);
206                 if (fso->uid == (uid_t)-1)
207                         fso->uname = nfstrsave(thisline);
208                 else
209                         fso->uname = NULL;
210
211                 if (fso->uid == (uid_t)-1 && !(flags & STATDB_PARSE_LAX))
212                         ohshit(_("unknown user '%s' in statoverride file"),
213                                thisline);
214
215                 /* Move to the next bit */
216                 thisline = ptr + 1;
217                 if (thisline >= loaded_list_end)
218                         ohshit(_("unexpected end of line in statoverride file"));
219
220                 /* Extract the gid */
221                 ptr = memchr(thisline, ' ', nextline - thisline);
222                 if (ptr == NULL)
223                         ohshit(_("syntax error in statoverride file"));
224                 *ptr = '\0';
225
226                 fso->gid = statdb_parse_gid(thisline);
227                 if (fso->gid == (gid_t)-1)
228                         fso->gname = nfstrsave(thisline);
229                 else
230                         fso->gname = NULL;
231
232                 if (fso->gid == (gid_t)-1 && !(flags & STATDB_PARSE_LAX))
233                         ohshit(_("unknown group '%s' in statoverride file"),
234                                thisline);
235
236                 /* Move to the next bit */
237                 thisline = ptr + 1;
238                 if (thisline >= loaded_list_end)
239                         ohshit(_("unexpected end of line in statoverride file"));
240
241                 /* Extract the mode */
242                 ptr = memchr(thisline, ' ', nextline - thisline);
243                 if (ptr == NULL)
244                         ohshit(_("syntax error in statoverride file"));
245                 *ptr = '\0';
246
247                 fso->mode = statdb_parse_mode(thisline);
248
249                 /* Move to the next bit */
250                 thisline = ptr + 1;
251                 if (thisline >= loaded_list_end)
252                         ohshit(_("unexpected end of line in statoverride file"));
253
254                 fnn = findnamenode(thisline, 0);
255                 if (fnn->statoverride)
256                         ohshit(_("multiple statoverrides present for file '%.250s'"),
257                                thisline);
258                 fnn->statoverride = fso;
259
260                 /* Moving on... */
261                 thisline = nextline;
262         }
263
264         free(loaded_list);
265
266         onerr_abort--;
267 }