aboutsummaryrefslogtreecommitdiff
path: root/winsup/utils
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2023-01-29 14:13:25 +0100
committerCorinna Vinschen <corinna@vinschen.de>2023-01-29 14:13:25 +0100
commit022665af17d68c8e8bfe60258c69d5dc1c4f625d (patch)
treecf0109b7df670d1efa64c8e49d6ec0c6882ba3ab /winsup/utils
parent76d2053ec890884f149c8cd46dee95bde36cb95d (diff)
downloadnewlib-022665af17d68c8e8bfe60258c69d5dc1c4f625d.zip
newlib-022665af17d68c8e8bfe60258c69d5dc1c4f625d.tar.gz
newlib-022665af17d68c8e8bfe60258c69d5dc1c4f625d.tar.bz2
Cygwin: cygcheck: package info / available package search, take 2
- 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 TODO: - Human-readable filesize - url and license needs to be added to setup.ini yet - Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup/utils')
-rw-r--r--winsup/utils/mingw/cygcheck.cc313
-rw-r--r--winsup/utils/mingw/cygcheck.h17
-rw-r--r--winsup/utils/mingw/dump_setup.cc20
3 files changed, 257 insertions, 93 deletions
diff --git a/winsup/utils/mingw/cygcheck.cc b/winsup/utils/mingw/cygcheck.cc
index 4a57e9a..ed1d8f8 100644
--- a/winsup/utils/mingw/cygcheck.cc
+++ b/winsup/utils/mingw/cygcheck.cc
@@ -20,6 +20,7 @@
#include <shlwapi.h>
#include "path.h"
#include "wide_path.h"
+#include "cygcheck.h"
#include <getopt.h>
#include <cygwin/version.h>
#define cygwin_internal cygwin_internal_dontuse
@@ -53,9 +54,15 @@ int find_package = 0;
int list_package = 0;
int grep_packages = 0;
int info_packages = 0;
+int info_selector = 0;
int search_packages = 0;
int del_orphaned_reg = 0;
+#define INFO_INST 0x01
+#define INFO_CURR 0x02
+#define INFO_PREV 0x04
+#define INFO_TEST 0x08
+
static char emptystr[] = "";
#ifdef __GNUC__
@@ -2097,11 +2104,6 @@ struct passwd {
char *pw_shell; /* default shell */
};
-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;
t24h_before = time (NULL) - 24 * 60 * 60;
for (int i = 0; i < 2; ++i)
@@ -2123,22 +2123,15 @@ maybe_download_setup_ini ()
path = cygpath ("/etc/setup/setup.ini", NULL);
else
{
- BOOL ret;
- DWORD len;
- HANDLE ptok;
+ char *localappdata = getenv ("LOCALAPPDATA");
+ char *cp;
- if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok))
- return NULL;
- ret = GetTokenInformation (ptok, TokenUser, &curr_user,
- sizeof curr_user, &len);
- CloseHandle (ptok);
- if (!ret)
- return NULL;
- pw = (struct passwd *) cygwin_internal (CW_GETPWSID, FALSE,
- curr_user.psid);
- if (!pw)
+ if (!localappdata)
return NULL;
- path = cygpath (pw->pw_dir, "/.setup.ini", NULL);
+ path = (char *) malloc (strlen (localappdata)
+ + strlen ("\\.setup.ini") + 1);
+ cp = 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 = fopen (path, "w+")) != 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 = 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;
};
struct ini_package_info
@@ -2351,7 +2348,7 @@ package_info_print (ini_package_info *pi, vers_info *vers)
{
char buf[4096];
- printf ("Name : %s\n", pi->name);
+ printf ("Name : %s\n", pi->name);
if (vers->version)
{
char *version = strcpy (buf, vers->version);
@@ -2360,9 +2357,9 @@ package_info_print (ini_package_info *pi, vers_info *vers)
release = strrchr (version, '-');
if (release)
*release++ = '\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_info *vers)
*cp = '\0';
cp = 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 = strcpy (buf, pi->ldesc);
+ printf ("Description :\n%s\n", pi->ldesc);
+ puts ("");
+}
- while (ldesc)
- {
- char *nl = strchr (ldesc, '\n');
- if (nl)
- *nl = '\0';
- printf ("%s : %s\n", ldesc == buf ? "Description " : " ",
- ldesc);
- ldesc = nl ? nl + 1 : NULL;
- }
+static void
+package_info_check (ini_package_info *pi, vers_info *vi, pkgver *pv,
+ bool &am, bool &ai)
+{
+ vi->matches = true;
+ if (pv && !strcmp (vi->version, pv->ver))
+ vi->installed = true;
+ am |= vi->matches;
+ ai |= vi->installed;
+}
+
+static inline bool
+check_name_version (char *pkg_name, char *pkg_version, char *search)
+{
+ char nv_buf[4096];
+ char *nvp, *cp;
+
+ nvp = stpcpy (nv_buf, pkg_name);
+ *nvp++ = '-';
+ stpcpy (nvp, pkg_version);
+ if (PathMatchSpecA (nv_buf, search))
+ return true;
+ if ((cp = strrchr (nvp, '-'))) /* try w/o release */
+ {
+ *cp = '\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 = check_name_version (pi->name, vi->version, search);
+ if (pv && !strcmp (vi->version, pv->ver))
+ vi->installed = true;
+ am |= vi->matches;
+ ai |= vi->installed;
+}
+
+int
+pkg_comp (const void *a, const void *b)
+{
+ pkgver *pa = (pkgver *) a;
+ pkgver *pb = (pkgver *) b;
+
+ return strcmp (pa->name, pb->name);
}
/* 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 = maybe_download_setup_ini ();
ini_package_info pi_buf, *pi;
+ size_t inst_pkg_count;
+ pkgver *inst_pkgs;
if (!fp)
return 1;
+ if (selector == 0)
+ selector = INFO_CURR | INFO_PREV | INFO_TEST | INFO_INST;
+
+ inst_pkgs = get_installed_packages (NULL, &inst_pkg_count);
+
while (search && *search)
{
rewind (fp);
while ((pi = collect_pkg_info (fp, &pi_buf)))
{
+ pkgver pv = { pi->name, NULL }, *inst_pkg = NULL;
+ bool avail_installed = false;
+ bool avail_matches = false;
+ bool inst_matches = false;
+
+ if (selector & INFO_INST)
+ {
+ inst_pkg = (pkgver *) bsearch (&pv, inst_pkgs, inst_pkg_count,
+ sizeof *inst_pkgs, pkg_comp);
+ if (inst_pkg)
+ {
+ if (PathMatchSpecA (inst_pkg->name, *search))
+ inst_matches = true;
+ else
+ inst_matches = 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 = 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 = 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 = 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 = 0; i < pi->test_count; ++i)
+ package_info_vers_check (pi, pi->test + i, *search, inst_pkg,
+ avail_matches, avail_installed);
+ }
- nvp = stpcpy (nv_buf, pi->name);
- *nvp++ = '-';
+ /* First print installed package(s) */
+ if (inst_pkg && inst_matches)
+ {
+ time_t install_ts = 0;
+ struct stat st;
+ char *path;
- if (pi->curr.version)
+ printf ("Installed package:\n"
+ "------------------\n\n");
+ /* fetch timestamp of last install. */
+
+ path = cygpath ("/etc/setup/", inst_pkg->name, ".lst.gz", NULL);
+ if (path)
+ {
+ if (stat (path, &st) == 0)
+ install_ts = st.st_mtime;
+ free (path);
+ }
+
+ /* Fake min info if installed package is not available anymore */
+ if (!avail_installed)
+ {
+ ini_package_info inst_pi = { 0 };
+
+ inst_pi.name = inst_pkg->name;
+ inst_pi.sdesc = pi->sdesc;
+ inst_pi.ldesc = pi->ldesc;
+ inst_pi.url = pi->url;
+ inst_pi.license = pi->license;
+ inst_pi.curr.version = inst_pkg->ver;
+ inst_pi.curr.install_date = 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 = strrchr (nvp, '-'))) /* try w/o release */
+ if (pi->curr.installed)
{
- *cp = '\0';
- if (PathMatchSpecA (nv_buf, *search))
- package_info_print (pi, &pi->curr);
+ pi->curr.install_date = install_ts;
+ package_info_print (pi, &pi->curr);
}
+ for (size_t i = 0; i < pi->prev_count; ++i)
+ if (pi->prev[i].installed)
+ {
+ pi->prev[i].install_date = install_ts;
+ package_info_print (pi, pi->prev + i);
+ }
+ for (size_t i = 0; i < pi->test_count; ++i)
+ if (pi->test[i].installed)
+ {
+ pi->test[i].install_date = install_ts;
+ package_info_print (pi, pi->test + i);
+ }
}
- for (size_t i = 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 = strrchr (nvp, '-'))) /* try w/o release */
- {
- *cp = '\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 = 0;
+
+ for (size_t i = 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 = 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 = strrchr (nvp, '-'))) /* try w/o release */
- {
- *cp = '\0';
- if (PathMatchSpecA (nv_buf, *search))
+ uint32_t header_printed = 0;
+
+ for (size_t i = 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 required, 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, installed\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 packages\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, installed\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 matches\n\
package names, descriptions, and names of files/paths within all packages.\n\
\n");
@@ -2629,6 +2768,10 @@ struct option longopts[] = {
{"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 = 1;
break;
+ case 0x1001:
+ case 0x1002:
+ case 0x1004:
+ case 0x1008:
+ info_selector |= (i & 0xf);
+ break;
case 'e':
search_packages = 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);
diff --git a/winsup/utils/mingw/cygcheck.h b/winsup/utils/mingw/cygcheck.h
new file mode 100644
index 0000000..fb104a8
--- /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 * = NULL);
diff --git a/winsup/utils/mingw/dump_setup.cc b/winsup/utils/mingw/dump_setup.cc
index ec70da0..06aa06f 100644
--- a/winsup/utils/mingw/dump_setup.cc
+++ b/winsup/utils/mingw/dump_setup.cc
@@ -21,6 +21,7 @@ details. */
#include <winternl.h>
#include <ntstatus.h>
#include "path.h"
+#include "cygcheck.h"
#include <zlib.h>
static int package_len = 20;
@@ -151,12 +152,6 @@ dump_file (const char *msg, const char *fn)
return printed;
}
-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 = cygpath ("/etc/setup/installed.db", NULL);
FILE *fp = fopen (setup, "rt");
@@ -464,13 +459,16 @@ get_packages (char **argv)
fclose (fp);
+ if (count)
+ *count = n;
+
return packages;
}
void
dump_setup (int verbose, char **argv, bool check_files)
{
- pkgver *packages = get_packages(argv);
+ pkgver *packages = get_installed_packages (argv);
puts ("Cygwin Package Information");
if (packages == NULL)
@@ -509,7 +507,7 @@ dump_setup (int verbose, char **argv, bool check_files)
void
package_list (int verbose, char **argv)
{
- pkgver *packages = get_packages(argv);
+ pkgver *packages = get_installed_packages (argv);
if (packages == 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 = get_packages(NULL);
+ pkgver *packages = get_installed_packages (NULL);
if (packages == NULL)
{
puts ("No setup information found");