3 Copyright 2001, 2002, 2003, 2004, 2005, 2008, 2010 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
19 #define WIN32_NO_STATUS /* Disable status codes in winnt.h since we include
20 ntstatus.h for extended status codes below. */
22 #undef WIN32_NO_STATUS
23 #ifndef __MINGW64_VERSION_MAJOR
24 # include <ddk/ntapi.h>
25 # include <ddk/winddk.h>
27 # include <winternl.h>
28 # include <ntstatus.h>
33 static int package_len
= 20;
34 static unsigned int version_len
= 10;
39 char pkgtar
[MAX_PATH
+ 1];
40 char pkg
[MAX_PATH
+ 1];
41 char ver
[MAX_PATH
+ 1];
42 char tail
[MAX_PATH
+ 1];
47 find_tar_ext (const char *path
)
49 char *p
= strchr (path
, '\0') - 7;
54 if (strcmp (p
, ".tar.gz") != 0)
57 else if (--p
<= path
|| strcmp (p
, ".tar.bz2") != 0)
71 if ((*s
== '/' || *s
== ':' || *s
== '\\') && s
[1])
78 /* Parse a filename into package, version, and extension components. */
80 parse_filename (const char *in_fn
, fileparse
& f
)
83 char fn
[strlen (in_fn
) + 1];
86 int n
= find_tar_ext (fn
);
91 strcpy (f
.tail
, fn
+ n
);
93 f
.pkg
[0] = f
.what
[0] = '\0';
95 for (ver
= p
; *ver
; ver
++)
98 else if (isdigit (ver
[1]))
104 else if (strcasecmp (ver
, "-src") == 0 ||
105 strcasecmp (ver
, "-patch") == 0)
109 strcpy (f
.what
, strlwr (ver
));
110 strcpy (f
.pkgtar
, p
);
111 strcat (f
.pkgtar
, f
.tail
);
112 ver
= strchr (ver
, '\0');
122 p
= strchr (ver
, '\0');
123 strcpy (f
.pkgtar
, in_fn
);
124 if ((p
-= 4) >= ver
&& strcasecmp (p
, "-src") == 0)
126 else if ((p
-= 2) >= ver
&& strcasecmp (p
, "-patch") == 0)
132 strcpy (f
.what
, p
+ 1);
134 p
= f
.pkgtar
+ (p
- fn
) + n
;
135 memmove (p
- 4, p
, strlen (p
));
139 strcpy (f
.ver
, *ver
? ver
: "0.0");
144 dump_file (const char *msg
, const char *fn
)
147 bool printed
= false;
149 size_t len
= strlen (fn
);
150 char *path
= cygpath ("/etc/setup/setup.rc", NULL
);
151 FILE *fp
= fopen (path
, "rt");
155 while (fgets (buf
, 4096, fp
))
163 char *p
= strchr (bufp
, '\0');
164 printf ("%s%s%s", msg
, bufp
,
165 (p
== bufp
) || p
[-1] != '\n' ? "\n" : "");
169 if (!strncmp (buf
, fn
, len
) && buf
[len
] == '\n')
185 compar (const void *a
, const void *b
)
187 const pkgver
*pa
= (const pkgver
*) a
;
188 const pkgver
*pb
= (const pkgver
*) b
;
189 return strcasecmp (pa
->name
, pb
->name
);
194 match_argv (char **argv
, const char *name
)
198 for (char **a
= argv
; *a
; a
++)
199 if (strcasecmp (*a
, name
) == 0)
205 could_not_access (int verbose
, char *filename
, char *package
, const char *type
)
213 printf ("Missing %s: /%s from package %s\n",
214 type
, filename
, package
);
218 printf ("Unable to access %s /%s from package %s\n",
219 type
, filename
, package
);
225 static const WCHAR tfx_chars
[] = {
226 0, 0xf000 | 1, 0xf000 | 2, 0xf000 | 3,
227 0xf000 | 4, 0xf000 | 5, 0xf000 | 6, 0xf000 | 7,
228 0xf000 | 8, 0xf000 | 9, 0xf000 | 10, 0xf000 | 11,
229 0xf000 | 12, 0xf000 | 13, 0xf000 | 14, 0xf000 | 15,
230 0xf000 | 16, 0xf000 | 17, 0xf000 | 18, 0xf000 | 19,
231 0xf000 | 20, 0xf000 | 21, 0xf000 | 22, 0xf000 | 23,
232 0xf000 | 24, 0xf000 | 25, 0xf000 | 26, 0xf000 | 27,
233 0xf000 | 28, 0xf000 | 29, 0xf000 | 30, 0xf000 | 31,
234 ' ', '!', 0xf000 | '"', '#',
236 '(', ')', 0xf000 | '*', '+',
240 '8', '9', 0xf000 | ':', ';',
241 0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?',
257 0xf000 | '|', '}', '~', 127
261 transform_chars (PWCHAR path
, PWCHAR path_end
)
263 for (; path
<= path_end
; ++path
)
265 *path
= tfx_chars
[*path
];
268 extern "C" NTAPI NTSTATUS
NtQueryAttributesFile (POBJECT_ATTRIBUTES
,
269 PFILE_BASIC_INFORMATION
);
271 /* This function checks for file existance and fills the stat structure
272 with only the required mode info. We're using a native NT function
273 here, otherwise we wouldn't be able to check for files with special
274 characters not valid in Win32, and espacially not valid using the
277 simple_nt_stat (const char *filename
, struct stat
*st
)
279 size_t len
= mbstowcs (NULL
, filename
, 0) + 1;
280 WCHAR path
[len
+ 8]; /* Enough space for the NT prefix */
282 UNICODE_STRING upath
;
283 OBJECT_ATTRIBUTES attr
;
284 FILE_BASIC_INFORMATION fbi
;
287 wcscpy (p
, L
"\\??\\");
289 if (filename
[0] == '\\' && filename
[1] == '\\')
293 p
+= mbstowcs (p
, filename
+ 1, len
);
296 p
+= mbstowcs (p
, filename
, len
);
297 /* Remove trailing backslashes. NT functions don't like them. */
300 /* Skip prefix and drive, otherwise question marks and colons are converted
302 transform_chars (path
+ 7, p
);
303 RtlInitUnicodeString (&upath
, path
);
304 InitializeObjectAttributes (&attr
, &upath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
305 status
= NtQueryAttributesFile (&attr
, &fbi
);
306 if (NT_SUCCESS (status
))
308 st
->st_mode
= (fbi
.FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
312 if (status
== STATUS_OBJECT_PATH_NOT_FOUND
313 || status
== STATUS_OBJECT_NAME_INVALID
314 || status
== STATUS_BAD_NETWORK_PATH
315 || status
== STATUS_BAD_NETWORK_NAME
316 || status
== STATUS_NO_MEDIA_IN_DEVICE
317 || status
== STATUS_OBJECT_NAME_NOT_FOUND
318 || status
== STATUS_NO_SUCH_FILE
)
326 directory_exists (int verbose
, char *filename
, char *package
)
329 if (simple_nt_stat(cygpath("/", filename
, NULL
), &status
))
331 if (could_not_access (verbose
, filename
, package
, "directory"))
334 else if (!S_ISDIR(status
.st_mode
))
337 printf ("Directory/file mismatch: /%s from package %s\n", filename
, package
);
344 file_exists (int verbose
, char *filename
, const char *alt
, char *package
)
347 if (simple_nt_stat(cygpath("/", filename
, NULL
), &status
) &&
348 (!alt
|| simple_nt_stat(cygpath("/", filename
, alt
, NULL
), &status
)))
350 if (could_not_access (verbose
, filename
, package
, "file"))
353 else if (!S_ISREG(status
.st_mode
))
356 printf ("File type mismatch: /%s from package %s\n", filename
, package
);
363 open_package_list (char *package
)
365 char filelist
[MAX_PATH
+ 1] = "/etc/setup/";
366 strcat (strcat (filelist
, package
), ".lst.gz");
367 if (!file_exists (false, filelist
+ 1, NULL
, NULL
))
374 char *fn
= cygpath (filelist
, NULL
);
375 fp
= gzopen (fn
, "rb9");
383 check_package_files (int verbose
, char *package
)
385 gzFile fp
= open_package_list (package
);
389 printf ("Empty package %s\n", package
);
394 char buf
[MAX_PATH
+ 1];
395 while (gzgets (fp
, buf
, MAX_PATH
))
397 char *filename
= strtok(buf
, "\n");
399 if (*filename
== '/')
401 else if (!strncmp (filename
, "./", 2))
404 if (filename
[strlen (filename
) - 1] == '/')
406 if (!directory_exists (verbose
, filename
, package
))
409 else if (!strncmp (filename
, "etc/postinstall/", 16))
411 if (!file_exists (verbose
, filename
, ".done", package
))
416 if (!file_exists (verbose
, filename
, ".lnk", package
))
426 * Returns a calloc'd sorted list of packages or NULL if no info.
427 * The last entry in the list is {NULL,NULL}.
430 get_packages (char **argv
)
432 char *setup
= cygpath ("/etc/setup/installed.db", NULL
);
433 FILE *fp
= fopen (setup
, "rt");
441 while (fgets (buf
, 4096, fp
))
442 nlines
+= 2; /* potentially binary + source */
452 packages
= (pkgver
*) calloc (nlines
+ 1, sizeof(packages
[0]));
454 for (n
= 0; fgets (buf
, 4096, fp
) && n
< nlines
;)
456 char *package
= strtok (buf
, " ");
457 if (!package
|| !*package
|| !match_argv (argv
, package
))
459 for (int i
= 0; i
< 2; i
++)
462 char *tar
= strtok (NULL
, " ");
463 if (!tar
|| !*tar
|| !parse_filename (tar
, f
))
466 int len
= strlen (package
);
468 len
+= strlen (f
.what
) + 1;
469 if (len
> package_len
)
471 packages
[n
].name
= (char *) malloc (len
+ 1);
472 strcpy (packages
[n
].name
, package
);
474 strcat (strcat (packages
[n
].name
, "-"), f
.what
);
475 packages
[n
].ver
= strdup (f
.ver
);
476 if (strlen(f
.ver
) > version_len
)
477 version_len
= strlen(f
.ver
);
479 if (strtok (NULL
, " ") == NULL
)
484 packages
[n
].name
= packages
[n
].ver
= NULL
;
486 qsort (packages
, n
, sizeof (packages
[0]), compar
);
494 dump_setup (int verbose
, char **argv
, bool check_files
)
496 pkgver
*packages
= get_packages(argv
);
498 puts ("Cygwin Package Information");
499 if (packages
== NULL
)
501 puts ("No setup information found");
507 bool need_nl
= dump_file ("Last downloaded files to: ", "last-cache");
508 if (dump_file ("Last downloaded files from: ", "last-mirror") || need_nl
)
512 printf ("%-*s %-*s%s\n", package_len
, "Package",
513 check_files
? version_len
: 7, "Version",
514 check_files
? " Status" : "");
515 for (int i
= 0; packages
[i
].name
; i
++)
518 printf ("%-*s %-*s%s\n", package_len
, packages
[i
].name
,
519 version_len
, packages
[i
].ver
,
520 check_package_files (verbose
, packages
[i
].name
)
521 ? " OK" : " Incomplete");
523 printf ("%-*s %s\n", package_len
, packages
[i
].name
, packages
[i
].ver
);
533 package_list (int verbose
, char **argv
)
535 pkgver
*packages
= get_packages(argv
);
536 if (packages
== NULL
)
538 puts ("No setup information found");
542 for (int i
= 0; packages
[i
].name
; i
++)
544 gzFile fp
= open_package_list (packages
[i
].name
);
548 printf ("Can't open file list /etc/setup/%s.lst.gz for package %s\n",
549 packages
[i
].name
, packages
[i
].name
);
554 printf ("Package: %s-%s\n", packages
[i
].name
, packages
[i
].ver
);
556 char buf
[MAX_PATH
+ 1];
557 while (gzgets (fp
, buf
, MAX_PATH
))
559 char *lastchar
= strchr(buf
, '\n');
560 if (lastchar
[-1] != '/')
561 printf ("%s/%s", (verbose
?" ":""), buf
);
573 package_find (int verbose
, char **argv
)
575 pkgver
*packages
= get_packages(NULL
);
576 if (packages
== NULL
)
578 puts ("No setup information found");
582 for (int i
= 0; packages
[i
].name
; i
++)
584 gzFile fp
= open_package_list (packages
[i
].name
);
588 char buf
[MAX_PATH
+ 2];
590 while (gzgets (fp
, buf
+ 1, MAX_PATH
))
592 char *filename
= strtok(buf
, "\n");
593 int flen
= strlen (filename
);
594 if (filename
[flen
- 1] != '/')
596 // FIXME: verify that /bin is mounted on /usr/bin; ditto for /lib
597 bool is_alias
= !strncmp(filename
, "/usr/bin/", 9) ||
598 !strncmp(filename
, "/usr/lib/", 9);
599 int a
= match_argv (argv
, filename
);
601 a
= match_argv (argv
, filename
+ 4);
602 if (!a
&& !strcmp(filename
+ flen
- 4, ".exe"))
604 filename
[flen
- 4] = '\0';
605 a
= match_argv (argv
, filename
);
608 a
= match_argv (argv
, filename
+ 4);
612 printf ("%s: found in package ", filename
);
613 printf ("%s-%s\n", packages
[i
].name
, packages
[i
].ver
);