| /* |
| * dpkg-deb - construction and deconstruction of *.deb archives |
| * info.c - providing information |
| * |
| * Copyright © 1994,1995 Ian Jackson <ian@chiark.greenend.org.uk> |
| * Copyright © 2001 Wichert Akkerman |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <config.h> |
| #include <compat.h> |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/wait.h> |
| |
| #include <errno.h> |
| #include <limits.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <dirent.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include <dpkg/i18n.h> |
| #include <dpkg/dpkg.h> |
| #include <dpkg/dpkg-db.h> |
| #include <dpkg/pkg-format.h> |
| #include <dpkg/buffer.h> |
| #include <dpkg/path.h> |
| #include <dpkg/subproc.h> |
| #include <dpkg/options.h> |
| |
| #include "dpkg-deb.h" |
| |
| static void cu_info_prepare(int argc, void **argv) { |
| pid_t pid; |
| char *dir; |
| struct stat stab; |
| |
| dir = argv[0]; |
| if (lstat(dir, &stab) && errno == ENOENT) |
| return; |
| |
| pid = subproc_fork(); |
| if (pid == 0) { |
| if (chdir("/")) |
| ohshite(_("failed to chdir to `/' for cleanup")); |
| execlp(RM, "rm", "-rf", dir, NULL); |
| ohshite(_("unable to execute %s (%s)"), _("rm command for cleanup"), RM); |
| } |
| subproc_wait_check(pid, _("rm command for cleanup"), 0); |
| } |
| |
| static void info_prepare(const char *const **argvp, |
| const char **debarp, |
| const char **dirp, |
| int admininfo) { |
| char *dbuf; |
| |
| *debarp= *(*argvp)++; |
| if (!*debarp) badusage(_("--%s needs a .deb filename argument"),cipaction->olong); |
| |
| dbuf = mkdtemp(path_make_temp_template("dpkg-deb")); |
| if (!dbuf) |
| ohshite(_("unable to create temporary directory")); |
| *dirp = dbuf; |
| |
| push_cleanup(cu_info_prepare, -1, NULL, 0, 1, (void *)dbuf); |
| extracthalf(*debarp, dbuf, "mx", admininfo); |
| } |
| |
| static int ilist_select(const struct dirent *de) { |
| return strcmp(de->d_name,".") && strcmp(de->d_name,".."); |
| } |
| |
| static void |
| info_spew(const char *debar, const char *dir, const char *const *argv) |
| { |
| const char *component; |
| struct varbuf controlfile = VARBUF_INIT; |
| int fd; |
| int re= 0; |
| |
| while ((component = *argv++) != NULL) { |
| varbuf_reset(&controlfile); |
| varbuf_printf(&controlfile, "%s/%s", dir, component); |
| |
| fd = open(controlfile.buf, O_RDONLY); |
| if (fd >= 0) { |
| fd_fd_copy(fd, 1, -1, _("control file '%s'"), controlfile.buf); |
| close(fd); |
| } else if (errno == ENOENT) { |
| fprintf(stderr, |
| _("dpkg-deb: `%.255s' contains no control component `%.255s'\n"), |
| debar, component); |
| re++; |
| } else { |
| ohshite(_("open component `%.255s' (in %.255s) failed in an unexpected way"), |
| component, dir); |
| } |
| } |
| varbuf_destroy(&controlfile); |
| |
| if (re > 0) |
| ohshit(P_("%d requested control component is missing", |
| "%d requested control components are missing", re), re); |
| } |
| |
| static void |
| info_list(const char *debar, const char *dir) |
| { |
| char interpreter[INTERPRETER_MAX+1], *p; |
| int il, lines; |
| struct varbuf controlfile = VARBUF_INIT; |
| struct dirent **cdlist, *cdep; |
| int cdn, n; |
| FILE *cc; |
| struct stat stab; |
| int c; |
| |
| cdn = scandir(dir, &cdlist, &ilist_select, alphasort); |
| if (cdn == -1) |
| ohshite(_("cannot scan directory `%.255s'"), dir); |
| |
| for (n = 0; n < cdn; n++) { |
| cdep = cdlist[n]; |
| |
| varbuf_reset(&controlfile); |
| varbuf_printf(&controlfile, "%s/%s", dir, cdep->d_name); |
| |
| if (stat(controlfile.buf, &stab)) |
| ohshite(_("cannot stat `%.255s' (in `%.255s')"), cdep->d_name, dir); |
| if (S_ISREG(stab.st_mode)) { |
| cc = fopen(controlfile.buf, "r"); |
| if (!cc) |
| ohshite(_("cannot open `%.255s' (in `%.255s')"), cdep->d_name, dir); |
| lines = 0; |
| interpreter[0] = '\0'; |
| if (getc(cc) == '#') { |
| if (getc(cc) == '!') { |
| while ((c= getc(cc))== ' '); |
| p=interpreter; *p++='#'; *p++='!'; il=2; |
| while (il<INTERPRETER_MAX && !isspace(c) && c!=EOF) { |
| *p++= c; il++; c= getc(cc); |
| } |
| *p = '\0'; |
| if (c=='\n') lines++; |
| } |
| } |
| while ((c= getc(cc))!= EOF) { if (c == '\n') lines++; } |
| if (ferror(cc)) ohshite(_("failed to read `%.255s' (in `%.255s')"), |
| cdep->d_name, dir); |
| fclose(cc); |
| printf(_(" %7jd bytes, %5d lines %c %-20.127s %.127s\n"), |
| (intmax_t)stab.st_size, lines, S_IXUSR & stab.st_mode ? '*' : ' ', |
| cdep->d_name, interpreter); |
| } else { |
| printf(_(" not a plain file %.255s\n"), cdep->d_name); |
| } |
| free(cdep); |
| } |
| free(cdlist); |
| |
| varbuf_reset(&controlfile); |
| varbuf_printf(&controlfile, "%s/%s", dir, CONTROLFILE); |
| cc = fopen(controlfile.buf, "r"); |
| if (!cc) { |
| if (errno != ENOENT) |
| ohshite(_("failed to read `%.255s' (in `%.255s')"), CONTROLFILE, dir); |
| fputs(_("(no `control' file in control archive!)\n"), stdout); |
| } else { |
| lines= 1; |
| while ((c= getc(cc))!= EOF) { |
| if (lines) |
| putc(' ', stdout); |
| putc(c, stdout); |
| lines= c=='\n'; |
| } |
| if (!lines) |
| putc('\n', stdout); |
| |
| if (ferror(cc)) |
| ohshite(_("failed to read `%.255s' (in `%.255s')"), CONTROLFILE, dir); |
| fclose(cc); |
| } |
| |
| m_output(stdout, _("<standard output>")); |
| varbuf_destroy(&controlfile); |
| } |
| |
| static void |
| info_field(const char *debar, const char *dir, const char *const *fields, |
| bool showfieldname) |
| { |
| FILE *cc; |
| char *controlfile; |
| char fieldname[MAXFIELDNAME+1]; |
| char *pf; |
| const char *const *fp; |
| int c, lno, fnl; |
| bool doing; |
| |
| m_asprintf(&controlfile, "%s/%s", dir, CONTROLFILE); |
| cc = fopen(controlfile, "r"); |
| if (!cc) |
| ohshite(_("could not open the `control' component")); |
| doing = true; |
| lno = 1; |
| for (;;) { |
| c = getc(cc); |
| if (c == EOF) { |
| doing = false; |
| break; |
| } |
| if (c == '\n') { |
| lno++; |
| doing = true; |
| continue; |
| } |
| if (!isspace(c)) { |
| for (pf=fieldname, fnl=0; |
| fnl <= MAXFIELDNAME && c!=EOF && !isspace(c) && c!=':'; |
| c= getc(cc)) { *pf++= c; fnl++; } |
| *pf = '\0'; |
| doing= fnl >= MAXFIELDNAME || c=='\n' || c==EOF; |
| for (fp=fields; !doing && *fp; fp++) |
| if (!strcasecmp(*fp, fieldname)) |
| doing = true; |
| if (showfieldname) { |
| if (doing) |
| fputs(fieldname,stdout); |
| } else { |
| if (c==':') c= getc(cc); |
| while (c != '\n' && isspace(c)) c= getc(cc); |
| } |
| } |
| for(;;) { |
| if (c == EOF) break; |
| if (doing) putc(c,stdout); |
| if (c == '\n') { lno++; break; } |
| c= getc(cc); |
| } |
| if (c == EOF) break; |
| } |
| if (ferror(cc)) ohshite(_("failed during read of `control' component")); |
| if (fclose(cc)) |
| ohshite(_("error closing the '%s' component"), CONTROLFILE); |
| if (doing) putc('\n',stdout); |
| m_output(stdout, _("<standard output>")); |
| free(controlfile); |
| } |
| |
| int |
| do_showinfo(const char *const *argv) |
| { |
| const char *debar, *dir; |
| char *controlfile; |
| struct pkginfo *pkg; |
| struct pkg_format_node *fmt = pkg_format_parse(showformat); |
| |
| if (!fmt) |
| ohshit(_("Error in format")); |
| |
| info_prepare(&argv, &debar, &dir, 1); |
| |
| m_asprintf(&controlfile, "%s/%s", dir, CONTROLFILE); |
| parsedb(controlfile, |
| pdb_recordavailable | pdb_rejectstatus | pdb_ignorefiles, &pkg); |
| pkg_format_show(fmt, pkg, &pkg->available); |
| free(controlfile); |
| |
| return 0; |
| } |
| |
| int |
| do_info(const char *const *argv) |
| { |
| const char *debar, *dir; |
| |
| if (*argv && argv[1]) { |
| info_prepare(&argv, &debar, &dir, 1); |
| info_spew(debar, dir, argv); |
| } else { |
| info_prepare(&argv, &debar, &dir, 2); |
| info_list(debar, dir); |
| } |
| |
| return 0; |
| } |
| |
| int |
| do_field(const char *const *argv) |
| { |
| const char *debar, *dir; |
| |
| info_prepare(&argv, &debar, &dir, 1); |
| if (*argv) { |
| info_field(debar, dir, argv, argv[1] != NULL); |
| } else { |
| static const char *const controlonly[] = { CONTROLFILE, NULL }; |
| info_spew(debar, dir, controlonly); |
| } |
| |
| return 0; |
| } |
| |
| int |
| do_contents(const char *const *argv) |
| { |
| const char *debar; |
| |
| if (!(debar= *argv++) || *argv) badusage(_("--contents takes exactly one argument")); |
| extracthalf(debar, NULL, "tv", 0); |
| |
| return 0; |
| } |
| /* vi: sw=2 |
| */ |