Commit | Line | Data |
---|---|---|
1479465f GJ |
1 | /* |
2 | * dpkg-deb - construction and deconstruction of *.deb archives | |
3 | * info.c - providing information | |
4 | * | |
5 | * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk> | |
6 | * Copyright © 2001 Wichert Akkerman | |
7 | * Copyright © 2007-2015 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 | #include <sys/wait.h> | |
29 | ||
30 | #include <errno.h> | |
31 | #include <limits.h> | |
32 | #include <string.h> | |
33 | #include <fcntl.h> | |
34 | #include <dirent.h> | |
35 | #include <unistd.h> | |
36 | #include <stdint.h> | |
37 | #include <stdlib.h> | |
38 | #include <stdio.h> | |
39 | ||
40 | #include <dpkg/i18n.h> | |
41 | #include <dpkg/c-ctype.h> | |
42 | #include <dpkg/dpkg.h> | |
43 | #include <dpkg/dpkg-db.h> | |
44 | #include <dpkg/parsedump.h> | |
45 | #include <dpkg/pkg-format.h> | |
46 | #include <dpkg/buffer.h> | |
47 | #include <dpkg/path.h> | |
48 | #include <dpkg/options.h> | |
49 | ||
50 | #include "dpkg-deb.h" | |
51 | ||
52 | static void cu_info_prepare(int argc, void **argv) { | |
53 | char *dir; | |
54 | ||
55 | dir = argv[0]; | |
56 | path_remove_tree(dir); | |
57 | free(dir); | |
58 | } | |
59 | ||
60 | static void info_prepare(const char *const **argvp, | |
61 | const char **debarp, | |
62 | const char **dirp, | |
63 | int admininfo) { | |
64 | char *dbuf; | |
65 | ||
66 | *debarp= *(*argvp)++; | |
67 | if (!*debarp) badusage(_("--%s needs a .deb filename argument"),cipaction->olong); | |
68 | ||
69 | dbuf = mkdtemp(path_make_temp_template("dpkg-deb")); | |
70 | if (!dbuf) | |
71 | ohshite(_("unable to create temporary directory")); | |
72 | *dirp = dbuf; | |
73 | ||
74 | push_cleanup(cu_info_prepare, -1, NULL, 0, 1, (void *)dbuf); | |
75 | extracthalf(*debarp, dbuf, DPKG_TAR_EXTRACT | DPKG_TAR_NOMTIME, admininfo); | |
76 | } | |
77 | ||
78 | static int ilist_select(const struct dirent *de) { | |
79 | return strcmp(de->d_name,".") && strcmp(de->d_name,".."); | |
80 | } | |
81 | ||
82 | static void | |
83 | info_spew(const char *debar, const char *dir, const char *const *argv) | |
84 | { | |
85 | struct dpkg_error err; | |
86 | const char *component; | |
87 | struct varbuf controlfile = VARBUF_INIT; | |
88 | int fd; | |
89 | int re= 0; | |
90 | ||
91 | while ((component = *argv++) != NULL) { | |
92 | varbuf_reset(&controlfile); | |
93 | varbuf_printf(&controlfile, "%s/%s", dir, component); | |
94 | ||
95 | fd = open(controlfile.buf, O_RDONLY); | |
96 | if (fd >= 0) { | |
97 | if (fd_fd_copy(fd, 1, -1, &err) < 0) | |
98 | ohshit(_("cannot extract control file '%s' from '%s': %s"), | |
99 | controlfile.buf, debar, err.str); | |
100 | close(fd); | |
101 | } else if (errno == ENOENT) { | |
102 | notice(_("'%.255s' contains no control component '%.255s'"), | |
103 | debar, component); | |
104 | re++; | |
105 | } else { | |
106 | ohshite(_("open component '%.255s' (in %.255s) failed in an unexpected way"), | |
107 | component, dir); | |
108 | } | |
109 | } | |
110 | varbuf_destroy(&controlfile); | |
111 | ||
112 | if (re > 0) | |
113 | ohshit(P_("%d requested control component is missing", | |
114 | "%d requested control components are missing", re), re); | |
115 | } | |
116 | ||
117 | static void | |
118 | info_list(const char *debar, const char *dir) | |
119 | { | |
120 | char interpreter[INTERPRETER_MAX+1], *p; | |
121 | int il, lines; | |
122 | struct varbuf controlfile = VARBUF_INIT; | |
123 | struct dirent **cdlist, *cdep; | |
124 | int cdn, n; | |
125 | FILE *cc; | |
126 | struct stat stab; | |
127 | int c; | |
128 | ||
129 | cdn = scandir(dir, &cdlist, &ilist_select, alphasort); | |
130 | if (cdn == -1) | |
131 | ohshite(_("cannot scan directory '%.255s'"), dir); | |
132 | ||
133 | for (n = 0; n < cdn; n++) { | |
134 | cdep = cdlist[n]; | |
135 | ||
136 | varbuf_reset(&controlfile); | |
137 | varbuf_printf(&controlfile, "%s/%s", dir, cdep->d_name); | |
138 | ||
139 | if (stat(controlfile.buf, &stab)) | |
140 | ohshite(_("cannot stat '%.255s' (in '%.255s')"), cdep->d_name, dir); | |
141 | if (S_ISREG(stab.st_mode)) { | |
142 | cc = fopen(controlfile.buf, "r"); | |
143 | if (!cc) | |
144 | ohshite(_("cannot open '%.255s' (in '%.255s')"), cdep->d_name, dir); | |
145 | lines = 0; | |
146 | interpreter[0] = '\0'; | |
147 | if (getc(cc) == '#') { | |
148 | if (getc(cc) == '!') { | |
149 | while ((c= getc(cc))== ' '); | |
150 | p=interpreter; *p++='#'; *p++='!'; il=2; | |
151 | while (il < INTERPRETER_MAX && !c_isspace(c) && c != EOF) { | |
152 | *p++= c; il++; c= getc(cc); | |
153 | } | |
154 | *p = '\0'; | |
155 | if (c=='\n') lines++; | |
156 | } | |
157 | } | |
158 | while ((c= getc(cc))!= EOF) { if (c == '\n') lines++; } | |
159 | if (ferror(cc)) | |
160 | ohshite(_("failed to read '%.255s' (in '%.255s')"), cdep->d_name, dir); | |
161 | fclose(cc); | |
162 | printf(_(" %7jd bytes, %5d lines %c %-20.127s %.127s\n"), | |
163 | (intmax_t)stab.st_size, lines, S_IXUSR & stab.st_mode ? '*' : ' ', | |
164 | cdep->d_name, interpreter); | |
165 | } else { | |
166 | printf(_(" not a plain file %.255s\n"), cdep->d_name); | |
167 | } | |
168 | free(cdep); | |
169 | } | |
170 | free(cdlist); | |
171 | ||
172 | varbuf_reset(&controlfile); | |
173 | varbuf_printf(&controlfile, "%s/%s", dir, CONTROLFILE); | |
174 | cc = fopen(controlfile.buf, "r"); | |
175 | if (!cc) { | |
176 | if (errno != ENOENT) | |
177 | ohshite(_("failed to read '%.255s' (in '%.255s')"), CONTROLFILE, dir); | |
178 | warning(_("no 'control' file in control archive!")); | |
179 | } else { | |
180 | lines= 1; | |
181 | while ((c= getc(cc))!= EOF) { | |
182 | if (lines) | |
183 | putc(' ', stdout); | |
184 | putc(c, stdout); | |
185 | lines= c=='\n'; | |
186 | } | |
187 | if (!lines) | |
188 | putc('\n', stdout); | |
189 | ||
190 | if (ferror(cc)) | |
191 | ohshite(_("failed to read '%.255s' (in '%.255s')"), CONTROLFILE, dir); | |
192 | fclose(cc); | |
193 | } | |
194 | ||
195 | m_output(stdout, _("<standard output>")); | |
196 | varbuf_destroy(&controlfile); | |
197 | } | |
198 | ||
199 | static void | |
200 | info_field(const char *debar, const char *dir, const char *const *fields, | |
201 | enum fwriteflags fieldflags) | |
202 | { | |
203 | char *controlfile; | |
204 | struct varbuf str = VARBUF_INIT; | |
205 | struct pkginfo *pkg; | |
206 | int i; | |
207 | ||
208 | controlfile = str_fmt("%s/%s", dir, CONTROLFILE); | |
209 | parsedb(controlfile, pdb_parse_binary | pdb_ignorefiles, &pkg); | |
210 | free(controlfile); | |
211 | ||
212 | for (i = 0; fields[i]; i++) { | |
213 | const struct fieldinfo *field; | |
214 | const struct arbitraryfield *arbfield; | |
215 | ||
216 | varbuf_reset(&str); | |
217 | field = find_field_info(fieldinfos, fields[i]); | |
218 | if (field) { | |
219 | field->wcall(&str, pkg, &pkg->available, fieldflags, field); | |
220 | } else { | |
221 | arbfield = find_arbfield_info(pkg->available.arbs, fields[i]); | |
222 | if (arbfield) | |
223 | varbuf_add_arbfield(&str, arbfield, fieldflags); | |
224 | } | |
225 | varbuf_end_str(&str); | |
226 | ||
227 | if (fieldflags & fw_printheader) | |
228 | printf("%s", str.buf); | |
229 | else | |
230 | printf("%s\n", str.buf); | |
231 | } | |
232 | ||
233 | m_output(stdout, _("<standard output>")); | |
234 | ||
235 | varbuf_destroy(&str); | |
236 | } | |
237 | ||
238 | int | |
239 | do_showinfo(const char *const *argv) | |
240 | { | |
241 | const char *debar, *dir; | |
242 | char *controlfile; | |
243 | struct dpkg_error err; | |
244 | struct pkginfo *pkg; | |
245 | struct pkg_format_node *fmt; | |
246 | ||
247 | fmt = pkg_format_parse(showformat, &err); | |
248 | if (!fmt) | |
249 | ohshit(_("error in show format: %s"), err.str); | |
250 | ||
251 | info_prepare(&argv, &debar, &dir, 1); | |
252 | ||
253 | controlfile = str_fmt("%s/%s", dir, CONTROLFILE); | |
254 | parsedb(controlfile, pdb_parse_binary | pdb_ignorefiles, &pkg); | |
255 | pkg_format_show(fmt, pkg, &pkg->available); | |
256 | pkg_format_free(fmt); | |
257 | free(controlfile); | |
258 | ||
259 | return 0; | |
260 | } | |
261 | ||
262 | int | |
263 | do_info(const char *const *argv) | |
264 | { | |
265 | const char *debar, *dir; | |
266 | ||
267 | if (*argv && argv[1]) { | |
268 | info_prepare(&argv, &debar, &dir, 1); | |
269 | info_spew(debar, dir, argv); | |
270 | } else { | |
271 | info_prepare(&argv, &debar, &dir, 2); | |
272 | info_list(debar, dir); | |
273 | } | |
274 | ||
275 | return 0; | |
276 | } | |
277 | ||
278 | int | |
279 | do_field(const char *const *argv) | |
280 | { | |
281 | const char *debar, *dir; | |
282 | ||
283 | info_prepare(&argv, &debar, &dir, 1); | |
284 | if (*argv) { | |
285 | info_field(debar, dir, argv, argv[1] != NULL ? fw_printheader : 0); | |
286 | } else { | |
287 | static const char *const controlonly[] = { CONTROLFILE, NULL }; | |
288 | info_spew(debar, dir, controlonly); | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | int | |
295 | do_contents(const char *const *argv) | |
296 | { | |
297 | const char *debar = *argv++; | |
298 | ||
299 | if (debar == NULL || *argv) | |
300 | badusage(_("--%s takes exactly one argument"), cipaction->olong); | |
301 | extracthalf(debar, NULL, DPKG_TAR_LIST, 0); | |
302 | ||
303 | return 0; | |
304 | } |