From 2fac517df43d7d8de14bd2c7ef4b944ffb507960 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sun, 11 Nov 2001 03:06:59 +0000 Subject: [PATCH] * Makefile.in (cygcheck.exe): Compile as -mno-cygwin executable. * path.cc: New file. * cygcheck.cc (init_paths): Use MS-DOS path syntax. (cygwin_info): Properly display cygwin version numbers. Prettify some output. (dump_sysinfo): Calculate max names of posix and ms-dos paths for prettier output. --- winsup/utils/ChangeLog | 10 ++ winsup/utils/Makefile.in | 16 ++ winsup/utils/cygcheck.cc | 60 +++++-- winsup/utils/path.cc | 350 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 423 insertions(+), 13 deletions(-) create mode 100644 winsup/utils/path.cc diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 56db805b8..960282da3 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,13 @@ +2001-11-10 Christopher Faylor + + * Makefile.in (cygcheck.exe): Compile as -mno-cygwin executable. + * path.cc: New file. + * cygcheck.cc (init_paths): Use MS-DOS path syntax. + (cygwin_info): Properly display cygwin version numbers. Prettify some + output. + (dump_sysinfo): Calculate max names of posix and ms-dos paths for + prettier output. + 2001-11-09 Corinna Vinschen * cygcheck.cc (dump_sysinfo): Print more detailed OS information string. diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in index deee3bdc9..7becee829 100644 --- a/winsup/utils/Makefile.in +++ b/winsup/utils/Makefile.in @@ -94,6 +94,14 @@ else $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) endif +cygcheck.exe: cygcheck.cc mingw_getopt.o path.o $(MINGW_DEP_LDLIBS) +ifdef VERBOSE + $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) +else + @echo $(CXX) -o $@ ${wordlist 1,2,$^} ${filter-out -B%, $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS)};\ + $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) +endif + dumper.o: dumper.cc dumper.h ifdef VERBOSE ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $@ $(DUMPER_INCLUDES) ${firstword $^} @@ -127,6 +135,14 @@ else ${filter-out -I$(newlib_source)/%,$(COMPILE_CC)} $c -o $(@D)/$(basename $@)$o $(MINGW_CFLAGS) $< endif +path.o: path.cc +ifdef VERBOSE + ${filter-out -I$(newlib_source)/%,$(COMPILE_CC)} $c -o $(@D)/$(basename $@)$o $(MINGW_CFLAGS) $< +else + @echo $(CC) $c -o $(@D)/$(basename $@)$o $(MINGW_CFLAGS) ... $^;\ + ${filter-out -I$(newlib_source)/%,$(COMPILE_CC)} $c -o $(@D)/$(basename $@)$o $(MINGW_CFLAGS) $< +endif + clean: rm -f *.o $(CLEAN_PROGS) diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc index 11a04d467..0f905a956 100644 --- a/winsup/utils/cygcheck.cc +++ b/winsup/utils/cygcheck.cc @@ -8,6 +8,8 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ +typedef unsigned short uid_t; +typedef unsigned short gid_t; #include #include #include @@ -16,6 +18,7 @@ #include #include #include +#include int verbose = 0; int registry = 0; @@ -134,18 +137,14 @@ init_paths () GetWindowsDirectory (tmp, 4000); add_path (tmp, strlen (tmp)); - char *path = getenv ("PATH"); - if (path) + char *wpath = getenv ("PATH"); + if (wpath) { - char wpath[4000]; - cygwin_posix_to_win32_path_list (path, wpath); - char *b, *e, sep = ':'; - if (strchr (wpath, ';')) - sep = ';'; + char *b, *e; b = wpath; while (1) { - for (e = b; *e && *e != sep; e++); + for (e = b; *e && *e != ';'; e++); add_path (b, e - b); if (!*e) break; @@ -350,6 +349,7 @@ cygwin_info (HANDLE h) return; } + char *dll_major; bufend = buf + size; while (buf < bufend) if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL) @@ -361,9 +361,33 @@ cygwin_info (HANDLE h) char *p = strchr (buf += CYGPREFIX, '\n'); if (!p) break; - fputs (hello, stdout); - fputs (" ", stdout); - fwrite (buf, 1 + p - buf, 1, stdout); + if (strncasecmp (buf, "dll major:", 10) == 0) + { + dll_major = buf + 11; + continue; + } + char *s, pbuf[80]; + int len; + len = 1 + p - buf; + if (strncasecmp (buf, "dll minor:", 10) != 0) + s = buf; + else + { + char c = dll_major[1]; + dll_major[1] = '\0'; + int maj = atoi (dll_major); + dll_major[1] = c; + int min = atoi (dll_major + 1); + sprintf (pbuf, "DLL version: %d.%d.%.*s", maj, min, len - 11, buf + 11); + len = strlen (s = pbuf); + } + if (strncmp (s, "dll", 3) == 0) + memcpy (s, "DLL", 3); + else if (strncmp (s, "api", 3) == 0) + memcpy (s, "API", 3); + else if (islower (*s)) + *s = toupper (*s); + fprintf (stdout, "%s %.*s", hello, len, s); hello = ""; } @@ -987,6 +1011,18 @@ dump_sysinfo () unsigned int ml_fsname = 4, ml_dir = 7, ml_type = 6; + struct mntent *mnt; + setmntent (0, 0); + while ((mnt = getmntent (0))) + { + int n = (int) strlen (mnt->mnt_fsname); + if (ml_fsname < n) + ml_fsname = n; + n = (int) strlen (mnt->mnt_dir); + if (ml_dir < n) + ml_dir = n; + } + if (givehelp) { printf @@ -995,9 +1031,7 @@ dump_sysinfo () ml_type, "-Type-", "-Flags-"); } - struct mntent *mnt; setmntent (0, 0); - while ((mnt = getmntent (0))) { printf ("%-*s %-*s %-*s %s\n", diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc new file mode 100644 index 000000000..7670904c8 --- /dev/null +++ b/winsup/utils/path.cc @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2000, Red Hat, Inc. + * + * This program 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. + * + * A copy of the GNU General Public License can be found at + * http://www.gnu.org/ + * + * Written by DJ Delorie + * + */ + +/* The purpose of this file is to hide all the details about accessing + Cygwin's mount table. If the format or location of the mount table + changes, this is the file to change to match it. */ + +#include +#include +#include +#include +#include +#include + +/* Used when treating / and \ as equivalent. */ +#define SLASH_P(ch) \ + ({ \ + char __c = (ch); \ + ((__c) == '/' || (__c) == '\\'); \ + }) + + +static struct mnt + { + const char *native; + char *posix; + unsigned flags; + int issys; + } mount_table[255]; + +struct mnt *root_here = NULL; + +static char * +find2 (HKEY rkey, unsigned *flags, char *what) +{ + char *retval = 0; + DWORD retvallen = 0; + DWORD type; + HKEY key; + + if (RegOpenKeyEx (rkey, what, 0, KEY_READ, &key) != ERROR_SUCCESS) + return 0; + + if (RegQueryValueEx (key, "native", 0, &type, 0, &retvallen) + == ERROR_SUCCESS) + { + retval = (char *) malloc (MAX_PATH + 1); + if (RegQueryValueEx (key, "native", 0, &type, (BYTE *) retval, &retvallen) + != ERROR_SUCCESS) + { + free (retval); + retval = 0; + } + } + + retvallen = sizeof (flags); + RegQueryValueEx (key, "flags", 0, &type, (BYTE *)flags, &retvallen); + + RegCloseKey (key); + + return retval; +} + +static LONG +get_cygdrive0 (HKEY key, const char *what, void *val, DWORD len) +{ + LONG status = RegQueryValueEx (key, what, 0, 0, (BYTE *)val, &len); + return status; +} + +static mnt * +get_cygdrive (HKEY key, mnt *m, int issystem) +{ + + if (get_cygdrive0 (key, CYGWIN_INFO_CYGDRIVE_FLAGS, &m->flags, + sizeof (m->flags)) != ERROR_SUCCESS) { + free (m->posix); + return m; + } + get_cygdrive0 (key, CYGWIN_INFO_CYGDRIVE_PREFIX, m->posix, MAX_PATH); + m->native = strdup ("."); + return m + 1; +} + +void +read_mounts () +{ + DWORD posix_path_size; + int res; + struct mnt *m = mount_table; + DWORD disposition; + char buf[10000]; + + root_here = NULL; + for (mnt *m1 = mount_table; m1->posix; m1++) + { + free (m1->posix); + if (m1->native) + free ((char *) m1->native); + m1->posix = NULL; + } + + /* Loop through subkeys */ + /* FIXME: we would like to not check MAX_MOUNTS but the heap in the + shared area is currently statically allocated so we can't have an + arbitrarily large number of mounts. */ + for (int issystem = 0; issystem <= 1; issystem++) + { + sprintf (buf, "Software\\%s\\%s\\%s", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME); + + HKEY key = issystem ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + if (RegCreateKeyEx (key, buf, 0, (LPTSTR) "Cygwin", 0, KEY_ALL_ACCESS, + 0, &key, &disposition) != ERROR_SUCCESS) + break; + for (int i = 0; ;i++, m++) + { + m->posix = (char *) malloc (MAX_PATH + 1); + posix_path_size = MAX_PATH; + /* FIXME: if maximum posix_path_size is 256, we're going to + run into problems if we ever try to store a mount point that's + over 256 but is under MAX_PATH. */ + res = RegEnumKeyEx (key, i, m->posix, &posix_path_size, NULL, + NULL, NULL, NULL); + + if (res == ERROR_NO_MORE_ITEMS) + { + m = get_cygdrive (key, m, issystem); + m->posix = NULL; + break; + } + + if (!*m->posix) + goto no_go; + else if (res != ERROR_SUCCESS) + break; + else + { + m->native = find2 (key, &m->flags, m->posix); + m->issys = issystem; + if (!m->native) + goto no_go; + } + continue; + no_go: + free (m->posix); + m->posix = NULL; + m--; + } + RegCloseKey (key); + } +} + +/* Return non-zero if PATH1 is a prefix of PATH2. + Both are assumed to be of the same path style and / vs \ usage. + Neither may be "". + LEN1 = strlen (PATH1). It's passed because often it's already known. + + Examples: + /foo/ is a prefix of /foo <-- may seem odd, but desired + /foo is a prefix of /foo/ + / is a prefix of /foo/bar + / is not a prefix of foo/bar + foo/ is a prefix foo/bar + /foo is not a prefix of /foobar +*/ + +static int +path_prefix_p (const char *path1, const char *path2, int len1) +{ + /* Handle case where PATH1 has trailing '/' and when it doesn't. */ + if (len1 > 0 && SLASH_P (path1[len1 - 1])) + len1--; + + if (len1 == 0) + return SLASH_P (path2[0]) && !SLASH_P (path2[1]); + + if (strncasecmp (path1, path2, len1) != 0) + return 0; + + return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':'; +} + +static char * +vconcat (const char *s, va_list v) +{ + int len; + char *rv, *arg; + va_list save_v = v; + int unc; + + if (!s) + return 0; + + len = strlen (s); + + unc = SLASH_P (*s) && SLASH_P (s[1]); + + while (1) + { + arg = va_arg (v, char *); + if (arg == 0) + break; + len += strlen (arg); + } + va_end (v); + + rv = (char *) malloc (len + 1); + strcpy (rv, s); + v = save_v; + while (1) + { + arg = va_arg (v, char *); + if (arg == 0) + break; + strcat (rv, arg); + } + va_end (v); + + char *d, *p; + for (p = rv; *p; p++) + if (*p == '\\') + *p = '/'; + + /* concat is only used for urls and files, so we can safely + canonicalize the results */ + for (p = d = rv; *p; p++) + { + *d++ = *p; + /* special case for URLs */ + if (*p == ':' && p[1] == '/' && p[2] == '/' && p > rv + 1) + { + *d++ = *++p; + *d++ = *++p; + } + else if (*p == '/' || *p == '\\') + { + if (p == rv && unc) + p++; + while (p[1] == '/') + p++; + } + } + *d = 0; + + return rv; +} + +static char * +concat (const char *s, ...) +{ + va_list v; + + va_start (v, s); + + return vconcat (s, v); +} + +char * +cygpath (const char *s, ...) +{ + va_list v; + int max_len = -1; + struct mnt *m, *match = NULL; + + va_start (v, s); + char *path = vconcat (s, v); + if (strncmp (path, "./", 2) == 0) + memmove (path, path + 2, strlen (path + 2) + 1); + if (strncmp (path, "/./", 3) == 0) + memmove (path + 1, path + 3, strlen (path + 3) + 1); + + for (m = mount_table; m->posix ; m++) + { + int n = strlen (m->posix); + if (n < max_len || !path_prefix_p (m->posix, path, n)) + continue; + max_len = n; + match = m; + } + + char *native; + if (match == NULL) + native = strdup (path); + else if (max_len == (int) strlen (path)) + native = strdup (match->native); + else + native = concat (match->native, "/", path + max_len, NULL); + free (path); + + return native; +} + +static mnt *m = NULL; + +extern "C" FILE * +setmntent (const char *, const char *) +{ + m = mount_table; + if (!m->posix) + read_mounts (); + return NULL; +} + +extern "C" struct mntent * +getmntent (FILE *) +{ + static mntent mnt; + if (!m->posix) + return NULL; + + mnt.mnt_fsname = (char *) m->native; + mnt.mnt_dir = (char *) m->posix; + if (!mnt.mnt_type) + mnt.mnt_type = (char *) malloc (1024); + if (!mnt.mnt_opts) + mnt.mnt_opts = (char *) malloc (1024); + if (!m->issys) + strcpy (mnt.mnt_type, (char *) "user"); + else + strcpy (mnt.mnt_type, (char *) "system"); + if (!(m->flags & MOUNT_BINARY)) + strcpy (mnt.mnt_opts, (char *) "textmode"); + else + strcpy (mnt.mnt_opts, (char *) "binmode"); + if (m->flags & MOUNT_CYGWIN_EXEC) + strcat (mnt.mnt_opts, (char *) ",cygexec"); + else if (m->flags & MOUNT_EXEC) + strcat (mnt.mnt_opts, (char *) ",exec"); + if ((m->flags & MOUNT_AUTO)) /* cygdrive */ + strcat (mnt.mnt_opts, (char *) ",noumount"); + mnt.mnt_freq = 1; + mnt.mnt_passno = 1; + m++; + return &mnt; +}