From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 4FE943858D32; Sun, 29 Jan 2023 13:13:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4FE943858D32 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674998022; bh=XJoZFIV6PW40lJBdstaeLA7+m7pF5rN2s9Xt2vOa6dc=; h=From:To:Subject:Date:From; b=vbB4cFZnvTtZiBTaNcvuONV49hw4lyO62/FSqoP8aqp6ECBUcId12tyz7rA0Yb03y rHjSPDy1pHHkJwgEvGuhN1bn4cbv9jq14HNLapmomIOxUUG3tZMWVtVMMdl7e6EvbV 3/j7YUQpCFw3V/BXRtUUsmrnqz53PGtOJkRFdBjM= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin/main] Cygwin: cygcheck: package info / available package search, take 2 X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/main X-Git-Oldrev: 76d2053ec890884f149c8cd46dee95bde36cb95d X-Git-Newrev: 022665af17d68c8e8bfe60258c69d5dc1c4f625d Message-Id: <20230129131342.4FE943858D32@sourceware.org> Date: Sun, 29 Jan 2023 13:13:42 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D022665af17d= 68c8e8bfe60258c69d5dc1c4f625d commit 022665af17d68c8e8bfe60258c69d5dc1c4f625d Author: Corinna Vinschen AuthorDate: Sun Jan 29 14:13:25 2023 +0100 Commit: Corinna Vinschen CommitDate: Sun Jan 29 14:13:25 2023 +0100 Cygwin: cygcheck: package info / available package search, take 2 =20 - if the user has no perms to write to /etc/setup, don't try to fetch user homedir from Cygwin (crashes galore). Use LOCALAPPDATA path instead. - info is more rpm like - print info of installed package - added info selectors --inst, --curr, --prev, --test - add installation date =20 TODO: =20 - Human-readable filesize - url and license needs to be added to setup.ini yet - =20 Signed-off-by: Corinna Vinschen Diff: --- winsup/utils/mingw/cygcheck.cc | 313 +++++++++++++++++++++++++++++------= ---- winsup/utils/mingw/cygcheck.h | 17 +++ winsup/utils/mingw/dump_setup.cc | 20 ++- 3 files changed, 257 insertions(+), 93 deletions(-) diff --git a/winsup/utils/mingw/cygcheck.cc b/winsup/utils/mingw/cygcheck.cc index 4a57e9a7b910..ed1d8f85a2d2 100644 --- a/winsup/utils/mingw/cygcheck.cc +++ b/winsup/utils/mingw/cygcheck.cc @@ -20,6 +20,7 @@ #include #include "path.h" #include "wide_path.h" +#include "cygcheck.h" #include #include #define cygwin_internal cygwin_internal_dontuse @@ -53,9 +54,15 @@ int find_package =3D 0; int list_package =3D 0; int grep_packages =3D 0; int info_packages =3D 0; +int info_selector =3D 0; int search_packages =3D 0; int del_orphaned_reg =3D 0; =20 +#define INFO_INST 0x01 +#define INFO_CURR 0x02 +#define INFO_PREV 0x04 +#define INFO_TEST 0x08 + static char emptystr[] =3D ""; =20 #ifdef __GNUC__ @@ -2097,11 +2104,6 @@ struct passwd { char *pw_shell; /* default shell */ }; =20 -struct sidbuf { - PSID psid; - int buffer[10]; -}; - /* Downloads setup.ini from cygwin.com, if it hasn't been downloaded already or is older than 24h. */ static FILE * @@ -2111,8 +2113,6 @@ maybe_download_setup_ini () char *path; struct stat st; FILE *fp; - struct passwd *pw; - sidbuf curr_user; =20 t24h_before =3D time (NULL) - 24 * 60 * 60; for (int i =3D 0; i < 2; ++i) @@ -2123,22 +2123,15 @@ maybe_download_setup_ini () path =3D cygpath ("/etc/setup/setup.ini", NULL); else { - BOOL ret; - DWORD len; - HANDLE ptok; + char *localappdata =3D getenv ("LOCALAPPDATA"); + char *cp; =20 - if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok)) - return NULL; - ret =3D GetTokenInformation (ptok, TokenUser, &curr_user, - sizeof curr_user, &len); - CloseHandle (ptok); - if (!ret) - return NULL; - pw =3D (struct passwd *) cygwin_internal (CW_GETPWSID, FALSE, - curr_user.psid); - if (!pw) + if (!localappdata) return NULL; - path =3D cygpath (pw->pw_dir, "/.setup.ini", NULL); + path =3D (char *) malloc (strlen (localappdata) + + strlen ("\\.setup.ini") + 1); + cp =3D stpcpy (path, localappdata); + stpcpy (cp, "\\.setup.ini"); } /* If file exists, and has been downloaded less than 24h ago, and if we can open it for reading, just use it. */ @@ -2149,11 +2142,12 @@ maybe_download_setup_ini () /* Otherwise, try to open it for writing and fetch from cygwin.com. = */ if ((fp =3D fopen (path, "w+")) !=3D NULL) { - fputs ("Fetching setup.ini from cygwin.com...\n", stderr); + fprintf (stderr, "Fetching %s from cygwin.com...\n", path); if (!fetch_url ("https://cygwin.com/ftp/cygwin/x86_64/setup.ini", fp)) { fclose (fp); fp =3D fopen (path, "rt"); + fputs ("\n", stderr); return fp; } fclose (fp); @@ -2168,6 +2162,9 @@ struct vers_info char *install; char *source; char *depends2; + time_t install_date; + bool matches; + bool installed; }; =20 struct ini_package_info @@ -2351,7 +2348,7 @@ package_info_print (ini_package_info *pi, vers_info *= vers) { char buf[4096]; =20 - printf ("Name : %s\n", pi->name); + printf ("Name : %s\n", pi->name); if (vers->version) { char *version =3D strcpy (buf, vers->version); @@ -2360,9 +2357,9 @@ package_info_print (ini_package_info *pi, vers_info *= vers) release =3D strrchr (version, '-'); if (release) *release++ =3D '\0'; - printf ("Version : %s\n", version); + printf ("Version : %s\n", version); if (release) - printf ("Release : %s\n", release); + printf ("Release : %s\n", release); } if (vers->install) { @@ -2385,8 +2382,10 @@ package_info_print (ini_package_info *pi, vers_info = *vers) } if (cp) { - printf ("Architecture : %s\n", arch); - printf ("Size : %s\n", size); /* FIXME: human-readable */ + printf ("Architecture: %s\n", arch); + if (vers->install_date) + printf ("Install Date: %s", ctime (&vers->install_date)); + printf ("Size : %s\n", size); /* FIXME: human-readable */ } } if (vers->source) @@ -2398,103 +2397,235 @@ package_info_print (ini_package_info *pi, vers_in= fo *vers) *cp =3D '\0'; cp =3D strrchr (source, '/'); if (cp) - printf ("Source : %s\n", cp + 1); + printf ("Source : %s\n", cp + 1); } } if (pi->sdesc) - printf ("Summary : %s\n", pi->sdesc); + printf ("Summary : %s\n", pi->sdesc); if (pi->url) - printf ("Url : %s\n", pi->url); + printf ("Url : %s\n", pi->url); if (pi->license) - printf ("License : %s\n", pi->license); + printf ("License : %s\n", pi->license); if (pi->ldesc) - { - char *ldesc =3D strcpy (buf, pi->ldesc); + printf ("Description :\n%s\n", pi->ldesc); + puts (""); +} =20 - while (ldesc) - { - char *nl =3D strchr (ldesc, '\n'); - if (nl) - *nl =3D '\0'; - printf ("%s : %s\n", ldesc =3D=3D buf ? "Description " : " ", - ldesc); - ldesc =3D nl ? nl + 1 : NULL; - } +static void +package_info_check (ini_package_info *pi, vers_info *vi, pkgver *pv, + bool &am, bool &ai) +{ + vi->matches =3D true; + if (pv && !strcmp (vi->version, pv->ver)) + vi->installed =3D true; + am |=3D vi->matches; + ai |=3D vi->installed; +} + +static inline bool +check_name_version (char *pkg_name, char *pkg_version, char *search) +{ + char nv_buf[4096]; + char *nvp, *cp; + + nvp =3D stpcpy (nv_buf, pkg_name); + *nvp++ =3D '-'; + stpcpy (nvp, pkg_version); + if (PathMatchSpecA (nv_buf, search)) + return true; + if ((cp =3D strrchr (nvp, '-'))) /* try w/o release */ + { + *cp =3D '\0'; + if (PathMatchSpecA (nv_buf, search)) + return true; } - puts (""); + return false; +} + +static void +package_info_vers_check (ini_package_info *pi, vers_info *vi, char *search, + pkgver *pv, bool &am, bool &ai) +{ + vi->matches =3D check_name_version (pi->name, vi->version, search); + if (pv && !strcmp (vi->version, pv->ver)) + vi->installed =3D true; + am |=3D vi->matches; + ai |=3D vi->installed; +} + +int +pkg_comp (const void *a, const void *b) +{ + pkgver *pa =3D (pkgver *) a; + pkgver *pb =3D (pkgver *) b; + + return strcmp (pa->name, pb->name); } =20 /* Print full info for the package matching the search string in terms of name/version. */ static int -package_info (char **search) +package_info (char **search, int selector) { FILE *fp =3D maybe_download_setup_ini (); ini_package_info pi_buf, *pi; + size_t inst_pkg_count; + pkgver *inst_pkgs; =20 if (!fp) return 1; =20 + if (selector =3D=3D 0) + selector =3D INFO_CURR | INFO_PREV | INFO_TEST | INFO_INST; + + inst_pkgs =3D get_installed_packages (NULL, &inst_pkg_count); + while (search && *search) { rewind (fp); while ((pi =3D collect_pkg_info (fp, &pi_buf))) { + pkgver pv =3D { pi->name, NULL }, *inst_pkg =3D NULL; + bool avail_installed =3D false; + bool avail_matches =3D false; + bool inst_matches =3D false; + + if (selector & INFO_INST) + { + inst_pkg =3D (pkgver *) bsearch (&pv, inst_pkgs, inst_pkg_count, + sizeof *inst_pkgs, pkg_comp); + if (inst_pkg) + { + if (PathMatchSpecA (inst_pkg->name, *search)) + inst_matches =3D true; + else + inst_matches =3D check_name_version (inst_pkg->name, + inst_pkg->ver, + *search); + } + } + /* Name matches? Print all versions */ if (PathMatchSpecA (pi->name, *search)) { if (pi->curr.version) - package_info_print (pi, &pi->curr); + package_info_check (pi, &pi->curr, inst_pkg, + avail_matches, avail_installed); for (size_t i =3D 0; i < pi->prev_count; ++i) - package_info_print (pi, pi->prev + i); + package_info_check (pi, pi->prev + i, inst_pkg, + avail_matches, avail_installed); for (size_t i =3D 0; i < pi->test_count; ++i) - package_info_print (pi, pi->test + i); + package_info_check (pi, pi->test + i, inst_pkg, + avail_matches, avail_installed); } else { /* Check if search matches name-version string */ - char nv_buf[4096], *nvp, *cp; + if (pi->curr.version) + package_info_vers_check (pi, &pi->curr, *search, inst_pkg, + avail_matches, avail_installed); + for (size_t i =3D 0; i < pi->prev_count; ++i) + package_info_vers_check (pi, pi->prev + i, *search, inst_pkg, + avail_matches, avail_installed); + for (size_t i =3D 0; i < pi->test_count; ++i) + package_info_vers_check (pi, pi->test + i, *search, inst_pkg, + avail_matches, avail_installed); + } =20 - nvp =3D stpcpy (nv_buf, pi->name); - *nvp++ =3D '-'; + /* First print installed package(s) */ + if (inst_pkg && inst_matches) + { + time_t install_ts =3D 0; + struct stat st; + char *path; =20 - if (pi->curr.version) + printf ("Installed package:\n" + "------------------\n\n"); + /* fetch timestamp of last install. */ + + path =3D cygpath ("/etc/setup/", inst_pkg->name, ".lst.gz", NULL); + if (path) + { + if (stat (path, &st) =3D=3D 0) + install_ts =3D st.st_mtime; + free (path); + } + + /* Fake min info if installed package is not available anymore */ + if (!avail_installed) + { + ini_package_info inst_pi =3D { 0 }; + + inst_pi.name =3D inst_pkg->name; + inst_pi.sdesc =3D pi->sdesc; + inst_pi.ldesc =3D pi->ldesc; + inst_pi.url =3D pi->url; + inst_pi.license =3D pi->license; + inst_pi.curr.version =3D inst_pkg->ver; + inst_pi.curr.install_date =3D install_ts; + package_info_print (&inst_pi, &pi->curr); + } + else { - stpcpy (nvp, pi->curr.version); - if (PathMatchSpecA (nv_buf, *search)) - package_info_print (pi, &pi->curr); - else if ((cp =3D strrchr (nvp, '-'))) /* try w/o release */ + if (pi->curr.installed) { - *cp =3D '\0'; - if (PathMatchSpecA (nv_buf, *search)) - package_info_print (pi, &pi->curr); + pi->curr.install_date =3D install_ts; + package_info_print (pi, &pi->curr); } + for (size_t i =3D 0; i < pi->prev_count; ++i) + if (pi->prev[i].installed) + { + pi->prev[i].install_date =3D install_ts; + package_info_print (pi, pi->prev + i); + } + for (size_t i =3D 0; i < pi->test_count; ++i) + if (pi->test[i].installed) + { + pi->test[i].install_date =3D install_ts; + package_info_print (pi, pi->test + i); + } } - for (size_t i =3D 0; i < pi->prev_count; ++i) + } + + /* Next print available, matching packages */ + if (avail_matches) + { + if ((selector & INFO_CURR) && pi->curr.matches) { - stpcpy (nvp, pi->prev[i].version); - if (PathMatchSpecA (nv_buf, *search)) - package_info_print (pi, pi->prev + i); - else if ((cp =3D strrchr (nvp, '-'))) /* try w/o release */ - { - *cp =3D '\0'; - if (PathMatchSpecA (nv_buf, *search)) + puts ("Latest available package:\n" + "-------------------------\n"); + package_info_print (pi, &pi->curr); + } + if (selector & INFO_PREV) + { + uint32_t header_printed =3D 0; + + for (size_t i =3D 0; i < pi->prev_count; ++i) + if (pi->prev[i].matches) + { + printf ("%s", header_printed++ + ? "" + : "Older available packages:\n" + "-------------------------\n\n"); package_info_print (pi, pi->prev + i); - } + } } - for (size_t i =3D 0; i < pi->test_count; ++i) + if (selector & INFO_TEST) { - stpcpy (nvp, pi->test[i].version); - if (PathMatchSpecA (nv_buf, *search)) - package_info_print (pi, pi->test + i); - else if ((cp =3D strrchr (nvp, '-'))) /* try w/o release */ - { - *cp =3D '\0'; - if (PathMatchSpecA (nv_buf, *search)) + uint32_t header_printed =3D 0; + + for (size_t i =3D 0; i < pi->test_count; ++i) + if (pi->test[i].matches) + { + printf ("%s", header_printed++ + ? "" + : "Available test packages:\n" + "------------------------\n\n"); package_info_print (pi, pi->test + i); - } + } } } + free_pkg_info (&pi_buf); } ++search; @@ -2578,7 +2709,7 @@ Usage: cygcheck [-v] [-h] PROGRAM\n\ cygcheck -k\n\ cygcheck -f FILE [FILE]...\n\ cygcheck -l [PACKAGE]...\n\ - cygcheck -i [PATTERN]...\n\ + cygcheck -i [--inst,--curr,--prev,--test] [PATTERN]...\n\ cygcheck -e [PATTERN]...\n\ cygcheck -p REGEXP\n\ cygcheck --delete-orphaned-installation-keys\n\ @@ -2595,12 +2726,19 @@ At least one command option or a PROGRAM is require= d, as shown above.\n\ -r, --registry also scan registry for Cygwin settings (with -s)\n\ -k, --keycheck perform a keyboard check session (must be run from = a\n\ plain console only, not from a pty/rxvt/xterm)\n\ + -e, --search-package list all available packages matching PATTERN\n\ + PATTERN is a glob pattern with * and ? as wildcard = chars\n\ + -i, --info-package print full info on packages matching PATTERN, insta= lled\n\ + and available packages\n\ + PATTERN is a glob pattern with * and ? as wildcard = chars\n\ + info selection specifiers (multiple allowed):\n\ + --inst only print info on installed package\n\ + --curr only print info on most recent available package\n\ + --prev only print info on older, but still available pack= ages\n\ + --test only print info on test packages\n\ -f, --find-package find the installed package to which FILE belongs\n\ -l, --list-package list contents of the installed PACKAGE (or all\n\ installed packages if none given)\n\ - -i, --info-package print full info on packages matching PATTERN, insta= lled\n\ - and available packages\n\ - -e, --search-package list all available packages matching PATTERN\n\ -p, --package-query search for REGEXP in the entire cygwin.com package\= n\ repository (requires internet connectivity)\n\ --delete-orphaned-installation-keys\n\ @@ -2612,7 +2750,8 @@ At least one command option or a PROGRAM is required,= as shown above.\n\ with another command, otherwise print this help\n\ -V, --version print the version of cygcheck and exit\n\ \n\ -Note: -c, -f, and -l only report on packages that are currently installed.= To\n\ +Notes:\n\ + -c, -f, and -l only report on packages that are currently installed. To\= n\ search all official Cygwin packages use -p instead. The -p REGEXP match= es\n\ package names, descriptions, and names of files/paths within all package= s.\n\ \n"); @@ -2629,6 +2768,10 @@ struct option longopts[] =3D { {"find-package", no_argument, NULL, 'f'}, {"list-package", no_argument, NULL, 'l'}, {"info-packages", no_argument, NULL, 'i'}, + {"inst", no_argument, NULL, 0x1001}, + {"curr", no_argument, NULL, 0x1002}, + {"prev", no_argument, NULL, 0x1004}, + {"test", no_argument, NULL, 0x1008}, {"search-packages", no_argument, NULL, 'e'}, {"package-query", no_argument, NULL, 'p'}, {"delete-orphaned-installation-keys", no_argument, NULL, CO_DELETE_KEYS}, @@ -2763,6 +2906,12 @@ main (int argc, char **argv) case 'i': info_packages =3D 1; break; + case 0x1001: + case 0x1002: + case 0x1004: + case 0x1008: + info_selector |=3D (i & 0xf); + break; case 'e': search_packages =3D 1; break; @@ -2821,7 +2970,7 @@ main (int argc, char **argv) if (grep_packages) return package_grep (*argv); if (info_packages) - return package_info (argv); + return package_info (argv, info_selector); if (search_packages) return package_search (argv); =20 diff --git a/winsup/utils/mingw/cygcheck.h b/winsup/utils/mingw/cygcheck.h new file mode 100644 index 000000000000..fb104a8e255c --- /dev/null +++ b/winsup/utils/mingw/cygcheck.h @@ -0,0 +1,17 @@ +/* cygcheck.h + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#pragma once + +struct pkgver +{ + char *name; + char *ver; +}; + +extern pkgver *get_installed_packages (char **, size_t * =3D NULL); diff --git a/winsup/utils/mingw/dump_setup.cc b/winsup/utils/mingw/dump_set= up.cc index ec70da0db04c..06aa06f81205 100644 --- a/winsup/utils/mingw/dump_setup.cc +++ b/winsup/utils/mingw/dump_setup.cc @@ -21,6 +21,7 @@ details. */ #include #include #include "path.h" +#include "cygcheck.h" #include =20 static int package_len =3D 20; @@ -151,12 +152,6 @@ dump_file (const char *msg, const char *fn) return printed; } =20 -struct pkgver -{ - char *name; - char *ver; -}; - extern "C" { int compar (const void *a, const void *b) @@ -403,8 +398,8 @@ check_package_files (int verbose, char *package) * Returns a calloc'd sorted list of packages or NULL if no info. * The last entry in the list is {NULL,NULL}. */ -static pkgver * -get_packages (char **argv) +pkgver * +get_installed_packages (char **argv, size_t *count) { char *setup =3D cygpath ("/etc/setup/installed.db", NULL); FILE *fp =3D fopen (setup, "rt"); @@ -464,13 +459,16 @@ get_packages (char **argv) =20 fclose (fp); =20 + if (count) + *count =3D n; + return packages; } =20 void dump_setup (int verbose, char **argv, bool check_files) { - pkgver *packages =3D get_packages(argv); + pkgver *packages =3D get_installed_packages (argv); =20 puts ("Cygwin Package Information"); if (packages =3D=3D NULL) @@ -509,7 +507,7 @@ dump_setup (int verbose, char **argv, bool check_files) void package_list (int verbose, char **argv) { - pkgver *packages =3D get_packages(argv); + pkgver *packages =3D get_installed_packages (argv); if (packages =3D=3D NULL) { puts ("No setup information found"); @@ -549,7 +547,7 @@ package_list (int verbose, char **argv) void package_find (int verbose, char **argv) { - pkgver *packages =3D get_packages(NULL); + pkgver *packages =3D get_installed_packages (NULL); if (packages =3D=3D NULL) { puts ("No setup information found");