From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id BDA263858D38; Sat, 28 Jan 2023 14:00:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BDA263858D38 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674914407; bh=q5Ndf+SvNHAD0nIUwcFBY72rpkqxfkjDyNJY1xEWmWI=; h=From:To:Subject:Date:From; b=cwieLJvUwDYzg8KbS9V40ZR/d4odft3cbF9dzoU7aDrK8C/FM1IXjTINSbMRYsb4V n1xrOBbfCcZ7WCOPa5/uWOLdIClZcXcB9NIFBu7J2TK/+AkTsC5N7tZqnzYmdyVjEZ D7gh96EU9wCVGblESEYnmRwYQ2FDMS3xfADw/Z8k= 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 1 X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/main X-Git-Oldrev: 963d6c79ead3941b399e3549bc753c2cb90ab79b X-Git-Newrev: 76d2053ec890884f149c8cd46dee95bde36cb95d Message-Id: <20230128140007.BDA263858D38@sourceware.org> Date: Sat, 28 Jan 2023 14:00:07 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D76d2053ec89= 0884f149c8cd46dee95bde36cb95d commit 76d2053ec890884f149c8cd46dee95bde36cb95d Author: Corinna Vinschen AuthorDate: Sat Jan 28 14:59:39 2023 +0100 Commit: Corinna Vinschen CommitDate: Sat Jan 28 14:59:39 2023 +0100 Cygwin: cygcheck: package info / available package search, take 1 =20 cygcheck -i =3D=3D dnf info cygcheck -e =3D=3D dnf search =20 Signed-off-by: Corinna Vinschen Diff: --- winsup/utils/mingw/Makefile.am | 2 +- winsup/utils/mingw/cygcheck.cc | 519 +++++++++++++++++++++++++++++++++++++= ++-- 2 files changed, 503 insertions(+), 18 deletions(-) diff --git a/winsup/utils/mingw/Makefile.am b/winsup/utils/mingw/Makefile.am index c26eef80f8c0..d9557d8b5029 100644 --- a/winsup/utils/mingw/Makefile.am +++ b/winsup/utils/mingw/Makefile.am @@ -33,7 +33,7 @@ cygcheck_SOURCES =3D \ path.cc cygcheck_CPPFLAGS=3D-I$(srcdir)/.. -idirafter ${top_srcdir}/cygwin/include cygcheck_LDFLAGS =3D ${AM_LDFLAGS} -Wl,--disable-high-entropy-va -cygcheck_LDADD =3D -lz -lwininet -lpsapi -lntdll +cygcheck_LDADD =3D -lz -lwininet -lshlwapi -lpsapi -lntdll =20 cygwin_console_helper_SOURCES =3D cygwin-console-helper.cc =20 diff --git a/winsup/utils/mingw/cygcheck.cc b/winsup/utils/mingw/cygcheck.cc index ce97cfe3a862..4a57e9a7b910 100644 --- a/winsup/utils/mingw/cygcheck.cc +++ b/winsup/utils/mingw/cygcheck.cc @@ -6,25 +6,27 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ =20 -#define cygwin_internal cygwin_internal_dontuse #include #include #include #include #include +#include #include #include #include #include #include +#include #include "path.h" #include "wide_path.h" #include #include +#define cygwin_internal cygwin_internal_dontuse #include +#undef cygwin_internal #define _NOMNTENT_MACROS #include -#undef cygwin_internal #include "loadlib.h" =20 #ifndef max @@ -35,6 +37,11 @@ #define alloca __builtin_alloca #endif =20 +extern "C" { +uintptr_t (*cygwin_internal) (cygwin_getinfo_types, ...); +WCHAR cygwin_dll_path[32768]; +}; + int verbose =3D 0; int registry =3D 0; int sysinfo =3D 0; @@ -45,6 +52,8 @@ int dump_only =3D 0; int find_package =3D 0; int list_package =3D 0; int grep_packages =3D 0; +int info_packages =3D 0; +int search_packages =3D 0; int del_orphaned_reg =3D 0; =20 static char emptystr[] =3D ""; @@ -238,6 +247,14 @@ display_internet_error (const char *message, ...) return 1; } =20 +static inline char * +stpcpy (char *d, const char *s) +{ + while ((*d++ =3D *s++)) + ; + return --d; +} + static void add_path (char *s, int maxlen, bool issys) { @@ -2069,10 +2086,462 @@ fetch_url (const char *url, FILE *outstream) return 0; } =20 +struct passwd { + char *pw_name; /* user name */ + char *pw_passwd; /* encrypted password */ + uint32_t pw_uid; /* user uid */ + uint32_t pw_gid; /* user gid */ + char *pw_comment; /* comment */ + char *pw_gecos; /* Honeywell login info */ + char *pw_dir; /* home directory */ + 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 * +maybe_download_setup_ini () +{ + time_t t24h_before; + char *path; + struct stat st; + FILE *fp; + struct passwd *pw; + sidbuf curr_user; + + t24h_before =3D time (NULL) - 24 * 60 * 60; + for (int i =3D 0; i < 2; ++i) + { + /* Check for the system-wide setup.ini file first. If that's too + old and not writable, check for ~/.setup.ini. */ + if (i =3D=3D 0) + path =3D cygpath ("/etc/setup/setup.ini", NULL); + else + { + BOOL ret; + DWORD len; + HANDLE ptok; + + 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) + return NULL; + path =3D cygpath (pw->pw_dir, "/.setup.ini", NULL); + } + /* If file exists, and has been downloaded less than 24h ago, + and if we can open it for reading, just use it. */ + if (stat (path, &st) =3D=3D 0 + && st.st_mtime > t24h_before + && (fp =3D fopen (path, "rt")) !=3D NULL) + return fp; + /* 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); + if (!fetch_url ("https://cygwin.com/ftp/cygwin/x86_64/setup.ini", fp)) + { + fclose (fp); + fp =3D fopen (path, "rt"); + return fp; + } + fclose (fp); + } + } + return NULL; +} + +struct vers_info +{ + char *version; + char *install; + char *source; + char *depends2; +}; + +struct ini_package_info +{ + char *name; + char *sdesc; + char *ldesc; + char *category; + char *url; + char *license; + vers_info curr; + size_t prev_count; + vers_info *prev; + size_t test_count; + vers_info *test; +}; + +static void +free_pkg_info (ini_package_info *pi) +{ + free (pi->name); + free (pi->sdesc); + free (pi->ldesc); + free (pi->category); + free (pi->url); + free (pi->license); + free (pi->curr.version); + free (pi->curr.install); + free (pi->curr.source); + free (pi->curr.depends2); + if (pi->prev) + { + for (size_t i =3D 0; i < pi->prev_count; ++i) + { + free (pi->prev[i].version); + free (pi->prev[i].install); + free (pi->prev[i].source); + free (pi->prev[i].depends2); + } + free (pi->prev); + } + if (pi->test) + { + for (size_t i =3D 0; i < pi->test_count; ++i) + { + free (pi->test[i].version); + free (pi->test[i].install); + free (pi->test[i].source); + free (pi->test[i].depends2); + } + free (pi->test); + } +} + +static void +collect_quoted_string (char *&tgt, FILE *fp, char *buf, size_t size, size_= t offset) +{ + bool found =3D false; + char *cp, *s; + + cp =3D buf + offset; + if (*cp !=3D '"') /* just 'til end of line */ + { + if ((s =3D strchr (cp, '\n'))) + *s =3D '\0'; + tgt =3D strdup (cp); + return; + } + /* text starts with a quote, collect 'til the closing quote */ + ++cp; + do + { + if ((s =3D strrchr (cp, '"')) && (s =3D=3D cp || s[-1] !=3D '\\')) + { + *s =3D '\0'; + found =3D true; + } + if (!tgt) + s =3D (char *) calloc (strlen (cp) + 1, sizeof *s); + else + s =3D (char *) realloc (tgt, strlen (tgt) + strlen (cp) + 1); + if (s) + { + tgt =3D s; + strcat (tgt, cp); + } + } + while (!found && (cp =3D fgets (buf, size, fp))); +} + +static ini_package_info * +collect_pkg_info (FILE *fp, ini_package_info *pi) +{ + vers_info *vinfo =3D &pi->curr; + char buf[4096]; + char *s; + + memset (pi, 0, sizeof *pi); + /* Search next line starting with "@ ". */ + while ((s =3D fgets (buf, sizeof buf, fp))) + { + if (s[0] =3D=3D '@' && s[1] =3D=3D ' ') + break; + } + if (!s) + goto error; + /* Extract package name */ + if ((s =3D strchr (buf, '\n'))) + *s =3D '\0'; + pi->name =3D strdup (buf + 2); + /* collect all of this package block. */ + while ((s =3D fgets (buf, sizeof buf, fp))) + { + /* empty line? EOR. */ + if (s[0] =3D=3D '\n') + break; + /* prev or test version? */ + if (buf[0] =3D=3D '[') + { + vers_info **vers_p =3D NULL; + size_t *vers_cnt_p =3D NULL; + + if (!strncmp (buf, "[prev]", strlen ("[prev]"))) + { + vers_p =3D &pi->prev; + vers_cnt_p =3D &pi->prev_count; + } + else if (!strncmp (buf, "[test]", strlen ("[test]"))) + { + vers_p =3D &pi->test; + vers_cnt_p =3D &pi->test_count; + } + if (vers_p) + { + vers_info *v; + + v =3D (vers_info *) realloc (*vers_p, (*vers_cnt_p + 1) + * sizeof (vers_info)); + if (!v) + goto error; + *vers_p =3D v; + vinfo =3D *vers_p + *vers_cnt_p; + memset (vinfo, 0, sizeof *vinfo); + ++(*vers_cnt_p); + } + } + else if (!strncmp (buf, "sdesc: ", strlen ("sdesc: "))) + collect_quoted_string (pi->sdesc, fp, buf, sizeof buf, + strlen ("sdesc: ")); + else if (!strncmp (buf, "ldesc: ", strlen ("ldesc: "))) + collect_quoted_string (pi->ldesc, fp, buf, sizeof buf, + strlen ("ldesc: ")); + else + { + if ((s =3D strchr (buf, '\n'))) + *s =3D '\0'; + if (!strncmp (buf, "category: ", strlen ("category: "))) + pi->category =3D strdup (buf + strlen ("category: ")); + else if (!strncmp (buf, "url: ", strlen ("url: "))) + pi->url =3D strdup (buf + strlen ("url: ")); + else if (!strncmp (buf, "license: ", strlen ("license: "))) + pi->license =3D strdup (buf + strlen ("license: ")); + else if (!strncmp (buf, "version: ", strlen ("version: "))) + vinfo->version =3D strdup (buf + strlen ("version: ")); + else if (!strncmp (buf, "install: ", strlen ("install: "))) + vinfo->install =3D strdup (buf + strlen ("install: ")); + else if (!strncmp (buf, "source: ", strlen ("source: "))) + vinfo->source =3D strdup (buf + strlen ("source: ")); + else if (!strncmp (buf, "depends2: ", strlen ("depends2: "))) + vinfo->depends2 =3D strdup (buf + strlen ("depends2: ")); + } + } + return pi; +error: + free_pkg_info (pi); + return NULL; +} + +static void +package_info_print (ini_package_info *pi, vers_info *vers) +{ + char buf[4096]; + + printf ("Name : %s\n", pi->name); + if (vers->version) + { + char *version =3D strcpy (buf, vers->version); + char *release =3D NULL; + + release =3D strrchr (version, '-'); + if (release) + *release++ =3D '\0'; + printf ("Version : %s\n", version); + if (release) + printf ("Release : %s\n", release); + } + if (vers->install) + { + char *arch =3D strcpy (buf, vers->install); + char *size =3D NULL; + char *cp; + + cp =3D strchr (arch, '/'); + if (cp) + { + *cp++ =3D '\0'; + cp =3D strchr (cp, ' '); + if (cp) + { + size =3D ++cp; + cp =3D strchr (cp, ' '); + if (cp) + *cp =3D '\0'; + } + } + if (cp) + { + printf ("Architecture : %s\n", arch); + printf ("Size : %s\n", size); /* FIXME: human-readable */ + } + } + if (vers->source) + { + char *source =3D strcpy (buf, vers->source); + char *cp =3D strchr (source, ' '); + if (cp) + { + *cp =3D '\0'; + cp =3D strrchr (source, '/'); + if (cp) + printf ("Source : %s\n", cp + 1); + } + } + if (pi->sdesc) + printf ("Summary : %s\n", pi->sdesc); + if (pi->url) + printf ("Url : %s\n", pi->url); + if (pi->license) + printf ("License : %s\n", pi->license); + if (pi->ldesc) + { + char *ldesc =3D strcpy (buf, pi->ldesc); + + 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; + } + } + puts (""); +} + +/* Print full info for the package matching the search string in terms of + name/version. */ +static int +package_info (char **search) +{ + FILE *fp =3D maybe_download_setup_ini (); + ini_package_info pi_buf, *pi; + + if (!fp) + return 1; + + while (search && *search) + { + rewind (fp); + while ((pi =3D collect_pkg_info (fp, &pi_buf))) + { + /* Name matches? Print all versions */ + if (PathMatchSpecA (pi->name, *search)) + { + if (pi->curr.version) + package_info_print (pi, &pi->curr); + for (size_t i =3D 0; i < pi->prev_count; ++i) + package_info_print (pi, pi->prev + i); + for (size_t i =3D 0; i < pi->test_count; ++i) + package_info_print (pi, pi->test + i); + } + else + { + /* Check if search matches name-version string */ + char nv_buf[4096], *nvp, *cp; + + nvp =3D stpcpy (nv_buf, pi->name); + *nvp++ =3D '-'; + + if (pi->curr.version) + { + 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 */ + { + *cp =3D '\0'; + if (PathMatchSpecA (nv_buf, *search)) + package_info_print (pi, &pi->curr); + } + } + for (size_t i =3D 0; i < pi->prev_count; ++i) + { + 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)) + package_info_print (pi, pi->prev + i); + } + } + for (size_t i =3D 0; i < pi->test_count; ++i) + { + 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)) + package_info_print (pi, pi->test + i); + } + } + } + free_pkg_info (&pi_buf); + } + ++search; + } + return 0; +} + +/* Search for the search string in name and sdesc of available packages. */ +static int +package_search (char **search) +{ + FILE *fp =3D maybe_download_setup_ini (); + ini_package_info pi_buf, *pi; + char *ext_search, *ep; + + if (!fp) + return 1; + + while (search && *search) + { + ext_search =3D (char *) malloc (strlen (*search) + 3); + ep =3D ext_search; + if (*(search)[0] !=3D '*') + *ep++ =3D '*'; + ep =3D stpcpy (ep, *search); + if (ep[-1] !=3D '*') + stpcpy (ep, "*"); + + rewind (fp); + while ((pi =3D collect_pkg_info (fp, &pi_buf))) + { + if (PathMatchSpecA (pi->name, ext_search) + || (pi->sdesc && PathMatchSpecA (pi->sdesc, ext_search))) + printf ("%s : %s\n", pi->name, pi->sdesc); + free_pkg_info (&pi_buf); + } + free (ext_search); + ++search; + } + + return 0; +} + /* Queries Cygwin web site for packages containing files matching a regexp. Return value is 1 if there was a problem, otherwise 0. */ static int -package_grep (char *search) +package_grep (const char *search) { /* construct the actual URL by escaping */ char *url =3D (char *) alloca (sizeof (grep_base_url) + strlen (ARCH_str) @@ -2109,6 +2578,8 @@ Usage: cygcheck [-v] [-h] PROGRAM\n\ cygcheck -k\n\ cygcheck -f FILE [FILE]...\n\ cygcheck -l [PACKAGE]...\n\ + cygcheck -i [PATTERN]...\n\ + cygcheck -e [PATTERN]...\n\ cygcheck -p REGEXP\n\ cygcheck --delete-orphaned-installation-keys\n\ cygcheck -h\n\n\ @@ -2124,8 +2595,12 @@ 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\ - -f, --find-package find the package to which FILE belongs\n\ - -l, --list-package list contents of PACKAGE (or all packages if none g= iven)\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\ @@ -2153,6 +2628,8 @@ struct option longopts[] =3D { {"keycheck", no_argument, NULL, 'k'}, {"find-package", no_argument, NULL, 'f'}, {"list-package", no_argument, NULL, 'l'}, + {"info-packages", no_argument, NULL, 'i'}, + {"search-packages", no_argument, NULL, 'e'}, {"package-query", no_argument, NULL, 'p'}, {"delete-orphaned-installation-keys", no_argument, NULL, CO_DELETE_KEYS}, {"help", no_argument, NULL, 'h'}, @@ -2160,7 +2637,7 @@ struct option longopts[] =3D { {0, no_argument, NULL, 0} }; =20 -static char opts[] =3D "cdsrvkflphV"; +static char opts[] =3D "cdsrvkfliephV"; =20 static void print_version () @@ -2188,11 +2665,6 @@ nuke (char *ev) putenv (s); } =20 -extern "C" { -uintptr_t (*cygwin_internal) (int, ...); -WCHAR cygwin_dll_path[32768]; -}; - static void load_cygwin (int& argc, char **&argv) { @@ -2201,8 +2673,8 @@ load_cygwin (int& argc, char **&argv) if (!(h =3D LoadLibrary ("cygwin1.dll"))) return; GetModuleFileNameW (h, cygwin_dll_path, 32768); - if ((cygwin_internal =3D (uintptr_t (*) (int, ...)) - GetProcAddress (h, "cygwin_internal"))) + if ((cygwin_internal =3D (uintptr_t (*) (cygwin_getinfo_types, ...)) + GetProcAddress (h, "cygwin_internal"))) { char **av =3D (char **) cygwin_internal (CW_ARGV); if (av && ((uintptr_t) av !=3D (uintptr_t) -1)) @@ -2239,6 +2711,7 @@ load_cygwin (int& argc, char **&argv) putenv (path); } } + /* GDB chokes when the DLL got unloaded and, for some reason, fails to s= et any breakpoint after the fact. */ if (!IsDebuggerPresent ()) @@ -2287,6 +2760,12 @@ main (int argc, char **argv) case 'l': list_package =3D 1; break; + case 'i': + info_packages =3D 1; + break; + case 'e': + search_packages =3D 1; + break; case 'p': grep_packages =3D 1; break; @@ -2310,7 +2789,7 @@ main (int argc, char **argv) putenv ("POSIXLY_CORRECT=3D"); =20 if ((argc =3D=3D 0) && !sysinfo && !keycheck && !check_setup && !list_pa= ckage - && !del_orphaned_reg) + && !del_orphaned_reg && !info_packages && !search_packages) { if (givehelp) usage (stdout, 0); @@ -2319,18 +2798,20 @@ main (int argc, char **argv) } =20 if ((check_setup || sysinfo || find_package || list_package || grep_pack= ages - || del_orphaned_reg) + || del_orphaned_reg || info_packages || search_packages) && keycheck) usage (stderr, 1); =20 - if ((find_package || list_package || grep_packages) + if ((find_package || list_package || grep_packages + || info_packages || search_packages) && (check_setup || del_orphaned_reg)) usage (stderr, 1); =20 if (dump_only && !check_setup && !sysinfo) usage (stderr, 1); =20 - if (find_package + list_package + grep_packages > 1) + if (find_package + list_package + grep_packages + + info_packages + search_packages > 1) usage (stderr, 1); =20 if (keycheck) @@ -2339,6 +2820,10 @@ main (int argc, char **argv) del_orphaned_reg_installations (); if (grep_packages) return package_grep (*argv); + if (info_packages) + return package_info (argv); + if (search_packages) + return package_search (argv); =20 init_paths ();