summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <vinschen@redhat.com>2007-11-12 15:31:45 +0000
committerCorinna Vinschen <vinschen@redhat.com>2007-11-12 15:31:45 +0000
commit3868726bb8a58ee9466ad022a2adf74cab715961 (patch)
tree794d75155a7f1f04b449a618023fa9d8231957f5
parente62ab8f1f4f65459d52959afc912eaaf0bc2767c (diff)
downloadgdb-3868726bb8a58ee9466ad022a2adf74cab715961.tar.gz
2007-08-31 Dave Korn <dave.korn@artimi.com>
* mkgroup.c (enum_groups): Use MAX_PREFERRED_LENGTH in netgroupenum call so that it will automatically size returned buffer sufficiently. 2007-08-03 Dave Korn <dave.korn@artimi.com> * Makefile.in (cygcheck.exe): Add bloda.o as prerequisite, adjusting dependency-filtering $(wordlist ...) call appropriately. Link ntdll. (bloda.o): New rule to build bloda.o * cygcheck.cc (dump_sysinfo): Call bloda function dump_dodgy_apps(). * bloda.cc: New file implements detection of applications from the Big List Of Dodgy Apps. 2007-07-24 Corinna Vinschen <corinna@vinschen.de> * COPYING.dumper: New file. * dumper.cc: Change license to plain GPLv2 + later. * dumper.h: Ditto. * parse_pe.cc: Ditto. 2007-07-23 Christopher Faylor <me+cygwin@cgf.cx> * strace.cc (create_child): Don't convert a path from cygwin format unless it has a slash. 2007-07-09 Christopher Faylor <me+cygwin@cgf.cx> * strace.cc (usage): Add missing description for -q. 2007-05-29 Pedro Alves <pedro_alves@portugalmail.pt> * dumper.cc (dumper::prepare_core_dump): Record a phdr for each section. 2007-03-30 Mark Mitchell <mark@codesourcery.com> * utils/cygpath.cc (get_long_path_name_w32impl): Close handles returned by FindFirstFile. 2006-09-11 Eric Blake <ebb9@byu.net> * cygcheck.cc (main): Restore POSIXLY_CORRECT before displaying user's environment. 2006-08-03 Corinna Vinschen <corinna@vinschen.de> * path.cc (vconcat): Don't convert backslahes to slashes. (cygpath): Return native path with all backslashes. 2006-07-30 Ilya Bobir <ilya@po4ta.com> * cygpath.cc (get_long_name): Fallback to get_long_path_name_w32impl. 2006-07-27 Corinna Vinschen <corinna@vinschen.de> * cygpath.c (get_long_name): Cover the case that GetLongPathName doesn't return valid information for non-existant files. Just return incoming filename in that case.
-rw-r--r--winsup/utils/COPYING.dumper340
-rw-r--r--winsup/utils/ChangeLog1977
-rw-r--r--winsup/utils/Makefile.in225
-rw-r--r--winsup/utils/bloda.cc410
-rw-r--r--winsup/utils/cygcheck.cc1958
-rw-r--r--winsup/utils/cygpath.cc831
-rw-r--r--winsup/utils/dumper.cc947
-rw-r--r--winsup/utils/dumper.h142
-rw-r--r--winsup/utils/mkgroup.c797
-rw-r--r--winsup/utils/parse_pe.cc104
-rw-r--r--winsup/utils/path.cc353
-rw-r--r--winsup/utils/strace.cc1061
12 files changed, 9145 insertions, 0 deletions
diff --git a/winsup/utils/COPYING.dumper b/winsup/utils/COPYING.dumper
new file mode 100644
index 00000000000..623b6258a13
--- /dev/null
+++ b/winsup/utils/COPYING.dumper
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog
new file mode 100644
index 00000000000..d12dd9c4a0e
--- /dev/null
+++ b/winsup/utils/ChangeLog
@@ -0,0 +1,1977 @@
+2007-08-31 Dave Korn <dave.korn@artimi.com>
+
+ * mkgroup.c (enum_groups): Use MAX_PREFERRED_LENGTH in netgroupenum
+ call so that it will automatically size returned buffer sufficiently.
+
+2007-08-03 Dave Korn <dave.korn@artimi.com>
+
+ * Makefile.in (cygcheck.exe): Add bloda.o as prerequisite, adjusting
+ dependency-filtering $(wordlist ...) call appropriately. Link ntdll.
+ (bloda.o): New rule to build bloda.o
+ * cygcheck.cc (dump_sysinfo): Call bloda function dump_dodgy_apps().
+ * bloda.cc: New file implements detection of applications from the
+ Big List Of Dodgy Apps.
+
+2007-07-24 Corinna Vinschen <corinna@vinschen.de>
+
+ * COPYING.dumper: New file.
+ * dumper.cc: Change license to plain GPLv2 + later.
+ * dumper.h: Ditto.
+ * parse_pe.cc: Ditto.
+
+2007-07-23 Christopher Faylor <me+cygwin@cgf.cx>
+
+ * strace.cc (create_child): Don't convert a path from cygwin format
+ unless it has a slash.
+
+2007-07-09 Christopher Faylor <me+cygwin@cgf.cx>
+
+ * strace.cc (usage): Add missing description for -q.
+
+2007-05-29 Pedro Alves <pedro_alves@portugalmail.pt>
+
+ * dumper.cc (dumper::prepare_core_dump): Record a phdr for each section.
+
+2007-03-30 Mark Mitchell <mark@codesourcery.com>
+
+ * utils/cygpath.cc (get_long_path_name_w32impl): Close handles returned
+ by FindFirstFile.
+
+2006-09-11 Eric Blake <ebb9@byu.net>
+
+ * cygcheck.cc (main): Restore POSIXLY_CORRECT before displaying user's
+ environment.
+
+2006-08-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * path.cc (vconcat): Don't convert backslahes to slashes.
+ (cygpath): Return native path with all backslashes.
+
+2006-07-30 Ilya Bobir <ilya@po4ta.com>
+
+ * cygpath.cc (get_long_name): Fallback to get_long_path_name_w32impl.
+
+2006-07-27 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygpath.c (get_long_name): Cover the case that GetLongPathName
+ doesn't return valid information for non-existant files. Just return
+ incoming filename in that case.
+
+2006-07-03 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+
+ * Makefile.in: Build setmetamode.exe.
+ * setmetamode.c: New file.
+
+2006-05-24 Christopher Faylor <cgf@timesys.com>
+
+ * configure.in: Update to newer autoconf.
+ (thanks to Steve Ellcey)
+ * configure: Regenerate.
+ * aclocal.m4: New file.
+
+2006-05-24 Christopher Faylor <cgf@timesys.com>
+
+ * strace.cc (proc_child): Propagate return code from child process.
+ (dostrace): Ditto.
+ (main): Ditto.
+
+2006-03-03 Christian Franke <franke@computer.org>
+
+ * regtool.cc (options): Add 'binary'.
+ (usage): Document 'load|unload|save' and '-b'.
+ (find_key): Add 'options' parameter, add load/unload.
+ (cmd_set): Add KT_BINARY case.
+ (cmd_get): Add hex output in KT_BINARY case.
+ (cmd_load): New function.
+ (cmd_unload): New function.
+ (set_privilege): New function.
+ (cmd_save): New function.
+ (commands): Add load, unload and save.
+ (main): Add '-b'
+ * utils.sgml (regtool): Document it.
+
+2006-02-17 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygpath.cc (get_long_name): Load GetLongPathNameA instead of incorrect
+ GetLongPathName.
+ (doit): Create mixed filename after converting to short or long pathname
+ respectively.
+
+2006-02-17 Jerry D. Hedden <jerry@hedden.us>
+
+ * ps.cc (main): Set aflag if -p option is given.
+
+2006-02-16 Jerry D. Hedden <jerry@hedden.us>
+
+ * ps.cc (longopts): Add --process option.
+ (opts): Add -p option.
+ (usage): Mention -p/--process option.
+ (main): Handle -p option.
+ * utils.sgml: Describe -p/--process option.
+
+2006-02-15 Igor Peshansky <pechtcha@cs.nyu.edu>
+
+ * regtool.cc (usage): Clarify help for "-K".
+
+2006-02-08 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (find_on_path): Update copyright text.
+
+2006-02-08 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (find_on_path): Create copy of rv on successful access
+ check, since rv can be reused in subsequent calls.
+
+2006-01-19 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (common_paths): Add "patch".
+
+2006-01-19 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (init_paths): Record first_nonsys_path.
+ (find_on_path): Start on first nonsys path when !search_sysdirs.
+
+2006-01-18 Christopher Faylor <cgf@timesys.com>
+
+ * Makefile.in (sysconfdir): Remove unneeded variable.
+
+ * mkgroup.c: Replace ` with ' throughout.
+ * mkpasswd.c: Ditto.
+ * setfacl.c: Ditto.
+ * ssp.c: Ditto.
+
+2006-01-18 Dave Korn <dave.korn@artimi.com>
+
+ * cygpath.cc (dowin): Remove stray debugging printf statement.
+
+2006-01-17 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in: Replace etcdir with sysconfdir.
+
+2006-01-13 Brian Dessent <brian@dessent.net>
+
+ * Makefile.in (cygcheck.exe): Do not link against libwininet.a.
+ * cygcheck.cc (pInternetCloseHandle): Define global function pointer.
+ (display_internet_error): Use it.
+ (package_grep): Attempt to load wininet.dll at runtime. Call WinInet
+ API through function pointers throughout.
+
+2006-01-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Convert k32 to HMODULE.
+
+2006-01-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Convert osname to const and remove casts
+ in subsequent assignments. Recognize Longhorn/Vista and report as not
+ yet supported. Recognize when running under WOW64 and report native
+ CPU type. Slightly rearrange \n printing.
+
+2006-01-12 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc: Replace ` with ' throughout.
+
+2006-01-05 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (dump_sysinfo): Report the failing drive to prevent
+ having to guess.
+
+2005-12-29 Christopher Faylor <cgf@timesys.com>
+
+ * strace.cc (nprocesses): Make static global.
+ (quiet): New variable.
+ (strace_active): Ditto.
+ (add_child): Increment nprocesses here. Don't add a child if it is
+ already added (windows bug?). Report on child if not quiet.
+ (get_child): Just return NULL if child not found.
+ (remove_child): Report on child if not quiet.
+ (attach_process): Don't complain if given a windows process. Use
+ windows pid in error.
+ (handle_output_debug_string): Issue error if trying to manipulate a process that we don't know about.
+ Handle _STRACE_CHILD_PID - attach to reported child when we get this.
+ (proc_child): Move nprocesses to file scope.
+ Report on exceptions.
+ (longopts): Implement "--quiet".
+ (opts): Implement "-q".
+ (main): Manipulate quiet flag.
+ * utils.sgml (strace): Add words describing '-q'.
+
+2005-12-29 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (common_apps): Add crontab, vi, vim.
+
+2005-12-19 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * dump_setup.cc (package_find): Fix is_alias computation for "/usr/lib".
+
+2005-12-14 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (common_apps): Add a few more binaries to look for.
+
+2005-12-05 Christopher Faylor <cgf@timesys.com>
+
+ * strace.cc (show_usecs): Renamed from 'usecs'.
+ (main): Use show_usecs rather than usecs. Toggle delta if '-u' is
+ specified.
+ (handle_output_debug_string): Avoid printing microsecond timestamp if
+ show_usecs == 0.
+ * utils.sgml (strace): Add words to describe '-u'.
+
+2005-11-22 Brian Dessent <brian@dessent.net>
+
+ * Makefile.in: Link cygcheck with libwininet.a.
+ * cygcheck.cc: Add includes.
+ (grep_packages): New global variable.
+ (display_internet_error): New function.
+ (safe_chars): New global variable.
+ (base_url): Ditto.
+ (package_grep): New function.
+ (usage): Reword --help output for clarity. Document new argument.
+ (longopts): Add 'package-query' option.
+ (opts): Add 'p' option, reorder to be consistent with 'longopts'.
+ (main): Accommodate new option.
+ * utils.sgml (cygcheck): Update --help output. Document new -p option.
+
+2005-09-22 Corinna Vinschen <corinna@vinschen.de>
+
+ Align error message handling to mkpasswd's error messages throughout.
+ * mkgroup.c (print_win_error): Create macro calling ...
+ (_print_win_error): ... this function created from former
+ print_win_error. Move up in source.
+ (PDOMAIN_CONTROLLER_INFOW): Define return type of DsGetDcNameW.
+ (dsgetdcname): New function pointer for DsGetDcNameW.
+ (load_netapi): Get DsGetDcNameW address.
+ (main): If DsGetDcNameW is available, use it.
+ * mkpasswd.c (PDOMAIN_CONTROLLER_INFOW): Define return type of
+ DsGetDcNameW.
+ (dsgetdcname): New function pointer for DsGetDcNameW.
+ (load_netapi): Get DsGetDcNameW address.
+ (main): If DsGetDcNameW is available, use it. Rename local variable
+ domain_name_specified to domain_specified as in mkgroup.c.
+
+2005-09-08 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * regtool.cc: Extend copyright-years.
+ (print_version): Ditto.
+ (cmd_list): Don't depend on terminating '\0' being present on
+ string-values.
+ (cmd_get): Don't attempt to read more than present, but keep
+ extra space for terminating '\0'. Really output REG_BINARY.
+ Don't leak memory.
+ (cmd_set): Include trailing '\0' in string's length.
+
+2005-08-18 Corinna Vinschen <corinna@vinschen.de>
+
+ * passwd.c (longopts): Add --logonserver option.
+ (opts): Add -d option.
+ (GetPW): Add server parameter which is given to Net functions.
+ (ChangePW): Ditto.
+ (PrintPW): Ditto.
+ (SetModals): Ditto.
+ (usage): Add description for -d/--logonserver option.
+ (main): Add option handling for -d/--logonserver. Use LOGONSERVER
+ environment variable content for server to contact, unless
+ -d/--logonserver option is given. If both is missing, use NULL.
+
+2005-08-16 Brian Dessent <brian@dessent.net>
+
+ * cygcheck.cc (dump_sysinfo_services): Properly null-terminate 'buf'.
+ Avoid extraneous cygrunsrv invocation if 'verbose' is true.
+
+2005-08-03 Corinna Vinschen <corinna@vinschen.de>
+
+ * mount.cc (longopts): Fix typo which disallows --options option.
+
+2005-07-19 Christopher Faylor <cgf@timesys.com>
+ Eric Blake <ebb9@byu.net>
+
+ * cygcheck.cc (find_on_path): Perform .exe magic on non-PATH search.
+
+2005-07-05 Eric Blake <ebb9@byu.net>
+
+ * cygcheck.cc (track_down, cygcheck): Return true on success.
+ (main): Reflect cygcheck failures in exit status.
+
+2005-06-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * parse_pe.c (exclusion::sort_and_check): Remove crude cast.
+
+2005-05-30 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Recognize XP Media Center and Tablet PC
+ Editions. Change .NET to 2003 throughout. Recognize 2003 Web Server
+ and Datacenter Server. Report when running in terminal server session.
+
+2005-05-27 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (load_cygwin): Make half-hearted attempt to work with
+ older DLLs.
+ * strace.cc (load_cygwin): Ditto.
+
+2005-05-22 Brian Dessent <brian@dessent.net>
+
+ * cygcheck.cc (dump_sysinfo_services): Add new function that uses
+ new cygrunsrv options to dump service info.
+ (dump_sysinfo): Call dump_sysinfo_services if running under NT.
+ Change 'Cygnus' to 'Cygwin' in output.
+
+2005-05-20 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (load_cygwin): Remove debugging statement.
+
+2005-05-20 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (dump_sysinfo): Don't attempt to use path if it is not
+ set.
+ (nuke): Fix off by one error in allocation of environment variable.
+ (load_cygwin): Always set PATH even if cygwin environment is empty.
+
+2005-05-16 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (cygwin_internal): Define as a "C" function.
+ * strace.cc (cygwin_internal): Ditto.
+
+ * cygpath.cc (print_version): Update copyright.
+
+2005-05-15 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (load_cygwin): Avoid calling putenv with a NULL path.
+
+2005-05-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (load_cygwin): Don't touch $PATH for now.
+ (print_version): Fix copyright.
+ * strace.cc (print_version): Ditto.
+
+2005-05-13 Christopher Faylor <cgf@timesys.com>
+
+ * mount.cc (mount_commands): Display "-X" option when appropriate.
+
+2005-05-08 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (nuke): New function.
+ (load_cygwin): New function.
+ (main): Use load_cygwin to load argv/envp from cygwin environment, if
+ appropriate.
+
+2005-05-08 Christopher Faylor <cgf@timesys.com>
+
+ * strace.cc (attach_process): Don't call load_cygwin(). Assume that
+ it's already happened.
+ (dotoggle): Ditto.
+ (main): Set argv from cygwin environment, if it exists.
+
+2005-05-01 Christopher Faylor <cgf@timesys.com>
+
+ * mount.cc (usage): Clarify action of -m option.
+
+2005-04-29 Dave Korn <dave.korn@artimi.com>
+
+ * path.cc (getmntent): Add previously-omitted 'noexec' and 'managed'
+ flags to mnt_opts string if present in mount flags.
+
+2005-04-20 Brian Dessent <brian@dessent.net>
+
+ * utils.sgml (mount): Clarify setting cygdrive prefix for user
+ and system-wide.
+
+2005-03-24 Brian Dessent <brian@dessent.net>
+
+ * cygcheck.cc (init_paths): Use full path instead of "." for the
+ current directory. Do not add "." if present in $PATH.
+ (dump_sysinfo): Skip placeholder first value of paths[].
+
+2005-03-07 Christopher Faylor <cgf@timesys.com>
+
+ * kill.cc (getsig): Rectify bug introduced by 2005-02-26 change. Don't
+ pad signal name with spaces.
+
+2005-03-07 Corinna Vinschen <corinna@vinschen.de>
+
+ * strace.cc (handle_output_debug_string): Fix compiler warning.
+
+2005-03-06 Christopher Faylor <cgf@timesys.com>
+
+ * cygpath.cc (usage): Pass in one more copy of program_name to printf
+ to avoid a SEGV.
+
+2005-02-27 Christopher Faylor <cgf@timesys.com>
+
+ * regtool.cc (opts): The argument to 'K' is not optional.
+ (main): Revert previous change. Just let getopt deal with missing
+ argument.
+
+2005-02-27 Christopher Faylor <cgf@timesys.com>
+
+ * regtool.cc (main): Avoid a SEGV when nothing follows -K.
+
+2005-02-26 Christopher Faylor <cgf@timesys.com>
+
+ * kill.cc (getsig): Avoid buffer overflow when generating a signal name.
+
+ * strace.cc (handle_output_debug_string): Make error a little more specific.
+
+2005-02-23 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygpath.cc (usage): Clarify help output to indicate acceptance
+ of multiple file names as arguments.
+
+2005-01-16 Christopher Faylor <cgf@timesys.com>
+
+ * ps.cc (main): Eliminate use of PID_ZOMBIE.
+ * strace.cc (main): Recognize new option for displaying hex value of
+ strace type.
+ (handle_output_debug_string): Prepend output with hex value of strace
+ message if -H is specified.
+
+2005-01-11 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * mkpasswd.c (print_win_error): Transform into macro.
+ (_print_win_error): Upgrade former print_win_error by
+ printing the line.
+ (current_user): Call _print_win_error.
+ (enum_users): Print name in case of lookup failure.
+ (enum_local_groups): Ditto.
+
+2004-11-18 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (eprintf): New function.
+
+2004-11-16 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (find_on_path): Clear show_error and/or print_failed
+ parameters to display_error.
+ (rva_to_offset): Ditto.
+ (dll_info): Ditto.
+ (track_down): Ditto.
+
+2004-11-13 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * kill.cc (forcekill): Do not pass negative pids to
+ cygwin_internal. Check if sig == 0. Improve error messages.
+ (main): Make pid a long long and distinguish between pids, gpids
+ (i.e. negative pids) and Win9x pids.
+
+2004-11-11 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc: Change "keyeprint" to "display_error" throughout.
+
+2004-11-11 Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (main): Allow a '-l' without an additional argument.
+
+2004-11-11 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (keyeprint): New optional parameters: show_error and
+ print_failed.
+
+2004-10-31 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (get_dword): Fix errormessage.
+ (cygwin_info): Ditto.
+ (track_down): Ditto.
+ (check_keys): Ditto.
+
+2004-10-27 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Warn about missing or multiple cygwin1
+ dlls.
+
+2004-10-25 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Add leading newline before legend for
+ drive-list.
+
+2004-10-22 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): In legend for drive-list: Add ``ram'' and
+ ``unk''. Use single puts. Add leading newline. Line up equal-signs.
+
+2004-10-20 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Allow for larger drives in drive-list.
+ Change ``Used'' to ``Free'' in helptext-title for drive-list.
+
+2004-10-18 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (pretty_id): Don't let i become negative. Fix
+ printf-format.
+
+2004-10-17 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (pretty_id): Allocate space for ')' in uid and guid.
+
+2004-10-17 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+ Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (pretty_id): Allocate space for trailing '\0' in uid and
+ guid.
+
+2004-10-15 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+ Christopher Faylor <cgf@timesys.com>
+
+ * cygcheck.cc (pretty_id): Don't exit on id error. Fix size
+ calculations.
+
+2004-10-14 Christopher Faylor <cgf@timesys.com>
+ Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (pretty_id): Correct column calculations. Abort if id is
+ acting funny.
+
+2004-10-10 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (add_path): Don't leak memory when path is already in
+ ``paths''.
+
+2004-10-10 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Warn about trailing (back)slash on mount
+ entries.
+
+2004-10-10 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Don't warn about empty path components,
+ just display ``.''.
+
+2004-10-06 Corinna Vinschen <corinna@vinschen.de>
+
+ * strace.cc (_impure_ptr): Remove.
+
+2004-10-06 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (dump_sysinfo): Warn about empty path components.
+
+2004-10-04 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * cygcheck.cc (pretty_id): Close pipe.
+
+2004-09-23 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * dump_setup.cc (dump_setup): Remove unneeded strlen when check_files
+ is not set.
+
+2004-09-22 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+ Corinna Vinschen <corinna@vinschen.de>
+
+ * dump_setup.cc (dump_setup): Avoid trailing spaces on package-list.
+
+2004-09-15 Bas van Gompel <cygwin-patch.buzz@bavag.tmfweb.nl>
+
+ * getfacl.c (main): Correct layout when nopt is set.
+
+2004-07-12 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * mkgroup.cc (netapibufferallocate,netgroupgetinfo): New function
+ pointers.
+ (load_netapi): Load NetApiBufferAllocate and NetGroupGetInfo.
+ (enum_local_groups,enum_groups): Add disp_groupname parameter.
+ Load info for disp_groupname if specified.
+ (usage): Add description of "-g/--group" option.
+ (longopts,opts): Add "-g/--group" option.
+ (main): Process "-g/--group" option.
+ * utils.sgml (mkgroup): Add description of "-g/--group" option
+
+2004-06-15 Alan Modra <amodra@bigpond.net.au>
+
+ * dumper.cc (dumper::prepare_core_dump): Use bfd_get_section_size
+ instead of _raw_size.
+ (dumper::write_core_dump): Likewise.
+ * parse_pe.cc (select_data_section): Likewise.
+
+2004-05-29 John Paul Wallington <jpw@gnu.org>
+
+ * ssp.c (usage): Add missing linefeed.
+
+2004-05-27 Christopher Faylor <cgf@alum.bu.edu>
+
+ * kill.cc (listsig): Fix "kill -l" segv. NSIG includes Signal 0, so we
+ need to avoid calling strtosigno with NSIG - 1.
+
+2004-03-21 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (dump_sysinfo): Remove "Win95/NT" from output.
+
+2004-03-15 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc (usage): Don't issue helpful message if -i is used.
+ (from Igor Pechtchanski)
+
+2004-03-13 Rob Siklos <rob2@siklos.ca>
+
+ * kill.cc (get_debug_priv): New function.
+ (forcekill): Call get_debug_priv before trying to kill process.
+
+2004-02-24 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc (long_options): Add "mode" option.
+ (options): Ditto.
+ (usage): Report on new option.
+ (report_mode): New function.
+ (main): Implement -M option.
+
+2004-02-20 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (build_dumper): Detect missing iconv library.
+
+ * cygpath.cc (dowin): Report on filename conversion errors.
+ (doit): Ditto.
+
+ * strace.cc (main): Use symbolic constant for _STRACE_ALL when setting
+ mask.
+
+2004-02-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * ssp.c (opts): Add leading '+' to force posixly correct behaviour.
+
+2004-02-11 Corinna Vinschen <corinna@vinschen.de>
+
+ * strace.cc (opts): Add leading '+' to force posixly correct
+ behaviour.
+ (main): Revert POSIXLY_CORRECT manipulations.
+
+2004-02-10 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (main): Guard against previous setting of POSIXLY_CORRECT.
+
+2004-02-10 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc: Update copyrights.
+ * cygcheck.cc: Update copyrights.
+
+2004-02-10 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (main): Ensure POSIXLY_CORRECT argument ordering.
+ * cygcheck.cc (main): Ditto.
+
+2004-01-23 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (pretty_id): Make more robust in absence of id.exe.
+
+2004-01-22 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygpath.cc (dowin): Revert accidental checkin from November.
+
+2003-11-26 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c (main): Print "root" group with local admins group sid
+ and gid 0.
+
+2003-11-19 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in: Add rules to build ipcrm and ipcs.
+ * ipcrm.c: New file.
+ * ipcs.c: New file.
+
+2003-11-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c: Avoid compiler warnings throughout.
+ * mkpasswd.c: Ditto.
+ * passwd.c: Ditto.
+
+2003-11-07 Mark Blackburn <marklist@fangorn.ca>
+
+ * cygpath.cc (main): Allow multiple pathnames on command line.
+
+2003-11-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * passwd.c (PrintPW): Turn around meaning printed for "Password not
+ required" option to be in line with Windows meaning.
+ (main): Use more appropriate 1008 option when calling
+ NetUserSetInfo to change flag values.
+
+2003-11-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * passwd.c (UF_LOCKOUT): Remove (defined in lmaccess.h).
+ (version): Bump version number to 1.5.
+ (longopts): Add -c, -C, -e, -E, -p, -P options.
+ (opts): Ditto.
+ (PrintPW): Print values of UF_PASSWD_CANT_CHANGE and
+ UF_DONT_EXPIRE_PASSWD flags. Slightly reformat output. Don't suppress
+ correct system password settings just because the account has admin
+ privileges.
+ (usage): Define as "noreturn" function. Restructure and rephrase
+ output. Accommodate new options.
+ (print_version): Fix copyright dates.
+ (main): Accommodate new options for setting UF_PASSWD_CANT_CHANGE,
+ UF_DONT_EXPIRE_PASSWD and UF_PASSWD_NOTREQD settings.
+
+2003-10-17 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (pretty_id): Don't exec if `id' program is not found.
+
+2003-09-20 Christopher Faylor <cgf@redhat.com>
+
+ * kill.cc (main): Allow negative pids (indicates process groups).
+
+2003-09-17 Christopher Faylor <cgf@redhat.com>
+
+ * parse_pe.cc (exclusion::sort_and_check): Make error message a little
+ more explicit and ignore (hopefully) harmless region overlap.
+
+2003-09-13 Christopher Faylor <cgf@redhat.com>
+
+ * kill.c (forcekill): Wait for process to terminate even if
+ TerminateProcess says it failed.
+
+2003-09-11 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Tweak mingw libz.a detection to make it more reliably
+ detect when libz.a is not available.
+
+2003-09-11 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * cygcheck.cc (dump_only): New global variable.
+ (usage): Add "--dump-only" option, fix "--verbose" line.
+ (longopts, opts): Add "--dump-only" option.
+ (main): Process the "--dump-only" flag. Add new semantic check.
+ Pass dump_only information to dump_setup().
+
+2003-09-11 Corinna Vinschen <corinna@vinschen.de>
+
+ * getfacl (main): Remove extern declaration of optind.
+ * setfacl (main): Remove extern declaration of optarg and optind.
+
+2003-09-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (cygcheck.o): Use MINGW_CXX for compilation.
+ * cygcheck.cc: Just include <getopt.h> rather than cygwin version.
+ (pretty_id): Avoid compiler warnings.
+ * cygpath.cc (usage): Ditto.
+
+2003-09-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (MINGW_CXX): Define and use for mingw-compiled files.
+ * path.cc: Include more path info in cygwin-specific includes since the
+ cygwin directory is no longer included by default.
+
+2003-09-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: More fixups to adjust for the fact that mingw_getopt.o
+ is no longer built.
+
+2003-09-10 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Remove references to getopt since it is now part of
+ mingwex.
+
+2003-09-08 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Rename libz.h -> zlib.h.
+
+2003-09-07 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Detect existence of mingw zlib headers and libraries.
+ Build cygcheck without package checking if they are unavailable.
+ * dump_setup.cc: Generate dummy zlib macros when zlib is not available.
+ (open_package_list): Use zlib functions to uncompress package lists.
+ Return gzFile rather than FILE *.
+ (check_package_files): Change fp to gzFile to accommodate zlib
+ functions. Use gzgets to read from package file. Use gzclose to close
+ the handle.
+ (package_list): Ditto.
+ (package_find): Ditto.
+
+2003-09-05 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * dump_setup.cc (check_package_files): Don't fail on empty package.
+
+2003-09-01 AJ Reins <reinsaj@yahoo.com>
+
+ * mount.cc (mount_commands): Ensure user mode is actually user mode and
+ not the default system mode.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * kill.cc (forcekill): Silence some compiler warnings.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Oops. Put the '...' in the right place.
+
+2003-08-31 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Display "..." when not-verbose.
+
+ * kill.cc (forcekill): Default to entered pid when pinfo fails. Issue
+ some warnings when things don't work.
+
+2003-08-17 David Rothenberger <daveroth@acm.org>
+
+ * dump_setup.cc (check_package_files): Strip leading / and ./ from
+ package file names.
+
+2003-08-16 David Rothenberger <daveroth@acm.org>
+
+ * dump_setup.cc (package_find): Don't stop searching on missing
+ file list.
+ (package_list): Ditto.
+
+2003-08-16 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * dump_setup.cc: (package_list): Make output terse unless
+ verbose requested. Fix formatting.
+ (package_find): Ditto.
+
+2003-08-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (main): Fix some formatting and help text printing.
+
+2003-08-15 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * cygcheck.cc (find_package,list_package): New global
+ variables.
+ (usage): Add "--find-package" and "--list-package" options,
+ reformat output.
+ (longopts, opts): Add "--find-package" and "--list-package"
+ options.
+ (main): Process the "--find-package" and "--list-package"
+ flags. Add new semantic checks. Add calls to find_package()
+ and list_package().
+ * dump_setup.cc: Fix header comment.
+ (match_argv): Change return type to int to distinguish
+ between real matches and default ones.
+ (open_package_list): New static function.
+ (check_package_files): Factor out opening the package list
+ file into open_package_list().
+ (get_packages): New static function.
+ (dump_setup): Factor out getting a list of packages into
+ get_packages().
+ (package_list, package_find): New global functions.
+
+2003-08-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * regtool.cc (usage): Add missing linefeed. Move example to --help
+ text. Fix forward slash description.
+
+2003-08-13 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * dump_setup.cc (check_package_files): Fix extra '/' in filename.
+ Resize command buffer. Fix buffer overflow bug.
+
+2003-08-09 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+ Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc (dump_setup): Check for the existence of the package
+ list file. Rework slightly to use static buffer for popen commands.
+
+2003-08-07 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+ Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc (version_len): New static variable.
+ (could_not_access,directory_exists): New static function.
+ (file_exists): Ditto.
+ (check_package_files): Ditto.
+ (dump_setup): Check the contents of each package if check_files is true
+ and output the result in the "Status" column. Flush output after each
+ package.
+
+2003-08-07 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+ Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc (dump_setup): Remove redundant null check. Add
+ informative message if package info not found.
+
+2003-07-26 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (do_mount): Issue warning when using managed mount option on
+ non-empty directory.
+
+2003-07-25 Christopher Faylor <cgf@redhat.com>
+
+ * configure.in: Use 'install-sh -c'.
+ * configure: Regenerate.
+
+2003-07-25 Christopher Faylor <cgf@redhat.com>
+
+ * configure.in: Always use install-sh.
+ * configure: Regenerate.
+
+2003-07-03 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (struct opt): Remove posix option.
+
+2003-07-03 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (longopts): Add long "options" keyword.
+ (opts): Add -o option.
+ (usage): Display -o option.
+ (struct opt): New.
+ (concat3): New function.
+ (main): Handle -o flag.
+
+2003-06-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (pretty_id): Rework slightly to not rely on spaces.
+
+2003-06-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc: Throughout, always return error when GetShortPathName
+ returns 0.
+
+2003-04-26 Joshua Daniel Franklin <joshuadfranklin at yahoo dot com>
+
+ * mkpasswd.c (usage) Remove extra newline from description output.
+
+2003-04-26 Joshua Daniel Franklin <joshuadfranklin at yahoo dot com>
+
+ * cygcheck.cc (usage) Add description output.
+ * cygpath.cc (usage) Add description output.
+ * dumper.cc (usage) Add newline to description output.
+ * kill.cc (usage) Add description output.
+ * mkgroup.c (usage) Grammatical change to description output.
+ * mkpasswd.c (usage) Grammatical change to description output.
+ * mount.cc (usage) Add description output.
+ * passwd.c (usage) Add description output.
+ * ps.cc (usage) Add description output.
+ * regtool.cc (usage) Add description output.
+ * setfacl.c (usage) Remove extra newline from description output.
+ * ssp.c (usage) Add description output.
+ * strace.cc (usage) Add description output.
+ * umount.cc (usage) Add description output.
+
+2003-04-10 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * mkpasswd.c (current_user): print uid and gid as unsigned.
+ (enum_users): Ditto. Do not free servername.
+ (usage): Update to allow several domains and improve -p.
+ (main): On Win9x limit uids to 1000. Only print specials
+ when -l is specified. Add a loop to allow several domains
+ and free servername in the loop.
+ * mkgroup.c (enum_groups): Do not free servername.
+ (usage): Update to allow several domains. Change uid to gid.
+ (main): Only print specials when -l is specified. Add a
+ loop to allow several domains and free servername in the loop.
+
+2003-03-24 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (dump_sysinfo): Ensure that CYGWIN environment variable
+ is correctly set.
+
+2003-03-09 Corinna Vinschen <corinna@vinschen.de>
+
+ * getfacl.c (username): Fix ambiguous printf calls.
+ (groupname): Ditto.
+ (main): Ditto.
+
+2003-03-04 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (strace.exe): Include mingw_getopt.o in link line.
+ * cygcheck.cc (print_version): Update copyright.
+ * strace.cc (print_version): Ditto.
+ (main): Allow cygwin paths for -o option.
+ (create_child): Allow cygwin path as argv[0].
+ * path.cc (path.cc): Allow UNC paths.
+
+2003-03-01 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * mkpasswd.cc (main): On Win95, output both a default line and a
+ line for the current user (if known) with a pseudorandom uid. If
+ the -u switch is given, produce a line for the specified user.
+ * mkgroup.cc (main): On Win95 change the group name from "unknown" to
+ "all".
+
+2003-02-28 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (cygcheck.o): Fix so that actual mingw include files are
+ used.
+ * cygcheck.cc (find_on_path): Translate from cygwin path when qualified
+ path name found.
+ (pretty_id): New function. Dump output of id command.
+ (dump_sysinfo): Call pretty_id for CYGWIN=ntsec and CYGWIN=nontsec cases.
+
+2003-02-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc (doit): Allocate more space for non-path filename.
+
+2003-02-07 Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc (compar): Use case insensitive comparisons.
+ (dump_setup): Calculate package_len based on already used "len". Don't
+ bother with version_len.
+
+2003-02-07 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * dump_setup.cc (dump_setup): Compute the longest package name
+ and align columns properly.
+
+2003-02-06 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (common_apps): Add some more apps.
+ * path.cc (get_cygdrive): Correctly set system flag.
+
+2003-01-22 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in (ALL_LDFLAGS): Remove newlib/libm from tools paths.
+ (MINGW_LDFLAGS): Remove in favor of definition from Makefile.common.
+
+2003-01-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c: Fix copyright date.
+ * mkpasswd.c: Ditto.
+ * setfacl.c: Ditto.
+
+2003-01-09 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * setfacl.c (usage): Remove double ":" for mask and other.
+
+2003-01-07 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * mkpasswd.c (current_user): Create.
+ (usage): Reorganize to support Win95/98/ME.
+ (main): Add option for -c. Reorganize to parse options for
+ Win95/98/ME and to call current_user. Add username in gecos field
+ on Win95/98/ME.
+ * mkgroup.c (enum_groups): Print gid with %u.
+ (print_win_error): Create from passwd.cc.
+ (current_group): Create.
+ (usage): Reorganize to support Win95/98/ME.
+ (main): Add option for -c. Reorganize to parse options for
+ Win95/98/ME and to call current_group.
+
+2002-12-14 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * setfacl.c (main): Place a single : after other and mask.
+ * getfacl.c (getaclentry): Allow both : and :: for other and mask.
+ (main): Remove extraneous break.
+
+2002-11-25 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkpasswd.c (main): Set pw_passwd field to '*' on 9x/Me.
+
+2002-11-24 Corinna Vinschen <corinna@vinschen.de>
+
+ * setfacl.c (getperm): Set only `other' permission bits.
+ (getaclentry): Set a_id to -1 by default.
+
+2002-11-24 Corinna Vinschen <corinna@vinschen.de>
+
+ * getfacl.c (permstr): Use `other' permission bits for requesting
+ ace permissions.
+
+2002-11-08 Corinna Vinschen <corinna@vinschen.de>
+
+ * setfacl.c (usage): Add missing LF.
+
+2002-10-30 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc (get_long_path_name_w32impl): Define similarly to
+ GetLongPathName.
+ (get_long_name): Correctly prototype GetLongPathName.
+ (get_long_paths): Implement using get_long_name to cut down on code
+ duplication.
+ (doit): Do various things to make path output work predictably.
+
+2002-10-19 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (usage): Correctly report default mode.
+ * strace.cc (main): Use strtoul as appropriate.
+
+2002-09-29 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc (close_arg): Remove unused static.
+ * mkgroup.c (enum_local_users): Avoid compiler warning.
+ (enum_users): Ditto.
+ * mkpasswd.c: Ditto throughout.
+ * ssp.c: Ditto throughout.
+
+2002-09-18 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc: Include sys/time.h rather than time.h to avoid a
+ compiler error.
+
+2002-09-17 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc: Reorder includes to avoid compiler error.
+
+2002-09-15 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygcheck.cc (print_version) Add final newline.
+ * getfacl.c (print_version) Add final newline.
+ * kill.cc (print_version) Add final newline.
+ * mkgroup.c (print_version) Add final newline.
+ * mkpasswd.c (print_version) Add final newline.
+ * mount.cc (print_version) Add final newline.
+ * passwd.c (print_version) Add final newline.
+ * ps.cc (print_version) Add final newline.
+ * regtool.cc (print_version) Add final newline.
+ * setfacl.c (print_version) Add final newline.
+ * ssp.c (print_version) Add final newline.
+ * strace.cc (print_version) Add final newline.
+ * umount.cc (print_version) Add final newline.
+
+2002-09-12 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * cygpath.cc (options) New global variable.
+ (main) Make short options global for easier change.
+ (print_version) Add a missing newline.
+
+2002-08-07 Igor Pechtchanski <pechtcha@cs.nyu.edu>
+
+ * regtool.cc (find_key): Add support for custom key separator.
+ (usage): Document it.
+
+2002-08-02 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c (main): Don't print an entry for "Everyone".
+ * mkpasswd.c (print_special): Set pw_gid to 544 for SYSTEM user.
+ (main): Don't print an entry for "Everyone".
+
+2002-07-06 Christopher Faylor <cgf@redhat.com>
+
+ * configure.in: Check for libiconv.a.
+ * configure: Regenerate.
+ * Makefile.in: Add libiconv.a to libraries required for dumper.exe.
+
+2002-07-06 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Use MINGW stuff from Makefile.common.
+
+2002-07-01 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c: Add function pointers for functions from advapi32.dll.
+ (load_netapi): Load used functions from advapi32.dll.
+ (main): Use function pointers instead of statically linked functions
+ from advapi32.dll.
+
+2002-07-01 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (main): Ensure that mount_already_exists() also gets default
+ flag that is passed to do_mount.
+
+2002-06-22 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygpath.cc (long_options): Add "dos" and "mixed", correct "close",
+ "file" and "type" to use NULL flag.
+ (usage): Clean up usage output (more), accomodate new options.
+ (main): Add --dos and --mixed options; accomodate all output forms in
+ --type. Make UNIXy output default.
+
+2002-06-18 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygpath.cc (usage): Clean up usage output.
+ (dowin): Correct output of -t mixed for -ADHPSW options.
+
+2002-06-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * passwd.c: Rearrange includes to avoid unnecessary warnings.
+ (GetPW): Add parameter to (dis)allow printing of Windows username.
+ Use defines instead of numerical constants where possible.
+ Try avoiding impersonation problem. Rearrange to print Windows
+ username only if it's different from Cygwin username.
+ (ChangePW): Use defines instead of numerical constants where possible.
+ (main): Call GetPW with additional parameter. Change error text.
+
+2002-06-14 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * passwd.c (GetPW): Handle case of user-edited /etc/passwd
+ with cygwin_internal (CW_EXTRACT_DOMAIN_AND_USER, ...).
+
+2002-06-09 Christopher Faylor <cgf@redhat.com>
+
+ * path.cc (cygpath): Change MOUNT_AUTO to MOUNT_CYGDRIVE.
+ (getmntent): Ditto.
+
+2002-06-09 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (main): Use default system/user flag for cygdrive stuff,
+ too.
+ (change_cygdrive_prefix): Change MOUNT_AUTO to MOUNT_CYGDRIVE.
+ * umount.cc (remove_cygdrive_prefix): Ditto.
+ (main): Use default system/user flag for cygdrive stuff, too.
+
+2002-06-08 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (opts): Remove '-i' option.
+ (usage): Ditto.
+ (main): Ditto.
+ (longopts): Remove --import-old-mounts option.
+
+2002-06-07 David Peterson <chief@mail.idrive.com>
+ Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc: Add option to output windows paths in different formats:
+ "dos" and "mixed".
+ (main): Process options.
+ (doit): Check new options flags.
+
+2002-06-06 Egor Duda <deo@logos-m.ru>
+
+ * regtool.cc (Fail): Be more verbose.
+ (find_key): Add support for remote registry access.
+ (usage): Document it.
+ * utils.sgml: Document it.
+
+2002-06-06 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (main): Make toggle a local variable.
+
+2002-06-07 Conrad Scott <conrad.scott@dsl.pipex.com>
+
+ * strace.cc (toggle): New global variable.
+ (error): Use exit instead of ExitProcess so that stdio buffers get
+ flushed.
+ (create_child): Remove command line error checking.
+ (dostrace): Ditto.
+ (dotoggle): New function.
+ (usage): Add entry for new option -T|--toggle. Alphabetize.
+ (longopts): Add new option -T|--toggle.
+ (opts): Ditto.
+ (main): Handle new -T|--toggle option. Move all command line checking
+ here from other functions.
+ * utils.sgml: Update section for strace.
+
+2002-06-05 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * strace.cc (version): New global variable.
+ (usage): Accommodate stdout output.
+ (print_version): New function.
+
+2002-06-03 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * ssp.c (version): New global variable.
+ (longopts): Ditto.
+ (opts): Ditto.
+ (run_program): Correct cmd_line typos to cmdline.
+ (usage): New function. Standardize usage output. Add ssp.txt to
+ --help output.
+ (print_version): New function.
+ (main): Accommodate getopt.
+
+2002-06-03 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * umount.cc (version): New global variable.
+ (longopts): Accommodate new --version option.
+ (opts): Ditto.
+ (usage): Standardize usage output.
+ (print_version): New function.
+ (main): Accommodate --help, --version options.
+
+2002-06-02 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * regtool.cc (prog_name): New global variable.
+ (longopts): Ditto.
+ (opts): Ditto.
+ (usage): Standardize usage output. Rearrange/add descriptions.
+ (print_version): New function.
+ (main): Accommodate longopts and new --help, --version options. Add
+ check for (_argv[optind+1] == NULL).
+
+2002-06-02 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (forkdebug): Make true by default.
+ (attach_process): Use window pid if cygwin pid isn't available (yet).
+ (create_child): Use either DEBUG_ONLY_THIS_PROCESS or DEBUG_PROCESS,
+ exclusively. (Suggested by Conrad.Scott@dsl.pipex.com)
+
+2002-05-30 Christopher Faylor <cgf@redhat.com>
+
+ * mkpasswd.cc (main): Don't reset to binmode if stdout is a terminal.
+
+2002-05-29 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (main): Make -b the default.
+
+2002-05-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * ps.cc (main): Use uid or uid32 member of struct external_pinfo
+ dependent of the value of the struct's version member.
+
+2002-05-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * ps.cc (main): Change print format for uid to unsigned. Use uid32
+ member of struct external_pinfo instead of uid.
+
+2002-05-28 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * passwd.c (prog_name): New global variable.
+ (longopts): Ditto.
+ (opts): Ditto.
+ (usage): Standardize output. Accommodate new options.
+ (print_version): New function.
+ (main): Accommodate longopts and new --help, --version options.
+
+2002-05-28 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * ps.cc (usage): Fix typo.
+
+2002-05-27 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * ps.cc (prog_name): New global variable.
+ (longopts): Ditto.
+ (opts): Ditto.
+ (usage): New function.
+ (print_version): New function.
+ (main): Accommodate longopts and new --help, --version options.
+
+2002-05-26 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (attach_process): Don't tell process to start stracing
+ here.
+ (proc_child): Do it here, instead, after first debug event. This
+ should work around inexplicable races with DebugActiveProcess.
+ (dostrace): Pass any pid argument to proc_child.
+
+2002-05-23 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * getfacl.c (usage): Standardize usage output. Change return type to
+ static void.
+ (print_version): New function.
+ (longopts): Added longopts for all options.
+ (main): Accommodate new help and version options.
+
+2002-05-22 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * mount.cc (version): New global variable.
+ (usage): Standardize usage output. Accommodate new version option.
+ (print_version): New function.
+ (longopts): Accommodate new version option.
+ (opts): Ditto.
+ (main): Ditto.
+
+2002-05-22 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygpath.cc (usage): Change usage output slightly.
+
+2002-05-20 Joerg Schaible <joerg.schaible@gmx.de>
+
+ * cygpath.cc (main): Add option l to support conversion to
+ Windows long file names. Refactured code for capital options.
+ Support of options from file for capital options.
+ (dowin): New function. Refactured from main.
+ (doit): Call long path conversion.
+ (get_long_name): New function.
+ (get_long_paths): New function.
+ (get_long_path_name_w32impl): New function. Reimplementation
+ of Windows API function GetLongPathName (only 98/Me/2000/XP or
+ higher).
+ (get_short_name): Call GetShortPathName only once.
+ (get_short_paths): Fix calculating buffer size.
+ * utils.sgml: Update cygpath section for l option.
+
+2002-05-18 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (add_child): Use calloc since new requires working
+ libstdc++.a.
+ (remove_child): Ditto for delete/free.
+
+2002-05-15 Mark Blackburn <marklist@fangorn.ca>
+
+ * cygpath.cc (get_short_paths): Fix more error checking.
+ (get_short_name): Ditto.
+
+2002-05-14 Joerg Schaible <joerg.schaible@gmx.de>
+
+ * cygpath.cc (main): Add option H to show the Windows' profiles
+ directory. Support short names for options DPSW. Clean up
+ copied code lines.
+ * utils.sgml: Update cygpath section for H option and s support.
+
+2002-05-14 Mark Blackburn <marklist@fangorn.ca>
+
+ * cygpath.cc (get_short_paths): Fix error checking.
+
+2002-05-13 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * kill.cc (prog_name): New global variable.
+ (usage): Standardize usage output. Add descriptions.
+ (print_version): New function.
+ (longopts): Accommodate new version option.
+ (opts): Ditto.
+ (main): Ditto.
+
+2002-05-13 Christopher Faylor <cgf@redhat.com>
+
+ * kill.cc (listsig): Display numeric id when given symbolic input.
+
+2002-05-13 Christopher Faylor <cgf@redhat.com>
+
+ * kill.cc (usage): Show new options. Allow specification of output
+ stream.
+ (main): Implement 'h' option.
+
+2002-05-13 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (kill.exe): Add as a specific target.
+ * kill.cc (longopts): New.
+ (opts): Ditto.
+ (get_sig): Accept const char * parameter. Return -1 on unknown signal.
+ (test_for_unknown_sig): New function.
+ (listsig): New function.
+ (main): Use getopt_long for option parsing. Implement -l, and -s
+ options. Use test_for_unknown_sig() to test for signal validity.
+
+ * mount.cc (longopts): Make static.
+ (opts): Ditto.
+
+2002-05-12 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (do_mount): Default to non-exec option for remote drives.
+ Report warnings before attempting a mount.
+ (longopts): Add no-executable option.
+ (mount_commands): Ditto.
+ (opts): Ditto.
+ (usage): Ditto. Indicate that system mount is now the default.
+ (main): Accommodate no-executable option. Make system mount the
+ default.
+ * umount.cc (usage): Indicate that system umount is now the default.
+ (main): Make system umount the default.
+
+2002-05-07 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * dumper.cc (usage): Standardize usage output. Generalize to allow use
+ for help.
+ (longopts): New struct. Added longopts for all options.
+ (print_version): New function.
+ (main): Change getopt to getopt_long. Accommodate new help and version
+ options.
+
+2002-03-29 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c (main): Change call to exit() to a return statement.
+ * mkpasswd.c (main): Ditto.
+
+2002-03-27 Joshua Daniel Franklin joshuadfranklin@yahoo.com
+
+ * mkpasswd.c (usage): Simplify usage output. Generalize to allow use
+ for help. Correct '?' typo to 'h'.
+ (longopts): Add version option.
+ (opts): Add 'v' version option.
+ (print_version): New function.
+ (main): Accommodate new version option. Accommodate usage parameter
+ changes.
+
+2002-03-19 Christopher Faylor <cgf@redhat.com>
+
+ * mkgroup.c (usage): Use one just fprintf + string concatenation for
+ output message.
+ (print_version): Add void to function type and update copyright.
+
+2002-03-16 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * mkgroup.c (usage): Simplify usage output. Generalize to allow use
+ for help. Correct '?' typo to 'h'.
+ (longopts): Add version option.
+ (opts): Add 'v' version option.
+ (print_version): New function.
+ (main): Accommodate new version option. Accommodate usage parameter
+ changes. Use usage to output help message.
+
+2002-03-15 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c (main): When generating group 513, check for computer's
+ primary domain instead of current user's domain.
+
+2002-03-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c (main): When generating group 513, check for domain SID
+ if computer name isn't mapped to a SID.
+
+2001-03-11 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * kill.cc (usage): Move to top of file.
+ (getsig): Ditto.
+ (forcekill): Ditto.
+
+2002-03-06 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc: Reformat.
+
+2002-03-06 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (longopts): Use correct short option for --version.
+
+2002-03-06 Christopher Faylor <cgf@redhat.com>
+
+ * cygpath.cc: Reformat.
+
+2002-02-27 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygpath.cc (print_version): New function.
+ (main): Accommodate new version function. Initialize 'o' to prevent
+ warning.
+
+2002-02-27 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (main): Eliminate non-GNU formatting glitch.
+
+2002-02-27 Christopher Faylor <cgf@redhat.com>
+
+ * ssp.c (help_desk): Fix compiler warning.
+
+2002-02-27 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+ Christopher Faylor <cgf@redhat.com>
+
+ Change appropriate globals to statics throughout.
+ * cygcheck.cc (usage): Simplify usage output. Generalize to allow use
+ for help.
+ (longopts): Add version option.
+ (opts): Add 'V" version option.
+ (print_version): New function.
+ (main): Accommodate new version option. Accommodate usage parameter
+ changes. Use usage to output help message.
+
+002-02-19 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (CXXFLAGS): Add override so that HAVE_DECL_GETOPT is
+ defined.
+ (libbfd): Use -B rather than -L so that bfd from build directory is
+ correctly found.
+ (libintl): Ditto.
+
+2002-02-15 Christopher Faylor <cgf@redhat.com>
+
+ * mount.cc (usage): Fix typo in output.
+
+2002-02-14 Christopher Faylor <cgf@redhat.com>
+
+ * strace.cc (attach_process): Change CW_STRACE_ON to CW_STRACE_TOGGLE.
+
+2002-01-31 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkpasswd.c (main): Set default home path for 9x/Me if --path-to-home
+ isn't given.
+
+2002-01-30 Corinna Vinschen <corinna@vinschen.de>
+
+ * passwd.cc (ChangePW): Add parameter to differ between called for
+ checking old password and called for changing password. If called
+ for checking old password, return non-zero only if password is surely
+ incorrect.
+ (main): Call ChangePW() with additional parameter.
+
+2002-01-29 Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc (parse_filename): Don't consider '_' part of the
+ version.
+
+2002-01-28 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc: Fix typo. Remove uid_t kludge. Rely on kludge in
+ sys/cygwin.h instead.
+ * getfacl.c: Add include to remove warning.
+ * mkgroup.c (main): Assign variables outside of parameter passing.
+ This seems to eliminate some compiler warnings.
+
+2002-01-28 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc: Use specific cygwin includes, as required.
+
+2002-01-28 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (MINGW_INCLUDES): Change cygwin include.
+ * strace.cc: Use specific cygwin includes, as required.
+ (load_cygwin): New function. Loads cygwin DLL, if necessary.
+ (attach_process): Attaches strace to a running process.
+ (dostrace): Accept pid argument. Attach to pid if supplied.
+ (usage): Describe -p option. Correct system description.
+ (longopts): Alphabetize.
+ (opts): Ditto.
+ (main): Ditto. Handle -p option.
+
+2002-01-21 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in (CXXFLAGS): Ensure that important settings are preserved
+ even when overriden by command line.
+
+2002-01-21 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Build intermediate cygcheck.o to force use of MINGW_CXXFLAGS.
+ * cygcheck.cc (cygwin_info): Intitialize variable to quiet g++ warning.
+ (dump_sysinfo): Make variables unsigned to quiet g++ warnings.
+ * strace.cc (version_string): Rename from SCCSid.
+ (add_child): Remove unused variable.
+ (version): Use version_string. Avoid use of fprintf.
+
+2002-01-21 DJ Delorie <dj@redhat.com>
+
+ * Makefile.in: Use CXX instead of CC to compile C++ sources.
+
+2002-01-17 DJ Delorie <dj@redhat.com>
+
+ * cygcheck.cc (already_did): Avoid default constructors, which may
+ require exception support.
+
+2001-01-16 Joshua Daniel Franklin <joshuadfranklin@yahoo.com>
+
+ * cygpath.cc (main): Add options to show Desktop and Start
+ Menu's Programs directory for current user or all users.
+ Move bulk of DPWS options outside the getopt case statement.
+ * utils.sgml: Update cygpath section for ADPWS options.
+
+2002-01-15 Joerg Schaible <joerg.schaible@gmx.de>
+
+ * cygpath.cc (doit): Empty file ignored using option -i.
+
+2002-01-15 Mark Bradshaw <bradshaw@crosswalk.com>
+
+ * mkpasswd.c (print_win_error): Add a new function.
+ (enum_users): Use print_win_error.
+ (enum_local_groups): Ditto.
+ (main): Ditto.
+
+2001-12-26 Jonathan Kamens <jik@curl.com>
+
+ * cygpath.cc (doit): Detect and warn about an empty path. Detect and
+ warn about errors converting a path.
+ (main): Set prog_name correctly -- don't leave an extra slash or
+ backslash at the beginning of it.
+
+Fri Dec 14 14:04:37 2001 Jason Tishler <jason@tishler.net>
+
+ * mkpasswd.c (enum_users): Change to unconditionally use
+ the --path-to-home option, if supplied by the user. Use default
+ --path-to-home option value, if appropriate.
+ (usage): Change usage statement to reflect new semantics.
+ (main): Remove defaulting of the --path-to-home option.
+
+Fri Dec 14 12:10:39 2001 Jason Tishler <jason@tishler.net>
+
+ * mkpasswd.c (opts): Add indication that '-p' option requires an
+ argument.
+
+2001-12-11 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Add define to CXXFLAGS.
+
+2001-12-03 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (usage): Add -c description.
+ * cygpath.cc (usage): Alphabetize options.
+ * strace.cc (usage): Ditto.
+
+2001-11-21 Christopher Faylor <cgf@redhat.com>
+
+ * path.cc (cygpath): Don't consider cygdrive stuff when trying to derive
+ native paths.
+
+2001-11-20 Mark Bradshaw <bradshaw@staff.crosswalk.com>
+
+ * mkpasswd.c: include lmerr.h
+ (main): New -u option to allow specifying a
+ specific user. If specified, groups aren't displayed and
+ output is limited to only the specified user.
+ (enum_users): If specific user is specified, via -u option,
+ display only that user's record. With -u use NetUserGetInfo
+ instead of NetUserEnum.
+ (load_netapi): Added netusergetinfo.
+
+2001-11-15 Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
+
+ * strace.cc (main): Change getopt() to getopt_long().
+ Add support for help and version info.
+ Use new parse_mask() function for -m/--mask option.
+ (longopts): Add long options structure.
+ (opts): Move options string from getopts call to static var.
+ (usage): Print usage information.
+ (SCCSid): Version info.
+ (version): New function for displaying version info.
+ (parse_mask): New function supporting parsing of mnemonics,
+ hex, and basic expressions in masks.
+ (mnemonic2ul): New mnemonic parsing function.
+ (tag_mask_mnemonic): New type.
+ (mnemonic_table): New table of mnemonics for mnemonic2ul() to
+ search through.
+
+2001-11-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Redefine output format slightly.
+ Print correct build number on 9x/ME systems.
+
+2001-11-12 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (main): Slight formatting tweak.
+
+2001-11-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Add some more details.
+
+2001-11-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Print more detailed OS information string
+ using OSVERSIONINFOEX information.
+
+2001-11-11 Christopher Faylor <cgf@redhat.com>
+
+ * path.h: New file.
+
+2001-11-11 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (scan_registry): Open registry with read-only access.
+ (main): Reflect argument change for dump_setup.
+ * dump_setup.cc (dump_setup): Add preliminary extra argument for future
+ use.
+ * path.cc (read_mounts): Open registry with read-only access.
+
+2001-11-11 Christopher Faylor <cgf@redhat.com>
+
+ * cygcheck.cc (main): Display package info when '-s' is specified.
+ * dump_setup.cc (dump_setup): Change header. Remove typo. Always sort
+ packages output.
+
+2001-11-11 Christopher Faylor <cgf@redhat.com>
+
+ * dump_setup.cc: New file.
+ * Makefile.in: Add info for dump_setup.o.
+ * cygcheck.cc (main): Recognize '-c' option for checking setup
+ installed base.
+ * path.cc (cygpath): Read mount table if not loaded.
+
+2001-11-10 Christopher Faylor <cgf@redhat.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * cygcheck.cc (dump_sysinfo): Print more detailed OS information string.
+
+2001-11-04 Corinna Vinschen <corinna@vinschen.de>
+
+ * getfacl.c (username): New function.
+ (groupname): Ditto.
+ (usage): Ditto. Add more user friendly help text.
+ (main): Add -n and --help option. Print names instead of IDs
+ unless -n option is given.
+ * setfacl.c (getperm): Tolerate whitespace and comment chars in input.
+ (getaclentry): Fix several input string misdetections.
+ (getaclentries): Allow - as input file name to read from stdin.
+ Tolerate whitespace and comment chars in input.
+ (usage): Add more user friendly help text.
+ (main): Add --help option.
+
+2001-11-04 Egor Duda <deo@logos-m.ru>
+
+ * strace.cc (main): New option '-w'. Start traced process in separate
+ window. New option '-S x'. Flush buffered output every x seconds.
+ (create_child): Start child process in new window, when requested.
+ When requested, periodically flush debugging output.
+
+2001-10-24 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Remove EXEEXT consideration. We always need .exe
+ extensions.
+
+2001-10-20 Corinna Vinschen <corinna@vinschen.de>
+
+ * mkgroup.c: Avoid compiler warnings.
+ (print_special): New function.
+ (main): Print special accounts by calling print_special().
+ * mkpasswd.c: Avoid compiler warnings.
+ (enum_users): Print additional U-domain\username info in gecos
+ field when SIDs are printed.
+ (print_special): New function.
+ (main): Print special accounts by calling print_special().
+
+2001-10-15 Christopher Faylor <cgf@redhat.com>
+
+ * mkpasswd.cc (enum_users): Shorten "unused" passwd field.
+
+2001-10-13 Christopher Faylor <cgf@redhat.com>
+
+ * Makefile.in: Allow stdinc searching for dumper.
+
+Tue Oct 9 21:59:00 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in (MINGW_INCLUDES): Accommodate changes in Makefile.common.
+
+Sun Oct 7 23:06:39 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * kill.cc (main): Set exit value to 1 on invalid pid. Perform minor
+ cleanup.
+
+Fri Sep 21 20:40:30 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in (mingw_getopt.o): Ensure that newlib include directories
+ are not searched.
+
+Thu Sep 20 21:00:20 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in (MINGW_INCLUDES): Still need cygwin/include directory.
+
+Wed Sep 19 12:22:08 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Filter newlib includes from mingw compilation.
+
+2001-09-14 Egor Duda <deo@logos-m.ru>
+
+ * dumper.cc (dumper::dumper): Print error code in case of error.
+ (dumper::add_thread): Ditto.
+ (dumper::collect_memory_sections): Ditto.
+ (dumper::dump_memory_region): Ditto.
+ (dumper::collect_process_information): Ditto.
+ (print_section_name): Fix formatting.
+
+2001-09-13 Egor Duda <deo@logos-m.ru>
+
+ * dumper.cc (main): Properly recognize negative pids (used by w9x).
+
+2001-09-09 Egor Duda <deo@logos-m.ru>
+
+ * dumper.cc (main): Change command-line arguments format to be
+ similar to gdb. Allow adding error_start=x:\path\to\dumper.exe to
+ CYGWIN environment variable to perform core dumping in case of
+ program crash.
+ (usage): Ditto.
+
+Wed Sep 5 22:37:21 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in (dumper): Change logic for libbfd and libintl so that
+ they will be found either in the build tree or the installed directory.
+ * mkpasswd.c (enum_users): Add a comment as a password for NT.
+
+2001-09-03 Michael A Chase <mchase@ix.netcom.com>
+
+ * mount.cc (mount_commands): Don't write /cygdrive/u mount points.
+
+2001-09-03 Michael A Chase <mchase@ix.netcom.com>
+
+ * mount.cc (longopts): Add mount-commands to options list.
+ (usage): Add mount-commands option.
+ (mount_commands): New function. Write commands to recreate current
+ mounts.
+
+Sat Sep 1 15:58:11 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mount.cc (main): Eliminate excess arguments in printf.
+
+2001-08-30 Egor Duda <deo@logos-m.ru>
+
+ * dumper.h: Update copyright notice.
+ * dumper.cc: Ditto.
+ * dumper.cc: (dumper::print_core_section_list): New function.
+ * dumper.h: (dumper::print_core_section_list): Declare it.
+ * dumper.cc (print_section_name): New function.
+ (dumper::collect_process_information): Augment debugging output.
+ Stop debugee processing if it posts double exception.
+ (usage): Fix typo in option name.
+
+Tue Aug 28 14:45:02 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mount.cc (main): Issue correct warning for 'not enough arguments'.
+
+2001-08-14 Joerg Schaible <joerg.schaible@gmx.de>
+
+ * cygpath.cc (main): Support -w for Windows (System) directories and
+ return physical correct orthography for the Windows System dir.
+
+2001-07-14 Chris Genly <chgenly@alum.mit.edu>
+
+ * regtool.cc (find_key): Handle keys with only one subkey.
+
+Wed Jun 27 22:46:10 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * regtool.cc (find_key): Revert previous change.
+
+Wed Jun 27 13:37:41 2001 Keith Starsmeare" <keith_starsmeare@yahoo.co.uk>
+
+ * regtool.cc (find_key): Allow '/' as a synonym for '\\'.
+
+Fri Jun 15 00:49:21 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mkpasswd.c (main): Output passwd file in binary mode so that there
+ are no CRs in the file.
+ * umount.cc (remove_all_user_mounts): Don't try to remove /cygdrive
+ mounts.
+
+Tue May 1 10:50:48 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mkpasswd.c (enum_users): Use /bin/bash as the default shell.
+ (main): Ditto.
+
+Sat Apr 28 22:32:01 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * passwd.cc (ttymnam): New function.
+ (main): Use ttynam() to report name of tty.
+
+2001-04-19 Egor Duda <deo@logos-m.ru>
+
+ * dumper.cc (dumper::init_core_dump): Set architecture field in dump
+ header.
+
+Mon Apr 16 15:08:00 2001 Corinna Vinschen <vinschen@redhat.com>
+
+ * mkgroup.c: Add function pointers `netlocalgroupgetmembers' and
+ `netgroupgetusers'.
+ (load_netapi): Load function pointers `netlocalgroupgetmembers'
+ and `netgroupgetusers'.
+ (enum_local_users): New function.
+ (enum_local_groups): Call `enum_local_users' for each group if
+ `print_users' is set.
+ (enum_users): New function.
+ (enum_groups): Call `enum_users' for each group if `print_users' is set.
+ (usage): Add usage text for `-u/--users'.
+ (longopts): Add option `--users'.
+ (opts): Add option character `u'.
+ (main): Set `print_users' according to option `-u/--users'.
+ Call `enum_local_groups' and `enum_groups' with additional parameter
+ `print_users'.
+
+2001-04-15 Michael A Chase <mchase@ix.netcom.com>
+
+ * mount.cc (longopts): Add help to options list.
+ (opts): Add 'h' to options string.
+ * umount.cc (longopts): Add help to options list.
+ (opts): Add 'h' to options string and change 'R' to 'A'.
+
+2001-04-13 Kazuhiro Fujieda <fujieda@jaist.ac.jp>
+
+ * mkgroup.c (enum_groups): Use RID + offset specified an additional
+ argument as ID.
+ (usage): Add description of -o option.
+ (longopts, opts): Add specifications of -o/--id-offset option.
+ (main): Add -o option. Invoke enum_groups with specified offset.
+ * mkpasswd.c (enum_users): Just like mkgroup.c.
+ (usage, longopts, opts): Ditto.
+ (main): Add -o option. Invoke enum_users with specified offset only
+ against domain accounts.
+
+2001-04-11 Egor Duda <deo@logos-m.ru>
+
+ * mkgroup.c (uni2ansi): Use native method to convert from Unicode
+ to multi-byte strings.
+ * mkpasswd.c (uni2ansi): Ditto.
+ (enum_users): Pass buffer size when converting string.
+ (enum_local_groups): Ditto.
+ * mkgroup.c (enum_groups): Ditto.
+ (enum_local_groups): Ditto.
+
+Mon Apr 2 22:41:33 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mount.cc (main): Use getopt_long for parsing arguments.
+ (usage): Reformat, show long and short options.
+ * umount.cc (main): Ditto, all of the above.
+
+Mon Apr 2 10:58:26 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * mount.cc (show_mounts): Change format string to more closely resemble
+ UNIX when displaying mount table.
+
+Sat Mar 17 21:46:06 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * kill.cc (forcekill): Use dwProcessId when opening a process, not the
+ Cygwin pid.
+
+Mon Mar 5 18:50:00 2001 Corinna Vinschen <vinschen@redhat.com>
+
+ * getfacl.c: Add copyright hint.
+ * setfacl.c: Ditto.
+ * strace.cc: Ditto.
+
+Tue Jan 09 10:26:23 2001 Tony Sideris <tonys1110@home.com>
+
+ * regtool.cc (cmd_list): Add new registry display options.
+ (cmd_list): Add code to implement -p, -k, and -l options.
+
+ * regtool.cc (Fail): Add call to LocalFree to free memory allocated by
+ FormatMessage.
+
+Wed Jan 10 09:16:57 2001 Christopher Faylor <cgf@cygnus.com>
+
+ * regtool.cc (translate): Ensure that 'c' is initialized.
+ (cmd_set): Ditto for rv.
diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in
new file mode 100644
index 00000000000..5c8a2da37be
--- /dev/null
+++ b/winsup/utils/Makefile.in
@@ -0,0 +1,225 @@
+# Makefile for Cygwin utilities
+# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007 Red Hat, Inc.
+
+# 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.
+
+SHELL:=@SHELL@
+
+srcdir:=@srcdir@
+VPATH:=@srcdir@
+prefix:=@prefix@
+exec_prefix:=@exec_prefix@
+
+bindir:=@bindir@
+program_transform_name:=@program_transform_name@
+
+override INSTALL:=@INSTALL@
+override INSTALL_PROGRAM:=@INSTALL_PROGRAM@
+override INSTALL_DATA:=@INSTALL_DATA@
+
+EXEEXT:=@EXEEXT@
+EXEEXT_FOR_BUILD:=@EXEEXT_FOR_BUILD@
+
+CC:=@CC@
+CC_FOR_TARGET:=$(CC)
+CXX:=@CXX@
+CXX_FOR_TARGET:=$(CXX)
+
+CFLAGS:=@CFLAGS@
+CXXFLAGS:=@CXXFLAGS@
+override CXXFLAGS+=-fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0
+
+include $(srcdir)/../Makefile.common
+
+LIBICONV:=@libiconv@
+libbfd:=${shell $(CC) -B$(bupdir2)/bfd/ --print-file-name=libbfd.a}
+libintl:=${shell $(CC) -B$(bupdir2)/intl/ --print-file-name=libintl.a}
+build_dumper:=${shell test -r $(libbfd) -a -r $(libintl) -a -n "$(LIBICONV)" && echo 1}
+
+libz:=${shell x=$$($(CC) -mno-cygwin --print-file-name=libz.a); cd $$(dirname $$x); dir=$$(pwd); case "$$dir" in *mingw*) echo $$dir/libz.a ;; esac}
+zlib_h:=-include ${patsubst %/lib/mingw/libz.a,%/include/zlib.h,${patsubst %/lib/libz.a,%/include/zlib.h,$(libz)}}
+zconf_h:=${patsubst %/zlib.h,%/zconf.h,$(zlib_h)}
+ifeq "${libz}" ""
+zlib_h:=
+zconf_h:=
+libz:=
+endif
+
+DUMPER_INCLUDES:=-I$(bupdir2)/bfd -I$(updir1)/include
+
+libcygwin:=$(cygwin_build)/libcygwin.a
+libuser32:=$(w32api_lib)/libuser32.a
+libkernel32:=$(w32api_lib)/libkernel32.a
+ALL_DEP_LDLIBS:=$(libcygwin) $(w32api_lib)/libnetapi32.a \
+ $(w32api_lib)/libadvapi32.a $(w32api_lib)/libkernel32.a \
+ $(w32api_lib)/libuser32.a
+
+ALL_LDLIBS:=${patsubst $(w32api_lib)/lib%.a,-l%,\
+ ${filter-out $(libuser32),\
+ ${filter-out $(libkernel32),\
+ ${filter-out $(libcygwin), $(ALL_DEP_LDLIBS)}}}}
+
+MINGW_LIB:=$(mingw_build)/libmingw32.a
+DUMPER_LIB:=${libbfd} ${libintl} -L$(bupdir1)/libiberty $(LIBICONV) -liberty
+MINGW_LDLIBS:=${filter-out $(libcygwin),$(ALL_LDLIBS) $(MINGW_LIB)}
+MINGW_DEP_LDLIBS:=${ALL_DEP_LDLIBS} ${MINGW_LIB}
+ALL_LDFLAGS:=-B$(newlib_build)/libc -B$(w32api_lib) $(LDFLAGS) $(ALL_LDLIBS)
+DUMPER_LDFLAGS:=$(ALL_LDFLAGS) $(DUMPER_LIB)
+MINGW_CXX:=${patsubst %/cygwin/include,%/mingw/include,${filter-out -I$(newlib_source)/%,$(COMPILE_CXX)}} -I$(updir)
+
+PROGS:= cygcheck.exe cygpath.exe getfacl.exe kill.exe mkgroup.exe \
+ mkpasswd.exe mount.exe passwd.exe ps.exe regtool.exe setfacl.exe \
+ setmetamode.exe ssp.exe strace.exe umount.exe ipcrm.exe ipcs.exe
+
+CLEAN_PROGS:=$(PROGS)
+ifndef build_dumper
+PROGS:=warn_dumper $(PROGS)
+else
+PROGS+=dumper$(EXEEXT)
+CLEAN_PROGS+=dumper.exe
+endif
+
+.SUFFIXES:
+.NOEXPORT:
+
+.PHONY: all install clean realclean warn_dumper
+
+all: Makefile $(PROGS)
+
+strace.exe: strace.o path.o $(MINGW_DEP_LDLIBS)
+ifdef VERBOSE
+ $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,2,$^} -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,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS)
+endif
+
+cygcheck.exe: cygcheck.o bloda.o path.o dump_setup.o $(MINGW_DEP_LDLIBS)
+ifeq "$(libz)" ""
+ @echo '*** Building cygcheck without package content checking due to missing mingw libz.a.'
+endif
+ifdef VERBOSE
+ $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,4,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) -lntdll
+else
+ @echo $(CXX) -o $@ ${wordlist 1,4,$^} ${filter-out -B%, $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS)} $(libz) -lntdll;\
+ $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,4,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) -lntdll
+endif
+
+dumper.o: dumper.cc dumper.h
+ifdef VERBOSE
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $@ $(DUMPER_INCLUDES) ${firstword $^}
+else
+ @echo $(CXX) $c $(CFLAGS) $(DUMPER_INCLUDES) ... $(basename $@).cc;\
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $(@D)/$(basename $@)$o $(DUMPER_INCLUDES) $<
+endif
+
+module_info.o: module_info.cc
+ifdef VERBOSE
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $@ $(DUMPER_INCLUDES) ${firstword $^}
+else
+ @echo $(CXX) $c $(CFLAGS) $(DUMPER_INCLUDES) ... $(basename $@).cc;\
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $(@D)/$(basename $@)$o $(DUMPER_INCLUDES) $<
+endif
+
+parse_pe.o: parse_pe.cc dumper.h
+ifdef VERBOSE
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $@ $(DUMPER_INCLUDES) ${firstword $^}
+else
+ @echo $(CXX) $c $(CFLAGS) $(DUMPER_INCLUDES) ... $(basename $@).cc;\
+ ${filter-out -nostdinc,$(COMPILE_CXX)} $c -o $(@D)/$(basename $@)$o $(DUMPER_INCLUDES) $<
+endif
+
+path.o: path.cc
+ifdef VERBOSE
+ $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) $<
+else
+ @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\
+ ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) $<
+endif
+
+dump_setup.o: dump_setup.cc
+ifdef VERBOSE
+ $(MINGW_CXX) $(zconf_h) $(zlib_h) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) $<
+else
+ @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\
+ $(MINGW_CXX) $(zconf_h) $(zlib_h) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) $<
+endif
+
+bloda.o: bloda.cc
+ifdef VERBOSE
+ ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+else
+ @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\
+ ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+endif
+
+cygcheck.o: cygcheck.cc
+ifdef VERBOSE
+ ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+else
+ @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\
+ ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+endif
+
+strace.o: strace.cc
+ifdef VERBOSE
+ $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+else
+ @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\
+ $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $<
+endif
+
+kill.exe: kill.o $(bupdir1)/libiberty/strsignal.o
+ifdef VERBOSE
+ $(CXX) -o $@ $^ -B$(cygwin_build)/ $(ALL_LDFLAGS) $(KILL_LIB)
+else
+ @echo $(CXX) -o $@ $^ ${filter-out -B%, $(ALL_LDFLAGS)};\
+ $(CXX) -o $@ $^ -B$(cygwin_build)/ $(ALL_LDFLAGS) $(KILL_LIB)
+endif
+
+clean:
+ rm -f *.o $(CLEAN_PROGS)
+
+realclean: clean
+ rm -f Makefile config.cache
+
+install: all
+ $(SHELL) $(updir1)/mkinstalldirs $(bindir)
+ for i in $(PROGS) ; do \
+ n=`echo $$i | sed '$(program_transform_name)'`; \
+ $(INSTALL_PROGRAM) $$i $(bindir)/$$n; \
+ done
+
+$(cygwin_build)/libcygwin.a: $(cygwin_build)/Makefile
+ @$(MAKE) -C $(@D) $(@F)
+
+$(mingw_build)/libmingw32.a: $(mingw_build)/Makefile
+ @$(MAKE) -C $(@D) $(@F)
+
+warn_dumper:
+ @echo '*** Not building dumper.exe since some required libraries are'
+ @echo '*** missing: libbfd.a and libintl.a.'
+ @echo '*** If you need this program, check out the naked-bfd and naked-intl'
+ @echo '*** sources from sources.redhat.com. Then, configure and build these'
+ @echo '*** libraries. Otherwise, you can safely ignore this warning.'
+
+dumper.exe: module_info.o parse_pe.o dumper.o $(ALL_DEP_LDLIBS)
+ifdef VERBOSE
+ $(CXX) -o $@ ${wordlist 1,3,$^} -B$(cygwin_build)/ $(DUMPER_LDFLAGS)
+else
+ @echo $(CXX) -o $@ ${wordlist 1,3,$^} ${filter-out -B%, $(DUMPER_LDFLAGS)};\
+ $(CXX) -o $@ ${wordlist 1,3,$^} -B$(cygwin_build)/ $(DUMPER_LDFLAGS)
+endif
+
+%.exe: %.o $(ALL_DEP_LDLIBS)
+ifdef VERBOSE
+ $(CXX) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS)
+else
+ @echo $(CXX) -o $@ ${firstword $^} ... ${filter-out -B%, $(ALL_LDFLAGS)};\
+ $(CXX) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS)
+endif
diff --git a/winsup/utils/bloda.cc b/winsup/utils/bloda.cc
new file mode 100644
index 00000000000..52aa67c941f
--- /dev/null
+++ b/winsup/utils/bloda.cc
@@ -0,0 +1,410 @@
+/* bloda.cc
+
+ Copyright 2007 Red Hat, Inc.
+
+ 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. */
+
+#define cygwin_internal cygwin_internal_dontuse
+#include <stdio.h>
+#include <assert.h>
+#include <windows.h>
+#include <ntdef.h>
+#include <ddk/ntstatus.h>
+#include <ddk/ntapi.h>
+#undef cygwin_internal
+
+#undef DEBUGGING
+#ifdef DEBUGGING
+#define dbg_printf(ARGS) printf ARGS ; fflush (NULL)
+#else /* !DEBUGGING */
+#define dbg_printf(ARGS) do { } while (0)
+#endif /* ?DEBUGGING */
+
+/* This module detects applications from the Big List of Dodgy Apps,
+ a list of applications that have at some given time been shown to
+ interfere with the operation of cygwin. It detects the presence of
+ applications on the system by looking for any of four traces an
+ installation might leave: 1) registry keys, 2) files on disk
+ 3) running executables 4) loaded dlls or drivers.
+
+ At the time of writing, the BLODA amounts to:-
+
+ Sonic Solutions burning software containing DLA component
+ Norton/MacAffee/Symantec antivirus or antispyware
+ Logitech webcam software with "Logitech process monitor" service
+ Kerio, Agnitum or ZoneAlarm Personal Firewall
+ Iolo System Mechanic/AntiVirus/Firewall
+ LanDesk
+ Windows Defender
+ Embassy Trust Suite fingerprint reader software containing wxvault.dll
+*/
+
+enum bad_app
+{
+ SONIC, NORTON, MACAFFEE, SYMANTEC,
+ LOGITECH, KERIO, AGNITUM, ZONEALARM,
+ IOLO, LANDESK, WINDEFENDER, EMBASSYTS
+};
+
+struct bad_app_info
+{
+ enum bad_app app_id;
+ const char *details;
+ char found_it;
+};
+
+enum bad_app_det_method
+{
+ HKLMKEY, HKCUKEY, FILENAME, PROCESSNAME, HOOKDLLNAME
+};
+
+struct bad_app_det
+{
+ enum bad_app_det_method type;
+ const char *param;
+ enum bad_app app;
+};
+
+static const struct bad_app_det dodgy_app_detects[] =
+{
+ { PROCESSNAME, "dlactrlw.exe", SONIC },
+ { HOOKDLLNAME, "wxvault.dll", EMBASSYTS },
+ { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\vsdatant", ZONEALARM },
+ { FILENAME, "%windir%\\System32\\vsdatant.sys", ZONEALARM },
+ { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\lvprcsrv", LOGITECH },
+ { PROCESSNAME, "LVPrcSrv.exe", LOGITECH },
+ { FILENAME, "%programfiles%\\common files\\logitech\\lvmvfm\\LVPrcSrv.exe", LOGITECH },
+};
+
+static const size_t num_of_detects = sizeof (dodgy_app_detects) / sizeof (dodgy_app_detects[0]);
+
+static struct bad_app_info big_list_of_dodgy_apps[] =
+{
+ { SONIC, "Sonic Solutions burning software containing DLA component" },
+ { NORTON, "Norton antivirus or antispyware software" },
+ { MACAFFEE, "Macaffee antivirus or antispyware software" },
+ { SYMANTEC, "Symantec antivirus or antispyware software" },
+ { LOGITECH, "Logitech Process Monitor service" },
+ { KERIO, "Kerio Personal Firewall" },
+ { AGNITUM, "Agnitum Personal Firewall" },
+ { ZONEALARM, "ZoneAlarm Personal Firewall" },
+ { IOLO, "Iolo System Mechanic/AntiVirus/Firewall software" },
+ { LANDESK, "Landesk" },
+ { WINDEFENDER, "Windows Defender" },
+ { EMBASSYTS, "Embassy Trust Suite fingerprint reader software containing wxvault.dll" },
+};
+
+static const size_t num_of_dodgy_apps = sizeof (big_list_of_dodgy_apps) / sizeof (big_list_of_dodgy_apps[0]);
+
+/* This function is not in the ntdll export lib, so it has
+ to be looked up at runtime and called through a pointer. */
+VOID NTAPI (*pRtlFreeUnicodeString)(PUNICODE_STRING) = NULL;
+
+static PSYSTEM_PROCESSES
+get_process_list (void)
+{
+ int n_procs = 0x100;
+ PSYSTEM_PROCESSES pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist);
+
+ while (NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
+ pslist, n_procs * sizeof *pslist, 0) == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ n_procs *= 2;
+ free (pslist);
+ pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist);
+ }
+ return pslist;
+}
+
+static PSYSTEM_MODULE_INFORMATION
+get_module_list (void)
+{
+ int modsize = 0x1000;
+ PSYSTEM_MODULE_INFORMATION modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize);
+
+ while (NtQuerySystemInformation (SystemModuleInformation,
+ modlist, modsize, NULL) == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ modsize *= 2;
+ free (modlist);
+ modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize);
+ }
+ return modlist;
+}
+
+static bool
+find_process_in_list (PSYSTEM_PROCESSES pslist, PUNICODE_STRING psname)
+{
+ while (1)
+ {
+ if (pslist->ProcessName.Length && pslist->ProcessName.Buffer)
+ {
+ dbg_printf (("%S\n", pslist->ProcessName.Buffer));
+ if (!_wcsicmp (pslist->ProcessName.Buffer, psname->Buffer))
+ return true;
+ }
+ if (!pslist->NextEntryDelta)
+ break;
+ pslist = (PSYSTEM_PROCESSES)(pslist->NextEntryDelta + (char *)pslist);
+ };
+ return false;
+}
+
+static bool
+find_module_in_list (PSYSTEM_MODULE_INFORMATION modlist, const char * const modname)
+{
+ PSYSTEM_MODULE_INFORMATION_ENTRY modptr = &modlist->Module[0];
+ DWORD count = modlist->Count;
+ while (count--)
+ {
+ dbg_printf (("name '%s' offset %d ", &modptr->ImageName[0], modptr->PathLength));
+ dbg_printf (("= '%s'\n", &modptr->ImageName[modptr->PathLength]));
+ if (!_stricmp (&modptr->ImageName[modptr->PathLength], modname))
+ return true;
+ modptr++;
+ }
+ return false;
+}
+
+static bool
+expand_path (const char *path, char *outbuf)
+{
+ char *dst = outbuf;
+ const char *end, *envval;
+ char envvar[MAX_PATH];
+ size_t len;
+
+ while ((dst - outbuf) < MAX_PATH)
+ {
+ if (*path != '%')
+ {
+ if ((*dst++ = *path++) != 0)
+ continue;
+ break;
+ }
+ /* Expand an environ var. */
+ end = path + 1;
+ while (*end != '%')
+ {
+ /* Watch out for unterminated % */
+ if (*end++ == 0)
+ {
+ end = NULL;
+ break;
+ }
+ }
+ /* If we didn't find the end, can't expand it. */
+ if ((end == NULL) || (end == (path + 1)))
+ {
+ /* Unterminated % so copy verbatim. */
+ *dst++ = *path++;
+ continue;
+ }
+ /* Expand the environment var into the new path. */
+ if ((end - (path + 1)) >= MAX_PATH)
+ return -1;
+ memcpy (envvar, path + 1, end - (path + 1));
+ envvar[end - (path + 1)] = 0;
+ envval = getenv (envvar);
+ /* If not found, copy env var name verbatim. */
+ if (envval == NULL)
+ {
+ *dst++ = *path++;
+ continue;
+ }
+ /* Check enough room before copying. */
+ len = strlen (envval);
+ if ((dst + len - outbuf) >= MAX_PATH)
+ return false;
+ memcpy (dst, envval, len);
+ dst += len;
+ /* And carry on past the end of env var name. */
+ path = end + 1;
+ }
+ return (dst - outbuf) < MAX_PATH;
+}
+
+static bool
+detect_dodgy_app (const struct bad_app_det *det, PSYSTEM_PROCESSES pslist, PSYSTEM_MODULE_INFORMATION modlist)
+{
+ HANDLE fh;
+ HKEY hk;
+ UNICODE_STRING unicodename;
+ ANSI_STRING ansiname;
+ NTSTATUS rv;
+ bool found;
+ char expandedname[MAX_PATH];
+
+ switch (det->type)
+ {
+ case HKLMKEY:
+ dbg_printf (("Detect reg key hklm '%s'... ", det->param));
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS)
+ {
+ RegCloseKey (hk);
+ dbg_printf (("found!\n"));
+ return true;
+ }
+ break;
+
+ case HKCUKEY:
+ dbg_printf (("Detect reg key hkcu '%s'... ", det->param));
+ if (RegOpenKeyEx (HKEY_CURRENT_USER, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS)
+ {
+ RegCloseKey (hk);
+ dbg_printf (("found!\n"));
+ return true;
+ }
+ break;
+
+ case FILENAME:
+ dbg_printf (("Detect filename '%s'... ", det->param));
+ if (!expand_path (det->param, expandedname))
+ {
+ printf ("Expansion failure!\n");
+ break;
+ }
+ dbg_printf (("('%s' after expansion)... ", expandedname));
+ fh = CreateFile (expandedname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
+ if (fh != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (fh);
+ dbg_printf (("found!\n"));
+ return true;
+ }
+ break;
+
+ case PROCESSNAME:
+ dbg_printf (("Detect proc name '%s'... ", det->param));
+ /* Equivalent of RtlInitAnsiString. */
+ ansiname.Length = ansiname.MaximumLength = strlen (det->param);
+ ansiname.Buffer = (CHAR *) det->param;
+ rv = RtlAnsiStringToUnicodeString (&unicodename, &ansiname, TRUE);
+ if (rv != STATUS_SUCCESS)
+ {
+ printf ("Ansi to unicode conversion failure $%08x\n", (unsigned int) rv);
+ break;
+ }
+ found = find_process_in_list (pslist, &unicodename);
+ if (!pRtlFreeUnicodeString)
+ pRtlFreeUnicodeString = (VOID NTAPI (*)(PUNICODE_STRING)) GetProcAddress (LoadLibrary ("ntdll.dll"), "RtlFreeUnicodeString");
+ if (pRtlFreeUnicodeString)
+ pRtlFreeUnicodeString (&unicodename);
+ else
+ printf ("leaking mem...oops\n");
+ if (found)
+ {
+ dbg_printf (("found!\n"));
+ return true;
+ }
+ break;
+
+ case HOOKDLLNAME:
+ dbg_printf (("Detect hookdll '%s'... ", det->param));
+ if (find_module_in_list (modlist, det->param))
+ {
+ dbg_printf (("found!\n"));
+ return true;
+ }
+ break;
+
+ }
+ dbg_printf (("not found.\n"));
+ return false;
+}
+
+static struct bad_app_info *
+find_dodgy_app_info (enum bad_app which_app)
+{
+ size_t i;
+ for (i = 0; i < num_of_dodgy_apps; i++)
+ {
+ if (big_list_of_dodgy_apps[i].app_id == which_app)
+ return &big_list_of_dodgy_apps[i];
+ }
+ return NULL;
+}
+
+/* External entrypoint called from cygcheck.cc/dump_sysinfo. */
+void
+dump_dodgy_apps (int verbose)
+{
+ size_t i, n_det = 0;
+ PSYSTEM_PROCESSES pslist;
+ PSYSTEM_MODULE_INFORMATION modlist;
+
+ /* Read system info for detect testing. */
+ pslist = get_process_list ();
+ modlist = get_module_list ();
+
+ /* Go with builtin list for now; later may enhance to
+ read dodgy apps from a file or download from an URL. */
+ for (i = 0; i < num_of_dodgy_apps; i++)
+ {
+ big_list_of_dodgy_apps[i].found_it = false;
+ }
+
+ for (i = 0; i < num_of_detects; i++)
+ {
+ const struct bad_app_det *det = &dodgy_app_detects[i];
+ struct bad_app_info *found = find_dodgy_app_info (det->app);
+ bool detected = detect_dodgy_app (det, pslist, modlist);
+
+ /* Not found would mean we coded the lists bad. */
+ assert (found);
+ if (detected)
+ {
+ ++n_det;
+ found->found_it |= (1 << det->type);
+ }
+ }
+ if (n_det)
+ {
+ printf ("\nPotential app conflicts:\n\n");
+ for (i = 0; i < num_of_dodgy_apps; i++)
+ {
+ if (big_list_of_dodgy_apps[i].found_it)
+ {
+ printf ("%s%s", big_list_of_dodgy_apps[i].details,
+ verbose ? "\nDetected: " : ".\n");
+ if (!verbose)
+ continue;
+ const char *sep = "";
+ if (big_list_of_dodgy_apps[i].found_it & (1 << HKLMKEY))
+ {
+ printf ("HKLM Registry Key");
+ sep = ", ";
+ }
+ if (big_list_of_dodgy_apps[i].found_it & (1 << HKCUKEY))
+ {
+ printf ("%sHKCU Registry Key", sep);
+ sep = ", ";
+ }
+ if (big_list_of_dodgy_apps[i].found_it & (1 << FILENAME))
+ {
+ printf ("%sNamed file", sep);
+ sep = ", ";
+ }
+ if (big_list_of_dodgy_apps[i].found_it & (1 << PROCESSNAME))
+ {
+ printf ("%sNamed process", sep);
+ sep = ", ";
+ }
+ if (big_list_of_dodgy_apps[i].found_it & (1 << HOOKDLLNAME))
+ {
+ printf ("%sLoaded hook DLL", sep);
+ }
+ printf (".\n\n");
+ }
+ }
+ }
+ /* Tidy up allocations. */
+ free (pslist);
+ free (modlist);
+}
+
diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc
new file mode 100644
index 00000000000..3c63913f7b1
--- /dev/null
+++ b/winsup/utils/cygcheck.cc
@@ -0,0 +1,1958 @@
+/* cygcheck.cc
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006 Red Hat, Inc.
+
+ 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. */
+
+#define cygwin_internal cygwin_internal_dontuse
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <io.h>
+#include <windows.h>
+#include <wininet.h>
+#include "path.h"
+#include <getopt.h>
+#include "cygwin/include/sys/cygwin.h"
+#include "cygwin/include/mntent.h"
+#undef cygwin_internal
+
+#define alloca __builtin_alloca
+
+int verbose = 0;
+int registry = 0;
+int sysinfo = 0;
+int givehelp = 0;
+int keycheck = 0;
+int check_setup = 0;
+int dump_only = 0;
+int find_package = 0;
+int list_package = 0;
+int grep_packages = 0;
+
+/* This is global because it's used in both internet_display_error as well
+ as package_grep. */
+BOOL (WINAPI *pInternetCloseHandle) (HINTERNET);
+
+#ifdef __GNUC__
+typedef long long longlong;
+#else
+typedef __int64 longlong;
+#endif
+
+/* In dump_setup.cc */
+void dump_setup (int, char **, bool);
+void package_find (int, char **);
+void package_list (int, char **);
+/* In bloda.cc */
+void dump_dodgy_apps (int verbose);
+
+
+static const char version[] = "$Revision$";
+
+static const char *known_env_vars[] = {
+ "c_include_path",
+ "compiler_path",
+ "cxx_include_path",
+ "cygwin",
+ "cygwin32",
+ "dejagnu",
+ "expect",
+ "gcc_default_options",
+ "gcc_exec_prefix",
+ "home",
+ "ld_library_path",
+ "library_path",
+ "login",
+ "lpath",
+ "make_mode",
+ "makeflags",
+ "path",
+ "pwd",
+ "strace",
+ "tcl_library",
+ "user",
+ 0
+};
+
+struct
+{
+ const char *name;
+ int missing_is_good;
+}
+static common_apps[] = {
+ {"awk", 0},
+ {"bash", 0},
+ {"cat", 0},
+ {"cp", 0},
+ {"cpp", 1},
+ {"crontab", 0},
+ {"find", 0},
+ {"gcc", 0},
+ {"gdb", 0},
+ {"grep", 0},
+ {"kill", 0},
+ {"ld", 0},
+ {"ls", 0},
+ {"make", 0},
+ {"mv", 0},
+ {"patch", 0},
+ {"perl", 0},
+ {"rm", 0},
+ {"sed", 0},
+ {"ssh", 0},
+ {"sh", 0},
+ {"tar", 0},
+ {"test", 0},
+ {"vi", 0},
+ {"vim", 0},
+ {0, 0}
+};
+
+static int num_paths, max_paths;
+static char **paths;
+int first_nonsys_path;
+
+void
+eprintf (const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+}
+
+/*
+ * display_error() is used to report failure modes
+ */
+static int
+display_error (const char *name, bool show_error = true, bool print_failed = true)
+{
+ if (show_error)
+ fprintf (stderr, "cygcheck: %s%s: %lu\n", name,
+ print_failed ? " failed" : "", GetLastError ());
+ else
+ fprintf (stderr, "cygcheck: %s%s\n", name,
+ print_failed ? " failed" : "");
+ return 1;
+}
+
+/* Display a WinInet error message, and close a variable number of handles.
+ (Passed a list of handles terminated by NULL.) */
+static int
+display_internet_error (const char *message, ...)
+{
+ DWORD err = GetLastError ();
+ TCHAR err_buf[256];
+ va_list hptr;
+ HINTERNET h;
+
+ /* in the case of a successful connection but 404 response, there is no
+ win32 error message, but we still get passed a message to display. */
+ if (err)
+ {
+ if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE,
+ GetModuleHandle ("wininet.dll"), err, 0, err_buf,
+ sizeof (err_buf), NULL) == 0)
+ strcpy (err_buf, "(Unknown error)");
+
+ fprintf (stderr, "cygcheck: %s: %s (win32 error %d)\n", message,
+ err_buf, err);
+ }
+ else
+ fprintf (stderr, "cygcheck: %s\n", message);
+
+ va_start (hptr, message);
+ while ((h = va_arg (hptr, HINTERNET)) != 0)
+ pInternetCloseHandle (h);
+ va_end (hptr);
+
+ return 1;
+}
+
+static void
+add_path (char *s, int maxlen)
+{
+ if (num_paths >= max_paths)
+ {
+ max_paths += 10;
+ if (paths)
+ paths = (char **) realloc (paths, max_paths * sizeof (char *));
+ else
+ paths = (char **) malloc (max_paths * sizeof (char *));
+ }
+ paths[num_paths] = (char *) malloc (maxlen + 1);
+ if (paths[num_paths] == NULL)
+ {
+ display_error ("add_path: malloc()");
+ return;
+ }
+ memcpy (paths[num_paths], s, maxlen);
+ paths[num_paths][maxlen] = 0;
+ char *e = paths[num_paths] + strlen (paths[num_paths]);
+ if (e[-1] == '\\' && e[-2] != ':')
+ *--e = 0;
+ for (int i = 1; i < num_paths; i++)
+ if (strcasecmp (paths[num_paths], paths[i]) == 0)
+ {
+ free (paths[num_paths]);
+ return;
+ }
+ num_paths++;
+}
+
+static void
+init_paths ()
+{
+ char tmp[4000], *sl;
+ add_path ((char *) ".", 1); /* to be replaced later */
+
+ if (GetCurrentDirectory (4000, tmp))
+ add_path (tmp, strlen (tmp));
+ else
+ display_error ("init_paths: GetCurrentDirectory()");
+
+ if (GetSystemDirectory (tmp, 4000))
+ add_path (tmp, strlen (tmp));
+ else
+ display_error ("init_paths: GetSystemDirectory()");
+ sl = strrchr (tmp, '\\');
+ if (sl)
+ {
+ strcpy (sl, "\\SYSTEM");
+ add_path (tmp, strlen (tmp));
+ }
+ GetWindowsDirectory (tmp, 4000);
+ add_path (tmp, strlen (tmp));
+ first_nonsys_path = num_paths;
+
+ char *wpath = getenv ("PATH");
+ if (!wpath)
+ fprintf (stderr, "WARNING: PATH is not set at all!\n");
+ else
+ {
+ char *b, *e;
+ b = wpath;
+ while (1)
+ {
+ for (e = b; *e && *e != ';'; e++);
+ if (strncmp(b, ".", 1) && strncmp(b, ".\\", 2))
+ add_path (b, e - b);
+ if (!*e)
+ break;
+ b = e + 1;
+ }
+ }
+}
+
+static char *
+find_on_path (char *file, char *default_extension,
+ int showall = 0, int search_sysdirs = 0)
+{
+ static char rv[4000];
+ char tmp[4000], *ptr = rv;
+
+ if (!file)
+ {
+ display_error ("find_on_path: NULL pointer for file", false, false);
+ return 0;
+ }
+
+ if (default_extension == NULL)
+ {
+ display_error ("find_on_path: NULL pointer for default_extension", false, false);
+ return 0;
+ }
+
+ if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/'))
+ {
+ char *fn = cygpath (file, NULL);
+ if (access (fn, F_OK) == 0)
+ return fn;
+ strcpy (rv, fn);
+ strcat (rv, default_extension);
+ return access (rv, F_OK) == 0 ? strdup (rv) : fn;
+ }
+
+ if (strchr (file, '.'))
+ default_extension = (char *) "";
+
+ for (int i = search_sysdirs ? 0 : first_nonsys_path; i < num_paths; i++)
+ {
+ if (i == 0 || !search_sysdirs || strcasecmp (paths[i], paths[0]))
+ {
+ sprintf (ptr, "%s\\%s%s", paths[i], file, default_extension);
+ if (GetFileAttributes (ptr) != (DWORD) - 1)
+ {
+ if (showall)
+ printf ("Found: %s\n", ptr);
+ if (ptr == tmp && verbose)
+ printf ("Warning: %s hides %s\n", rv, ptr);
+ ptr = tmp;
+ }
+ }
+ }
+
+ if (ptr == tmp)
+ return rv;
+
+ return 0;
+}
+
+#define DID_NEW 1
+#define DID_ACTIVE 2
+#define DID_INACTIVE 3
+
+struct Did
+{
+ Did *next;
+ char *file;
+ int state;
+};
+static Did *did = 0;
+
+static Did *
+already_did (char *file)
+{
+ Did *d;
+ for (d = did; d; d = d->next)
+ if (strcasecmp (d->file, file) == 0)
+ return d;
+ d = (Did *) malloc (sizeof (Did));
+ d->file = strdup (file);
+ d->next = did;
+ d->state = DID_NEW;
+ did = d;
+ return d;
+}
+
+static int
+get_word (HANDLE fh, int offset)
+{
+ short rv;
+ unsigned r;
+
+ if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
+ && GetLastError () != NO_ERROR)
+ display_error ("get_word: SetFilePointer()");
+
+ if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0))
+ display_error ("get_word: Readfile()");
+
+ return rv;
+}
+
+static int
+get_dword (HANDLE fh, int offset)
+{
+ int rv;
+ unsigned r;
+
+ if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
+ && GetLastError () != NO_ERROR)
+ display_error ("get_dword: SetFilePointer()");
+
+ if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0))
+ display_error ("get_dword: Readfile()");
+
+ return rv;
+}
+
+struct Section
+{
+ char name[8];
+ int virtual_size;
+ int virtual_address;
+ int size_of_raw_data;
+ int pointer_to_raw_data;
+};
+
+static int
+rva_to_offset (int rva, char *sections, int nsections, int *sz)
+{
+ int i;
+
+ if (sections == NULL)
+ {
+ display_error ("rva_to_offset: NULL passed for sections", true, false);
+ return 0;
+ }
+
+ for (i = 0; i < nsections; i++)
+ {
+ Section *s = (Section *) (sections + i * 40);
+#if 0
+ printf ("%08x < %08x < %08x ? %08x\n",
+ s->virtual_address, rva,
+ s->virtual_address + s->virtual_size, s->pointer_to_raw_data);
+#endif
+ if (rva >= s->virtual_address
+ && rva < s->virtual_address + s->virtual_size)
+ {
+ if (sz)
+ *sz = s->virtual_address + s->virtual_size - rva;
+ return rva - s->virtual_address + s->pointer_to_raw_data;
+ }
+ }
+ return 0; /* punt */
+}
+
+struct ExpDirectory
+{
+ int flags;
+ int timestamp;
+ short major_ver;
+ short minor_ver;
+ int name_rva;
+};
+
+struct ImpDirectory
+{
+ unsigned characteristics;
+ unsigned timestamp;
+ unsigned forwarder_chain;
+ unsigned name_rva;
+ unsigned iat_rva;
+};
+
+
+static bool track_down (char *file, char *suffix, int lvl);
+
+#define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
+static void
+cygwin_info (HANDLE h)
+{
+ char *buf, *bufend, *buf_start = NULL;
+ const char *hello = " Cygwin DLL version info:\n";
+ DWORD size = GetFileSize (h, NULL);
+ DWORD n;
+
+ if (size == 0xffffffff)
+ return;
+
+ buf_start = buf = (char *) calloc (1, size + 1);
+ if (buf == NULL)
+ {
+ display_error ("cygwin_info: calloc()");
+ return;
+ }
+
+ (void) SetFilePointer (h, 0, NULL, FILE_BEGIN);
+ if (!ReadFile (h, buf, size, &n, NULL))
+ {
+ free (buf_start);
+ return;
+ }
+
+ static char dummy[] = "\0\0\0\0\0\0\0";
+ char *dll_major = dummy;
+ bufend = buf + size;
+ while (buf < bufend)
+ if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL)
+ break;
+ else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0)
+ buf++;
+ else
+ {
+ char *p = strchr (buf += CYGPREFIX, '\n');
+ if (!p)
+ break;
+ 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 = "";
+ }
+
+ if (!*hello)
+ puts ("");
+
+ free (buf_start);
+ return;
+}
+
+static void
+dll_info (const char *path, HANDLE fh, int lvl, int recurse)
+{
+ DWORD junk;
+ int i;
+ int pe_header_offset = get_dword (fh, 0x3c);
+ int opthdr_ofs = pe_header_offset + 4 + 20;
+ unsigned short v[6];
+
+ if (path == NULL)
+ {
+ display_error ("dll_info: NULL passed for path", true, false);
+ return;
+ }
+
+ if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) ==
+ INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
+ display_error ("dll_info: SetFilePointer()");
+
+ if (!ReadFile (fh, &v, sizeof (v), &junk, 0))
+ display_error ("dll_info: Readfile()");
+
+ if (verbose)
+ printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
+ v[0], v[1], v[2], v[3], v[4], v[5]);
+ else
+ printf ("\n");
+
+ int num_entries = get_dword (fh, opthdr_ofs + 92);
+ int export_rva = get_dword (fh, opthdr_ofs + 96);
+ int export_size = get_dword (fh, opthdr_ofs + 100);
+ int import_rva = get_dword (fh, opthdr_ofs + 104);
+ int import_size = get_dword (fh, opthdr_ofs + 108);
+
+ int nsections = get_word (fh, pe_header_offset + 4 + 2);
+ char *sections = (char *) malloc (nsections * 40);
+
+ if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
+ get_word (fh, pe_header_offset + 4 + 16), 0,
+ FILE_BEGIN) == INVALID_SET_FILE_POINTER
+ && GetLastError () != NO_ERROR)
+ display_error ("dll_info: SetFilePointer()");
+
+ if (!ReadFile (fh, sections, nsections * 40, &junk, 0))
+ display_error ("dll_info: Readfile()");
+
+ if (verbose && num_entries >= 1 && export_size > 0)
+ {
+ int expsz;
+ int expbase = rva_to_offset (export_rva, sections, nsections, &expsz);
+
+ if (expbase)
+ {
+ if (SetFilePointer (fh, expbase, 0, FILE_BEGIN) ==
+ INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
+ display_error ("dll_info: SetFilePointer()");
+
+ unsigned char *exp = (unsigned char *) malloc (expsz);
+
+ if (!ReadFile (fh, exp, expsz, &junk, 0))
+ display_error ("dll_info: Readfile()");
+
+ ExpDirectory *ed = (ExpDirectory *) exp;
+ int ofs = ed->name_rva - export_rva;
+ struct tm *tm = localtime ((const time_t *) &(ed->timestamp));
+ if (tm->tm_year < 60)
+ tm->tm_year += 2000;
+ if (tm->tm_year < 200)
+ tm->tm_year += 1900;
+ printf ("%*c", lvl + 2, ' ');
+ printf ("\"%s\" v%d.%d ts=", exp + ofs,
+ ed->major_ver, ed->minor_ver);
+ printf ("%d/%d/%d %d:%02d\n",
+ tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ }
+ }
+
+ if (num_entries >= 2 && import_size > 0 && recurse)
+ {
+ int impsz;
+ int impbase = rva_to_offset (import_rva, sections, nsections, &impsz);
+ if (impbase)
+ {
+ if (SetFilePointer (fh, impbase, 0, FILE_BEGIN) ==
+ INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
+ display_error ("dll_info: SetFilePointer()");
+
+ unsigned char *imp = (unsigned char *) malloc (impsz);
+ if (imp == NULL)
+ {
+ display_error ("dll_info: malloc()");
+ return;
+ }
+
+ if (!ReadFile (fh, imp, impsz, &junk, 0))
+ display_error ("dll_info: Readfile()");
+
+ ImpDirectory *id = (ImpDirectory *) imp;
+ for (i = 0; id[i].name_rva; i++)
+ {
+ /* int ofs = id[i].name_rva - import_rva; */
+ track_down ((char *) imp + id[i].name_rva - import_rva,
+ (char *) ".dll", lvl + 2);
+ }
+ }
+ }
+ if (strstr (path, "\\cygwin1.dll"))
+ cygwin_info (fh);
+}
+
+// Return true on success, false if error printed
+static bool
+track_down (char *file, char *suffix, int lvl)
+{
+ if (file == NULL)
+ {
+ display_error ("track_down: NULL passed for file", true, false);
+ return false;
+ }
+
+ if (suffix == NULL)
+ {
+ display_error ("track_down: NULL passed for suffix", false, false);
+ return false;
+ }
+
+ char *path = find_on_path (file, suffix, 0, 1);
+ if (!path)
+ {
+ printf ("Error: could not find %s\n", file);
+ return false;
+ }
+
+ Did *d = already_did (file);
+ switch (d->state)
+ {
+ case DID_NEW:
+ break;
+ case DID_ACTIVE:
+ if (verbose)
+ {
+ if (lvl)
+ printf ("%*c", lvl, ' ');
+ printf ("%s", path);
+ printf (" (recursive)\n");
+ }
+ return true;
+ case DID_INACTIVE:
+ if (verbose)
+ {
+ if (lvl)
+ printf ("%*c", lvl, ' ');
+ printf ("%s", path);
+ printf (" (already done)\n");
+ }
+ return true;
+ default:
+ break;
+ }
+
+ if (lvl)
+ printf ("%*c", lvl, ' ');
+
+ if (!path)
+ {
+ printf ("%s not found\n", file);
+ return false;
+ }
+
+ printf ("%s", path);
+
+ HANDLE fh =
+ CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fh == INVALID_HANDLE_VALUE)
+ {
+ printf (" - Cannot open\n");
+ return false;
+ }
+
+ d->state = DID_ACTIVE;
+
+ dll_info (path, fh, lvl, 1);
+ d->state = DID_INACTIVE;
+ if (!CloseHandle (fh))
+ display_error ("track_down: CloseHandle()");
+ return true;
+}
+
+static void
+ls (char *f)
+{
+ HANDLE h = CreateFile (f, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ BY_HANDLE_FILE_INFORMATION info;
+
+ if (!GetFileInformationByHandle (h, &info))
+ display_error ("ls: GetFileInformationByHandle()");
+
+ SYSTEMTIME systime;
+
+ if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime))
+ display_error ("ls: FileTimeToSystemTime()");
+ printf ("%5dk %04d/%02d/%02d %s",
+ (((int) info.nFileSizeLow) + 512) / 1024,
+ systime.wYear, systime.wMonth, systime.wDay, f);
+ dll_info (f, h, 16, 0);
+ if (!CloseHandle (h))
+ display_error ("ls: CloseHandle()");
+}
+
+// Return true on success, false if error printed
+static bool
+cygcheck (char *app)
+{
+ char *papp = find_on_path (app, (char *) ".exe", 1, 0);
+ if (!papp)
+ {
+ printf ("Error: could not find %s\n", app);
+ return false;
+ }
+ char *s = strdup (papp);
+ char *sl = 0, *t;
+ for (t = s; *t; t++)
+ if (*t == '/' || *t == '\\' || *t == ':')
+ sl = t;
+ if (sl == 0)
+ paths[0] = (char *) ".";
+ else
+ {
+ *sl = 0;
+ paths[0] = s;
+ }
+ did = 0;
+ return track_down (papp, (char *) ".exe", 0);
+}
+
+
+extern char **environ;
+
+struct RegInfo
+{
+ RegInfo *prev;
+ char *name;
+ HKEY key;
+};
+
+static void
+show_reg (RegInfo * ri, int nest)
+{
+ if (!ri)
+ return;
+ show_reg (ri->prev, 1);
+ if (nest)
+ printf ("%s\\", ri->name);
+ else
+ printf ("%s\n", ri->name);
+}
+
+static void
+scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygnus)
+{
+ RegInfo ri;
+ ri.prev = prev;
+ ri.name = name;
+ ri.key = hKey;
+
+ char *cp;
+ for (cp = name; *cp; cp++)
+ if (strncasecmp (cp, "cygnus", 6) == 0)
+ cygnus = 1;
+
+ DWORD num_subkeys, max_subkey_len, num_values;
+ DWORD max_value_len, max_valdata_len, i;
+ if (RegQueryInfoKey (hKey, 0, 0, 0, &num_subkeys, &max_subkey_len, 0,
+ &num_values, &max_value_len, &max_valdata_len, 0, 0)
+ != ERROR_SUCCESS)
+ {
+#if 0
+ char tmp[400];
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (),
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0);
+ printf ("RegQueryInfoKey: %s\n", tmp);
+#endif
+ return;
+ }
+
+ if (cygnus)
+ {
+ show_reg (&ri, 0);
+
+ char *value_name = (char *) malloc (max_value_len + 1);
+ if (value_name == NULL)
+ {
+ display_error ("scan_registry: malloc()");
+ return;
+ }
+
+ char *value_data = (char *) malloc (max_valdata_len + 1);
+ if (value_data == NULL)
+ {
+ display_error ("scan_registry: malloc()");
+ return;
+ }
+
+ for (i = 0; i < num_values; i++)
+ {
+ DWORD dlen = max_valdata_len + 1;
+ DWORD nlen = max_value_len + 1;
+ DWORD type;
+ RegEnumValue (hKey, i, value_name, &nlen, 0,
+ &type, (BYTE *) value_data, &dlen);
+ {
+ printf (" %s = ", i ? value_name : "(default)");
+ switch (type)
+ {
+ case REG_DWORD:
+ printf ("0x%08x\n", *(unsigned *) value_data);
+ break;
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+ printf ("'%s'\n", value_data);
+ break;
+ default:
+ printf ("(unsupported type)\n");
+ break;
+ }
+ }
+ }
+ free (value_name);
+ free (value_data);
+ }
+
+ char *subkey_name = (char *) malloc (max_subkey_len + 1);
+ for (i = 0; i < num_subkeys; i++)
+ {
+ if (RegEnumKey (hKey, i, subkey_name, max_subkey_len + 1) ==
+ ERROR_SUCCESS)
+ {
+ HKEY sKey;
+ if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey)
+ == ERROR_SUCCESS)
+ {
+ scan_registry (&ri, sKey, subkey_name, cygnus);
+ if (RegCloseKey (sKey) != ERROR_SUCCESS)
+ display_error ("scan_registry: RegCloseKey()");
+ }
+ }
+ }
+ free (subkey_name);
+}
+
+void
+pretty_id (const char *s, char *cygwin, size_t cyglen)
+{
+ char *groups[16384];
+
+ strcpy (cygwin + cyglen++, " ");
+ strcpy (cygwin + cyglen, s);
+ putenv (cygwin);
+
+ char *id = cygpath ("/bin/id.exe", NULL);
+ for (char *p = id; (p = strchr (p, '/')); p++)
+ *p = '\\';
+
+ if (access (id, X_OK))
+ {
+ fprintf (stderr, "'id' program not found\n");
+ return;
+ }
+
+ FILE *f = popen (id, "rt");
+
+ char buf[16384];
+ buf[0] = '\0';
+ fgets (buf, sizeof (buf), f);
+ pclose (f);
+ char *uid = strtok (buf, ")");
+ if (uid)
+ uid += strlen ("uid=");
+ else
+ {
+ fprintf (stderr, "garbled output from 'id' command - no uid= found\n");
+ return;
+ }
+ char *gid = strtok (NULL, ")");
+ if (gid)
+ gid += strlen ("gid=") + 1;
+ else
+ {
+ fprintf (stderr, "garbled output from 'id' command - no gid= found\n");
+ return;
+ }
+
+ char **ng = groups - 1;
+ size_t len_uid = strlen ("UID: )") + strlen (uid);
+ size_t len_gid = strlen ("GID: )") + strlen (gid);
+ *++ng = groups[0] = (char *) alloca (len_uid + 1);
+ *++ng = groups[1] = (char *) alloca (len_gid + 1);
+ sprintf (groups[0], "UID: %s)", uid);
+ sprintf (groups[1], "GID: %s)", gid);
+ size_t sz = max (len_uid, len_gid);
+ while ((*++ng = strtok (NULL, ",")))
+ {
+ char *p = strchr (*ng, '\n');
+ if (p)
+ *p = '\0';
+ if (ng == groups + 2)
+ *ng += strlen (" groups=");
+ size_t len = strlen (*ng);
+ if (sz < len)
+ sz = len;
+ }
+ ng--;
+
+ printf ("\nOutput from %s (%s)\n", id, s);
+ int n = 80 / (int) ++sz;
+ int i = n > 2 ? n - 2 : 0;
+ sz = -sz;
+ for (char **g = groups; g <= ng; g++)
+ if ((g != ng) && (++i < n))
+ printf ("%*s", sz, *g);
+ else
+ {
+ puts (*g);
+ i = 0;
+ }
+}
+
+/* This dumps information about each installed cygwin service, if cygrunsrv
+ is available. */
+void
+dump_sysinfo_services ()
+{
+ char buf[1024];
+ char buf2[1024];
+ FILE *f;
+ bool no_services = false;
+
+ if (givehelp)
+ printf ("\nChecking for any Cygwin services... %s\n\n",
+ verbose ? "" : "(use -v for more detail)");
+ else
+ fputc ('\n', stdout);
+
+ /* find the location of cygrunsrv.exe */
+ char *cygrunsrv = cygpath ("/bin/cygrunsrv.exe", NULL);
+ for (char *p = cygrunsrv; (p = strchr (p, '/')); p++)
+ *p = '\\';
+
+ if (access (cygrunsrv, X_OK))
+ {
+ puts ("Can't find the cygrunsrv utility, skipping services check.\n");
+ return;
+ }
+
+ /* check for a recent cygrunsrv */
+ snprintf (buf, sizeof (buf), "%s --version", cygrunsrv);
+ if ((f = popen (buf, "rt")) == NULL)
+ {
+ printf ("Failed to execute '%s', skipping services check.\n", buf);
+ return;
+ }
+ int maj, min;
+ int ret = fscanf (f, "cygrunsrv V%u.%u", &maj, &min);
+ if (ferror (f) || feof (f) || ret == EOF || maj < 1 || min < 10)
+ {
+ puts ("The version of cygrunsrv installed is too old to dump service info.\n");
+ return;
+ }
+ fclose (f);
+
+ /* For verbose mode, just run cygrunsrv --list --verbose and copy output
+ verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
+ each service. */
+ snprintf (buf, sizeof (buf), (verbose ? "%s --list --verbose" : "%s --list"),
+ cygrunsrv);
+ if ((f = popen (buf, "rt")) == NULL)
+ {
+ printf ("Failed to execute '%s', skipping services check.\n", buf);
+ return;
+ }
+
+ if (verbose)
+ {
+ /* copy output to stdout */
+ size_t nchars = 0;
+ while (!feof (f) && !ferror (f))
+ nchars += fwrite ((void *) buf, 1,
+ fread ((void *) buf, 1, sizeof (buf), f), stdout);
+
+ /* cygrunsrv outputs nothing if there are no cygwin services found */
+ if (nchars < 1)
+ no_services = true;
+ pclose (f);
+ }
+ else
+ {
+ /* read the output of --list, and then run --query for each service */
+ size_t nchars = fread ((void *) buf, 1, sizeof (buf) - 1, f);
+ buf[nchars] = 0;
+ pclose (f);
+
+ if (nchars > 0)
+ for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n"))
+ {
+ snprintf (buf2, sizeof (buf2), "%s --query %s", cygrunsrv, srv);
+ if ((f = popen (buf2, "rt")) == NULL)
+ {
+ printf ("Failed to execute '%s', skipping services check.\n", buf2);
+ return;
+ }
+
+ /* copy output to stdout */
+ while (!feof (f) && !ferror (f))
+ fwrite ((void *) buf2, 1,
+ fread ((void *) buf2, 1, sizeof (buf2), f), stdout);
+ pclose (f);
+ }
+ else
+ no_services = true;
+ }
+
+ /* inform the user if nothing found */
+ if (no_services)
+ puts ("No Cygwin services found.\n");
+}
+
+static void
+dump_sysinfo ()
+{
+ int i, j;
+ char tmp[4000];
+ time_t now;
+ char *found_cygwin_dll;
+ bool is_nt = false;
+
+ printf ("\nCygwin Configuration Diagnostics\n");
+ time (&now);
+ printf ("Current System Time: %s\n", ctime (&now));
+
+ OSVERSIONINFO osversion;
+ osversion.dwOSVersionInfoSize = sizeof (osversion);
+ if (!GetVersionEx (&osversion))
+ display_error ("dump_sysinfo: GetVersionEx()");
+ const char *osname = "unknown OS";
+ switch (osversion.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32s:
+ osname = "32s";
+ break;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ switch (osversion.dwMinorVersion)
+ {
+ case 0:
+ if (strchr (osversion.szCSDVersion, 'C'))
+ osname = "95 OSR2";
+ else
+ osname = "95";
+ break;
+ case 10:
+ if (strchr (osversion.szCSDVersion, 'A'))
+ osname = "98 SE";
+ else
+ osname = "98";
+ break;
+ case 90:
+ osname = "ME";
+ break;
+ default:
+ osname = "9X";
+ break;
+ }
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ is_nt = true;
+ if (osversion.dwMajorVersion == 6)
+ osname = "Longhorn/Vista (not yet supported!)";
+ else if (osversion.dwMajorVersion == 5)
+ {
+ BOOL more_info = FALSE;
+ OSVERSIONINFOEX osversionex;
+ osversionex.dwOSVersionInfoSize = sizeof (osversionex);
+ if (GetVersionEx ((OSVERSIONINFO *) &osversionex))
+ more_info = TRUE;
+ if (osversion.dwMinorVersion == 0)
+ {
+ if (!more_info)
+ osname = "2000";
+ else if (osversionex.wProductType == VER_NT_SERVER
+ || osversionex.wProductType == VER_NT_DOMAIN_CONTROLLER)
+ {
+ if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
+ osname = "2000 Datacenter Server";
+ else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
+ osname = "2000 Advanced Server";
+ else
+ osname = "2000 Server";
+ }
+ else
+ osname = "2000 Professional";
+ }
+ else if (osversion.dwMinorVersion == 1)
+ {
+ if (GetSystemMetrics (SM_MEDIACENTER))
+ osname = "XP Media Center Edition";
+ else if (GetSystemMetrics (SM_TABLETPC))
+ osname = "XP Tablet PC Edition";
+ else if (!more_info)
+ osname = "XP";
+ else if (osversionex.wSuiteMask & VER_SUITE_PERSONAL)
+ osname = "XP Home Edition";
+ else
+ osname = "XP Professional";
+ }
+ else if (osversion.dwMinorVersion == 2)
+ {
+ if (!more_info)
+ osname = "2003 Server";
+ else if (osversionex.wSuiteMask & VER_SUITE_BLADE)
+ osname = "2003 Web Server";
+ else if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
+ osname = "2003 Datacenter Server";
+ else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
+ osname = "2003 Enterprise Server";
+ else
+ osname = "2003 Server";
+ }
+ }
+ else
+ osname = "NT";
+ break;
+ default:
+ osname = "??";
+ break;
+ }
+ printf ("Windows %s Ver %lu.%lu Build %lu %s\n", osname,
+ osversion.dwMajorVersion, osversion.dwMinorVersion,
+ osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
+ osversion.dwBuildNumber : (osversion.dwBuildNumber & 0xffff),
+ osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
+ osversion.szCSDVersion : "");
+
+ HMODULE k32 = LoadLibrary ("kernel32.dll");
+
+ BOOL (WINAPI *wow64_func) (HANDLE, PBOOL) = (BOOL (WINAPI *) (HANDLE, PBOOL))
+ GetProcAddress (k32, "IsWow64Process");
+ BOOL is_wow64 = FALSE;
+ if (wow64_func && wow64_func (GetCurrentProcess (), &is_wow64) && is_wow64)
+ {
+ void (WINAPI *nativinfo) (LPSYSTEM_INFO) = (void (WINAPI *)
+ (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo");
+ SYSTEM_INFO natinfo;
+ nativinfo (&natinfo);
+ fputs ("\nRunning under WOW64 on ", stdout);
+ switch (natinfo.wProcessorArchitecture)
+ {
+ case PROCESSOR_ARCHITECTURE_IA64:
+ puts ("IA64");
+ break;
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ puts ("AMD64");
+ break;
+ default:
+ puts("??");
+ break;
+ }
+ }
+
+ if (GetSystemMetrics (SM_REMOTESESSION))
+ printf ("\nRunning in Terminal Service session\n");
+
+ printf ("\nPath:");
+ char *s = getenv ("PATH"), *e;
+ if (!s)
+ puts ("");
+ else
+ {
+ char sep = strchr (s, ';') ? ';' : ':';
+ int count_path_items = 0;
+ while (1)
+ {
+ for (e = s; *e && *e != sep; e++);
+ if (e-s)
+ printf ("\t%.*s\n", e - s, s);
+ else
+ puts ("\t.");
+ count_path_items++;
+ if (!*e)
+ break;
+ s = e + 1;
+ }
+ }
+
+ fflush (stdout);
+
+ char *cygwin = getenv ("CYGWIN");
+ if (cygwin)
+ cygwin -= strlen ("CYGWIN=");
+ else
+ cygwin = const_cast <char *> ("CYGWIN=");
+ size_t cyglen = strlen (cygwin);
+ cygwin = strcpy ((char *) malloc (cyglen + sizeof (" nontsec")), cygwin);
+ pretty_id ("nontsec", cygwin, cyglen);
+ pretty_id ("ntsec", cygwin, cyglen);
+ cygwin[cyglen] = 0;
+ putenv (cygwin);
+
+ if (!GetSystemDirectory (tmp, 4000))
+ display_error ("dump_sysinfo: GetSystemDirectory()");
+ printf ("\nSysDir: %s\n", tmp);
+
+ GetWindowsDirectory (tmp, 4000);
+ printf ("WinDir: %s\n\n", tmp);
+
+
+ if (givehelp)
+ printf ("Here's some environment variables that may affect cygwin:\n");
+ for (i = 0; environ[i]; i++)
+ {
+ char *eq = strchr (environ[i], '=');
+ if (!eq)
+ continue;
+ /* int len = eq - environ[i]; */
+ for (j = 0; known_env_vars[j]; j++)
+ {
+ *eq = 0;
+ if (strcmp (environ[i], "PATH") == 0)
+ continue; /* we handle this one specially */
+ if (strcasecmp (environ[i], known_env_vars[j]) == 0)
+ printf ("%s = '%s'\n", environ[i], eq + 1);
+ *eq = '=';
+ }
+ }
+ printf ("\n");
+
+ if (verbose)
+ {
+ if (givehelp)
+ printf ("Here's the rest of your environment variables:\n");
+ for (i = 0; environ[i]; i++)
+ {
+ int found = 0;
+ char *eq = strchr (environ[i], '=');
+ if (!eq)
+ continue;
+ /* int len = eq - environ[i]; */
+ for (j = 0; known_env_vars[j]; j++)
+ {
+ *eq = 0;
+ if (strcasecmp (environ[i], known_env_vars[j]) == 0)
+ found = 1;
+ *eq = '=';
+ }
+ if (!found)
+ {
+ *eq = 0;
+ printf ("%s = '%s'\n", environ[i], eq + 1);
+ *eq = '=';
+ }
+ }
+ printf ("\n");
+ }
+
+ if (registry)
+ {
+ if (givehelp)
+ printf ("Scanning registry for keys with 'Cygnus' in them...\n");
+#if 0
+ /* big and not generally useful */
+ scan_registry (0, HKEY_CLASSES_ROOT, (char *) "HKEY_CLASSES_ROOT", 0);
+#endif
+ scan_registry (0, HKEY_CURRENT_CONFIG,
+ (char *) "HKEY_CURRENT_CONFIG", 0);
+ scan_registry (0, HKEY_CURRENT_USER, (char *) "HKEY_CURRENT_USER", 0);
+ scan_registry (0, HKEY_LOCAL_MACHINE, (char *) "HKEY_LOCAL_MACHINE", 0);
+#if 0
+ /* the parts we need are duplicated in HKEY_CURRENT_USER anyway */
+ scan_registry (0, HKEY_USERS, (char *) "HKEY_USERS", 0);
+#endif
+ printf ("\n");
+ }
+ else
+ printf ("Use '-r' to scan registry\n\n");
+
+ if (givehelp)
+ {
+ printf ("Listing available drives...\n");
+ printf ("Drv Type Size Used Flags Name\n");
+ }
+ int prev_mode =
+ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ int drivemask = GetLogicalDrives ();
+
+ BOOL (WINAPI * gdfse) (LPCSTR, long long *, long long *, long long *) =
+ (BOOL (WINAPI *) (LPCSTR, long long *, long long *, long long *))
+ GetProcAddress (k32, "GetDiskFreeSpaceExA");
+
+ for (i = 0; i < 26; i++)
+ {
+ if (!(drivemask & (1 << i)))
+ continue;
+ char drive[4], name[200], fsname[200];
+ DWORD serno = 0, maxnamelen = 0, flags = 0;
+ name[0] = name[0] = fsname[0] = 0;
+ sprintf (drive, "%c:\\", i + 'a');
+ /* Report all errors, except if the Volume is ERROR_NOT_READY.
+ ERROR_NOT_READY is returned when removeable media drives are empty
+ (CD, floppy, etc.) */
+ if (!GetVolumeInformation (drive, name, sizeof (name), &serno,
+ &maxnamelen, &flags, fsname,
+ sizeof (fsname))
+ && GetLastError () != ERROR_NOT_READY)
+ {
+# define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
+ char buf[sizeof (FMT)];
+ sprintf (buf, FMT, 'A' + i);
+ display_error (buf);
+# undef FMT
+ }
+
+ int dtype = GetDriveType (drive);
+ char drive_type[4] = "unk";
+ switch (dtype)
+ {
+ case DRIVE_REMOVABLE:
+ strcpy (drive_type, "fd ");
+ break;
+ case DRIVE_FIXED:
+ strcpy (drive_type, "hd ");
+ break;
+ case DRIVE_REMOTE:
+ strcpy (drive_type, "net");
+ break;
+ case DRIVE_CDROM:
+ strcpy (drive_type, "cd ");
+ break;
+ case DRIVE_RAMDISK:
+ strcpy (drive_type, "ram");
+ break;
+ default:
+ strcpy (drive_type, "unk");
+ }
+
+ long capacity_mb = -1;
+ int percent_full = -1;
+
+ long long free_me = 0ULL, free_bytes = 0ULL, total_bytes = 1ULL;
+ if (gdfse != NULL && gdfse (drive, &free_me, &total_bytes, &free_bytes))
+ {
+ capacity_mb = total_bytes / (1024L * 1024L);
+ percent_full = 100 - (int) ((100.0 * free_me) / total_bytes);
+ }
+ else
+ {
+ DWORD spc = 0, bps = 0, fc = 0, tc = 1;
+ if (GetDiskFreeSpace (drive, &spc, &bps, &fc, &tc))
+ {
+ capacity_mb = (spc * bps * tc) / (1024 * 1024);
+ percent_full = 100 - (int) ((100.0 * fc) / tc);
+ }
+ }
+
+ printf ("%.2s %s %-6s ", drive, drive_type, fsname);
+ if (capacity_mb >= 0)
+ printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full);
+ else
+ printf (" N/A N/A ");
+ printf ("%s %s %s %s %s %s %s\n",
+ flags & FS_CASE_IS_PRESERVED ? "CP" : " ",
+ flags & FS_CASE_SENSITIVE ? "CS" : " ",
+ flags & FS_UNICODE_STORED_ON_DISK ? "UN" : " ",
+ flags & FS_PERSISTENT_ACLS ? "PA" : " ",
+ flags & FS_FILE_COMPRESSION ? "FC" : " ",
+ flags & FS_VOL_IS_COMPRESSED ? "VC" : " ",
+#if 0
+ flags & FILE_SUPPORTS_ENCRYPTION ? "EN" : " ",
+ flags & FILE_SUPPORTS_OBJECT_IDS ? "OI" : " ",
+ flags & FILE_SUPPORTS_REPARSE_POINTS ? "RP" : " ",
+ flags & FILE_SUPPORTS_SPARSE_FILES ? "SP" : " ",
+ flags & FILE_VOLUME_QUOTAS ? "QU" : " ",
+#endif
+ name);
+ }
+
+ if (!FreeLibrary (k32))
+ display_error ("dump_sysinfo: FreeLibrary()");
+ SetErrorMode (prev_mode);
+ if (givehelp)
+ {
+ puts ("\n"
+ "fd = floppy, hd = hard drive, cd = CD-ROM\n"
+ "net= Network Share, ram= RAM drive, unk= Unknown\n"
+ "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
+ "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
+ }
+ printf ("\n");
+
+ unsigned ml_fsname = 4, ml_dir = 7, ml_type = 6;
+ bool ml_trailing = false;
+
+ struct mntent *mnt;
+ setmntent (0, 0);
+ while ((mnt = getmntent (0)))
+ {
+ unsigned n = (int) strlen (mnt->mnt_fsname);
+ ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_fsname[n - 1]));
+ if (ml_fsname < n)
+ ml_fsname = n;
+ n = (int) strlen (mnt->mnt_dir);
+ ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_dir[n - 1]));
+ if (ml_dir < n)
+ ml_dir = n;
+ }
+
+ if (ml_trailing)
+ puts ("Warning: Mount entries should not have a trailing (back)slash\n");
+
+ if (givehelp)
+ {
+ printf
+ ("Mount entries: these map POSIX directories to your NT drives.\n");
+ printf ("%-*s %-*s %-*s %s\n", ml_fsname, "-NT-", ml_dir, "-POSIX-",
+ ml_type, "-Type-", "-Flags-");
+ }
+
+ setmntent (0, 0);
+ while ((mnt = getmntent (0)))
+ {
+ printf ("%-*s %-*s %-*s %s\n",
+ ml_fsname, mnt->mnt_fsname,
+ ml_dir, mnt->mnt_dir, ml_type, mnt->mnt_type, mnt->mnt_opts);
+ }
+ printf ("\n");
+
+ add_path ((char *) "\\bin", 4); /* just in case */
+
+ if (givehelp)
+ printf
+ ("Looking to see where common programs can be found, if at all...\n");
+ for (i = 0; common_apps[i].name; i++)
+ if (!find_on_path ((char *) common_apps[i].name, (char *) ".exe", 1, 0))
+ {
+ if (common_apps[i].missing_is_good)
+ printf ("Not Found: %s (good!)\n", common_apps[i].name);
+ else
+ printf ("Not Found: %s\n", common_apps[i].name);
+ }
+ printf ("\n");
+
+ if (givehelp)
+ printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
+ int cygwin_dll_count = 0;
+ for (i = 1; i < num_paths; i++)
+ {
+ WIN32_FIND_DATA ffinfo;
+ sprintf (tmp, "%s/*.*", paths[i]);
+ HANDLE ff = FindFirstFile (tmp, &ffinfo);
+ int found = (ff != INVALID_HANDLE_VALUE);
+ found_cygwin_dll = NULL;
+ while (found)
+ {
+ char *f = ffinfo.cFileName;
+ if (strcasecmp (f + strlen (f) - 4, ".dll") == 0)
+ {
+ if (strncasecmp (f, "cyg", 3) == 0)
+ {
+ sprintf (tmp, "%s\\%s", paths[i], f);
+ if (strcasecmp (f, "cygwin1.dll") == 0)
+ {
+ cygwin_dll_count++;
+ found_cygwin_dll = strdup (tmp);
+ }
+ else
+ ls (tmp);
+ }
+ }
+ found = FindNextFile (ff, &ffinfo);
+ }
+ if (found_cygwin_dll)
+ {
+ ls (found_cygwin_dll);
+ free (found_cygwin_dll);
+ }
+
+ FindClose (ff);
+ }
+ if (cygwin_dll_count > 1)
+ puts ("Warning: There are multiple cygwin1.dlls on your path");
+ if (!cygwin_dll_count)
+ puts ("Warning: cygwin1.dll not found on your path");
+
+ dump_dodgy_apps (verbose);
+
+ if (is_nt)
+ dump_sysinfo_services ();
+}
+
+static int
+check_keys ()
+{
+ HANDLE h = CreateFileA ("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE || h == NULL)
+ return (display_error ("check_keys: Opening CONIN$"));
+
+ DWORD mode;
+
+ if (!GetConsoleMode (h, &mode))
+ display_error ("check_keys: GetConsoleMode()");
+ else
+ {
+ mode &= ~ENABLE_PROCESSED_INPUT;
+ if (!SetConsoleMode (h, mode))
+ display_error ("check_keys: SetConsoleMode()");
+ }
+
+ fputs ("\nThis key check works only in a console window,", stderr);
+ fputs (" _NOT_ in a terminal session!\n", stderr);
+ fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr);
+ fputs ("Press 'q' to exit.\n", stderr);
+
+ INPUT_RECORD in, prev_in;
+
+ // Drop first <RETURN> key
+ ReadConsoleInput (h, &in, 1, &mode);
+
+ memset (&in, 0, sizeof in);
+
+ do
+ {
+ prev_in = in;
+ if (!ReadConsoleInput (h, &in, 1, &mode))
+ display_error ("check_keys: ReadConsoleInput()");
+
+ if (!memcmp (&in, &prev_in, sizeof in))
+ continue;
+
+ switch (in.EventType)
+ {
+ case KEY_EVENT:
+ printf ("%s %ux VK: 0x%02x VS: 0x%02x A: 0x%02x CTRL: ",
+ in.Event.KeyEvent.bKeyDown ? "Pressed " : "Released",
+ in.Event.KeyEvent.wRepeatCount,
+ in.Event.KeyEvent.wVirtualKeyCode,
+ in.Event.KeyEvent.wVirtualScanCode,
+ (unsigned char) in.Event.KeyEvent.uChar.AsciiChar);
+ fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ?
+ "CL " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ?
+ "EK " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED ?
+ "LA " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED ?
+ "LC " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & NUMLOCK_ON ?
+ "NL " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED ?
+ "RA " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED ?
+ "RC " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON ?
+ "SL " : "-- ", stdout);
+ fputs (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ?
+ "SH " : "-- ", stdout);
+ fputc ('\n', stdout);
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (in.EventType != KEY_EVENT ||
+ in.Event.KeyEvent.bKeyDown != FALSE ||
+ in.Event.KeyEvent.uChar.AsciiChar != 'q');
+
+ CloseHandle (h);
+ return 0;
+}
+
+/* RFC1738 says that these do not need to be escaped. */
+static const char safe_chars[] = "$-_.+!*'(),";
+
+/* the URL to query. */
+static const char base_url[] =
+ "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
+
+/* 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)
+{
+ char buf[1024];
+
+ /* Attempt to dynamically load the necessary WinInet API functions so that
+ cygcheck can still function on older systems without IE. */
+ HMODULE hWinInet;
+ if (!(hWinInet = LoadLibrary ("wininet.dll")))
+ {
+ fputs ("Unable to locate WININET.DLL. This feature requires Microsoft "
+ "Internet Explorer v3 or later to function.\n", stderr);
+ return 1;
+ }
+
+ /* InternetCloseHandle is used outside this function so it is declared
+ global. The rest of these functions are only used here, so declare them
+ and call GetProcAddress for each of them with the following macro. */
+
+ pInternetCloseHandle = (BOOL (WINAPI *) (HINTERNET))
+ GetProcAddress (hWinInet, "InternetCloseHandle");
+#define make_func_pointer(name, ret, args) ret (WINAPI * p##name) args = \
+ (ret (WINAPI *) args) GetProcAddress (hWinInet, #name);
+ make_func_pointer (InternetAttemptConnect, DWORD, (DWORD));
+ make_func_pointer (InternetOpenA, HINTERNET, (LPCSTR, DWORD, LPCSTR, LPCSTR,
+ DWORD));
+ make_func_pointer (InternetOpenUrlA, HINTERNET, (HINTERNET, LPCSTR, LPCSTR,
+ DWORD, DWORD, DWORD));
+ make_func_pointer (InternetReadFile, BOOL, (HINTERNET, PVOID, DWORD, PDWORD));
+ make_func_pointer (HttpQueryInfoA, BOOL, (HINTERNET, DWORD, PVOID, PDWORD,
+ PDWORD));
+#undef make_func_pointer
+
+ if(!pInternetCloseHandle || !pInternetAttemptConnect || !pInternetOpenA
+ || !pInternetOpenUrlA || !pInternetReadFile || !pHttpQueryInfoA)
+ {
+ fputs ("Unable to load one or more functions from WININET.DLL. This "
+ "feature requires Microsoft Internet Explorer v3 or later to "
+ "function.\n", stderr);
+ return 1;
+ }
+
+ /* construct the actual URL by escaping */
+ char *url = (char *) alloca (sizeof (base_url) + strlen (search) * 3);
+ strcpy (url, base_url);
+
+ char *dest;
+ for (dest = &url[sizeof (base_url) - 1]; *search; search++)
+ {
+ if (isalnum (*search)
+ || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
+ {
+ *dest++ = *search;
+ }
+ else
+ {
+ *dest++ = '%';
+ sprintf (dest, "%02x", (unsigned char) *search);
+ dest += 2;
+ }
+ }
+ *dest = 0;
+
+ /* Connect to the net and open the URL. */
+ if (pInternetAttemptConnect (0) != ERROR_SUCCESS)
+ {
+ fputs ("An internet connection is required for this function.\n", stderr);
+ return 1;
+ }
+
+ /* Initialize WinInet and attempt to fetch our URL. */
+ HINTERNET hi = NULL, hurl = NULL;
+ if (!(hi = pInternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)))
+ return display_internet_error ("InternetOpen() failed", NULL);
+
+ if (!(hurl = pInternetOpenUrlA (hi, url, NULL, 0, 0, 0)))
+ return display_internet_error ("unable to contact cygwin.com site, "
+ "InternetOpenUrl() failed", hi, NULL);
+
+ /* Check the HTTP response code. */
+ DWORD rc = 0, rc_s = sizeof (DWORD);
+ if (!pHttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
+ (void *) &rc, &rc_s, NULL))
+ return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL);
+
+ if (rc != HTTP_STATUS_OK)
+ {
+ sprintf (buf, "error retrieving results from cygwin.com site, "
+ "HTTP status code %lu", rc);
+ return display_internet_error (buf, hurl, hi, NULL);
+ }
+
+ /* Fetch result and print to stdout. */
+ DWORD numread;
+ do
+ {
+ if (!pInternetReadFile (hurl, (void *) buf, sizeof (buf), &numread))
+ return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
+ if (numread)
+ fwrite ((void *) buf, (size_t) numread, 1, stdout);
+ }
+ while (numread);
+
+ pInternetCloseHandle (hurl);
+ pInternetCloseHandle (hi);
+ return 0;
+}
+
+static void
+usage (FILE * stream, int status)
+{
+ fprintf (stream, "\
+Usage: cygcheck PROGRAM [ -v ] [ -h ]\n\
+ cygcheck -c [ PACKAGE ] [ -d ]\n\
+ cygcheck -s [ -r ] [ -v ] [ -h ]\n\
+ cygcheck -k\n\
+ cygcheck -f FILE [ FILE ... ]\n\
+ cygcheck -l [ PACKAGE ] [ PACKAGE ... ]\n\
+ cygcheck -p REGEXP\n\
+List system information, check installed packages, or query package database.\n\
+\n\
+At least one command option or a PROGRAM is required, as shown above.\n\
+\n\
+ PROGRAM list library (DLL) dependencies of PROGRAM\n\
+ -c, --check-setup show installed version of PACKAGE and verify integrity\n\
+ (or for all installed packages if none specified)\n\
+ -d, --dump-only just list packages, do not verify (with -c)\n\
+ -s, --sysinfo produce diagnostic system information (implies -c -d)\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 that FILE belongs to\n\
+ -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
+ -p, --package-query search for REGEXP in the entire cygwin.com package\n\
+ repository (requies internet connectivity)\n\
+ -v, --verbose produce more verbose output\n\
+ -h, --help annotate output with explanatory comments when given\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\
+ 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");
+ exit (status);
+}
+
+struct option longopts[] = {
+ {"check-setup", no_argument, NULL, 'c'},
+ {"dump-only", no_argument, NULL, 'd'},
+ {"sysinfo", no_argument, NULL, 's'},
+ {"registry", no_argument, NULL, 'r'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"keycheck", no_argument, NULL, 'k'},
+ {"find-package", no_argument, NULL, 'f'},
+ {"list-package", no_argument, NULL, 'l'},
+ {"package-query", no_argument, NULL, 'p'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {0, no_argument, NULL, 0}
+};
+
+static char opts[] = "cdsrvkflphV";
+
+static void
+print_version ()
+{
+ const char *v = strchr (version, ':');
+ int len;
+ if (!v)
+ {
+ v = "?";
+ len = 1;
+ }
+ else
+ {
+ v += 2;
+ len = strchr (v, ' ') - v;
+ }
+ printf ("\
+cygcheck version %.*s\n\
+System Checker for Cygwin\n\
+Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.\n\
+Compiled on %s\n\
+", len, v, __DATE__);
+}
+
+void
+nuke (char *ev)
+{
+ int n = 1 + strchr (ev, '=') - ev;
+ char *s = (char *) alloca (n + 1);
+ memcpy (s, ev, n);
+ s[n] = '\0';
+ putenv (s);
+}
+
+extern "C" {
+unsigned long (*cygwin_internal) (int, ...);
+};
+
+static void
+load_cygwin (int& argc, char **&argv)
+{
+ HMODULE h;
+
+ if (!(h = LoadLibrary ("cygwin1.dll")))
+ return;
+ if (!(cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal")))
+ return;
+
+ char **av = (char **) cygwin_internal (CW_ARGV);
+ if (av && ((DWORD) av != (DWORD) -1))
+ for (argc = 0, argv = av; *av; av++)
+ argc++;
+
+ char **envp = (char **) cygwin_internal (CW_ENVP);
+ if (envp && ((DWORD) envp != (DWORD) -1))
+ {
+ /* Store path and revert to this value, otherwise path gets overwritten
+ by the POSIXy Cygwin variation, which breaks cygcheck.
+ Another approach would be to use the Cygwin PATH and convert it to
+ Win32 again. */
+ char *path = NULL;
+ char **env;
+ while (*(env = _environ))
+ {
+ if (strncmp (*env, "PATH=", 5) == 0)
+ path = strdup (*env);
+ nuke (*env);
+ }
+ for (char **ev = envp; *ev; ev++)
+ if (strncmp (*ev, "PATH=", 5) != 0)
+ putenv (*ev);
+ if (path)
+ putenv (path);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ bool ok = true;
+ load_cygwin (argc, argv);
+
+ /* Need POSIX sorting while parsing args, but don't forget the
+ user's original environment. */
+ char *posixly = getenv ("POSIXLY_CORRECT");
+ if (posixly == NULL)
+ (void) putenv("POSIXLY_CORRECT=1");
+ while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
+ switch (i)
+ {
+ case 's':
+ sysinfo = 1;
+ break;
+ case 'c':
+ check_setup = 1;
+ break;
+ case 'd':
+ dump_only = 1;
+ break;
+ case 'r':
+ registry = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'k':
+ keycheck = 1;
+ break;
+ case 'f':
+ find_package = 1;
+ break;
+ case 'l':
+ list_package = 1;
+ break;
+ case 'p':
+ grep_packages = 1;
+ break;
+ case 'h':
+ givehelp = 1;
+ break;
+ case 'V':
+ print_version ();
+ exit (0);
+ default:
+ usage (stderr, 1);
+ /*NOTREACHED*/}
+ argc -= optind;
+ argv += optind;
+ if (posixly == NULL)
+ putenv ("POSIXLY_CORRECT=");
+
+ if (argc == 0 && !sysinfo && !keycheck && !check_setup && !list_package)
+ if (givehelp)
+ usage (stdout, 0);
+ else
+ usage (stderr, 1);
+
+ if ((check_setup || sysinfo || find_package || list_package || grep_packages)
+ && keycheck)
+ usage (stderr, 1);
+
+ if ((find_package || list_package || grep_packages) && check_setup)
+ usage (stderr, 1);
+
+ if (dump_only && !check_setup)
+ usage (stderr, 1);
+
+ if (find_package + list_package + grep_packages > 1)
+ usage (stderr, 1);
+
+ if (keycheck)
+ return check_keys ();
+ if (grep_packages)
+ return package_grep (*argv);
+
+ init_paths ();
+
+ /* FIXME: Add help for check_setup and {list,find}_package */
+ if (argc >= 1 && givehelp && !check_setup && !find_package && !list_package)
+ {
+ printf("Here is where the OS will find your program%s, and which dlls\n",
+ argc > 1 ? "s" : "");
+ printf ("will be used for it. Use -v to see DLL version info\n");
+
+ if (!sysinfo)
+ printf ("\n");
+ }
+
+ if (check_setup)
+ dump_setup (verbose, argv, !dump_only);
+ else if (find_package)
+ package_find (verbose, argv);
+ else if (list_package)
+ package_list (verbose, argv);
+ else
+ for (i = 0; i < argc; i++)
+ {
+ if (i)
+ puts ("");
+ ok &= cygcheck (argv[i]);
+ }
+
+ if (sysinfo)
+ {
+ dump_sysinfo ();
+ if (!check_setup)
+ {
+ puts ("");
+ dump_setup (verbose, NULL, false);
+ }
+
+ if (!givehelp)
+ puts ("Use -h to see help about each section");
+ }
+
+ return ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/winsup/utils/cygpath.cc b/winsup/utils/cygpath.cc
new file mode 100644
index 00000000000..33262fed7c8
--- /dev/null
+++ b/winsup/utils/cygpath.cc
@@ -0,0 +1,831 @@
+/* cygpath.cc -- convert pathnames between Windows and Unix format
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007 Red Hat, Inc.
+
+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. */
+
+#define NOCOMATTRIBUTE
+
+#include <shlobj.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <windows.h>
+#include <io.h>
+#include <sys/fcntl.h>
+#include <sys/cygwin.h>
+#include <ctype.h>
+#include <errno.h>
+
+static const char version[] = "$Revision$";
+
+static char *prog_name;
+static char *file_arg;
+static int path_flag, unix_flag, windows_flag, absolute_flag;
+static int shortname_flag, longname_flag;
+static int ignore_flag, allusers_flag, output_flag;
+static int mixed_flag;
+static const char *format_type_arg;
+
+static struct option long_options[] = {
+ {(char *) "absolute", no_argument, NULL, 'a'},
+ {(char *) "close", required_argument, NULL, 'c'},
+ {(char *) "dos", no_argument, NULL, 'd'},
+ {(char *) "file", required_argument, NULL, 'f'},
+ {(char *) "help", no_argument, NULL, 'h'},
+ {(char *) "ignore", no_argument, NULL, 'i'},
+ {(char *) "long-name", no_argument, NULL, 'l'},
+ {(char *) "mixed", no_argument, NULL, 'm'},
+ {(char *) "mode", no_argument, NULL, 'M'},
+ {(char *) "option", no_argument, NULL, 'o'},
+ {(char *) "path", no_argument, NULL, 'p'},
+ {(char *) "short-name", no_argument, NULL, 's'},
+ {(char *) "type", required_argument, NULL, 't'},
+ {(char *) "unix", no_argument, NULL, 'u'},
+ {(char *) "version", no_argument, NULL, 'v'},
+ {(char *) "windows", no_argument, NULL, 'w'},
+ {(char *) "allusers", no_argument, NULL, 'A'},
+ {(char *) "desktop", no_argument, NULL, 'D'},
+ {(char *) "homeroot", no_argument, NULL, 'H'},
+ {(char *) "smprograms", no_argument, NULL, 'P'},
+ {(char *) "sysdir", no_argument, NULL, 'S'},
+ {(char *) "windir", no_argument, NULL, 'W'},
+ {0, no_argument, 0, 0}
+};
+
+static char options[] = "ac:df:hilmMopst:uvwADHPSW";
+
+static void
+usage (FILE * stream, int status)
+{
+ if (!ignore_flag || !status)
+ fprintf (stream, "\
+Usage: %s (-d|-m|-u|-w|-t TYPE) [-f FILE] [OPTION]... NAME...\n\
+ %s [-c HANDLE] \n\
+ %s [-ADHPSW] \n\
+Convert Unix and Windows format paths, or output system path information\n\
+\n\
+Output type options:\n\
+ -d, --dos print DOS (short) form of NAMEs (C:\\PROGRA~1\\)\n\
+ -m, --mixed like --windows, but with regular slashes (C:/WINNT)\n\
+ -M, --mode report on mode of file (binmode or textmode)\n\
+ -u, --unix (default) print Unix form of NAMEs (/cygdrive/c/winnt)\n\
+ -w, --windows print Windows form of NAMEs (C:\\WINNT)\n\
+ -t, --type TYPE print TYPE form: 'dos', 'mixed', 'unix', or 'windows'\n\
+Path conversion options:\n\
+ -a, --absolute output absolute path\n\
+ -l, --long-name print Windows long form of NAMEs (with -w, -m only)\n\
+ -p, --path NAME is a PATH list (i.e., '/bin:/usr/bin')\n\
+ -s, --short-name print DOS (short) form of NAMEs (with -w, -m only)\n\
+System information:\n\
+ -A, --allusers use `All Users' instead of current user for -D, -P\n\
+ -D, --desktop output `Desktop' directory and exit\n\
+ -H, --homeroot output `Profiles' directory (home root) and exit\n\
+ -P, --smprograms output Start Menu `Programs' directory and exit\n\
+ -S, --sysdir output system directory and exit\n\
+ -W, --windir output `Windows' directory and exit\n\
+", prog_name, prog_name, prog_name);
+ if (ignore_flag)
+ /* nothing to do */;
+ else if (stream != stdout)
+ fprintf(stream, "Try `%s --help' for more information.\n", prog_name);
+ else
+ {
+ fprintf (stream, "\
+Other options:\n\
+ -f, --file FILE read FILE for input; use - to read from STDIN\n\
+ -o, --option read options from FILE as well (for use with --file)\n\
+ -c, --close HANDLE close HANDLE (for use in captured process)\n\
+ -i, --ignore ignore missing argument\n\
+ -h, --help output usage information and exit\n\
+ -v, --version output version information and exit\n\
+");
+ }
+ exit (ignore_flag ? 0 : status);
+}
+
+static char *
+get_short_paths (char *path)
+{
+ char *sbuf;
+ char *sptr;
+ char *next;
+ char *ptr = path;
+ char *end = strrchr (path, 0);
+ DWORD acc = 0;
+ DWORD len;
+
+ while (ptr != NULL)
+ {
+ next = ptr;
+ ptr = strchr (ptr, ';');
+ if (ptr)
+ *ptr++ = 0;
+ len = GetShortPathName (next, NULL, 0);
+ if (!len)
+ {
+ fprintf (stderr, "%s: cannot create short name of %s\n", prog_name,
+ next);
+ exit (2);
+ }
+ acc += len + 1;
+ }
+ sptr = sbuf = (char *) malloc (acc + 1);
+ if (sbuf == NULL)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+ ptr = path;
+ for (;;)
+ {
+ len = GetShortPathName (ptr, sptr, acc);
+ if (!len)
+ {
+ fprintf (stderr, "%s: cannot create short name of %s\n", prog_name,
+ ptr);
+ exit (2);
+ }
+
+ ptr = strrchr (ptr, 0);
+ sptr = strrchr (sptr, 0);
+ if (ptr == end)
+ break;
+ *sptr = ';';
+ ++ptr, ++sptr;
+ acc -= len + 1;
+ }
+ return sbuf;
+}
+
+static char *
+get_short_name (const char *filename)
+{
+ char *sbuf, buf[MAX_PATH];
+ DWORD len = GetShortPathName (filename, buf, MAX_PATH);
+ if (!len)
+ {
+ fprintf (stderr, "%s: cannot create short name of %s\n", prog_name,
+ filename);
+ exit (2);
+ }
+ sbuf = (char *) malloc (++len);
+ if (sbuf == NULL)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+ return strcpy (sbuf, buf);
+}
+
+static DWORD WINAPI
+get_long_path_name_w32impl (LPCSTR src, LPSTR sbuf, DWORD)
+{
+ char buf1[MAX_PATH], buf2[MAX_PATH], *ptr;
+ const char *pelem, *next;
+ WIN32_FIND_DATA w32_fd;
+ int len;
+
+ strcpy (buf1, src);
+ *buf2 = 0;
+ pelem = src;
+ ptr = buf2;
+ while (pelem)
+ {
+ next = pelem;
+ if (*next == '\\')
+ {
+ strcat (ptr++, "\\");
+ pelem++;
+ if (!*pelem)
+ break;
+ continue;
+ }
+ pelem = strchr (next, '\\');
+ len = pelem ? (pelem++ - next) : strlen (next);
+ strncpy (ptr, next, len);
+ ptr[len] = 0;
+ if (next[1] != ':' && strcmp(next, ".") && strcmp(next, ".."))
+ {
+ HANDLE h;
+ h = FindFirstFile (buf2, &w32_fd);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ strcpy (ptr, w32_fd.cFileName);
+ FindClose (h);
+ }
+ }
+ ptr += strlen (ptr);
+ if (pelem)
+ {
+ *ptr++ = '\\';
+ *ptr = 0;
+ }
+ }
+ if (sbuf)
+ strcpy (sbuf, buf2);
+ SetLastError (0);
+ return strlen (buf2) + (sbuf ? 0 : 1);
+}
+
+static char *
+get_long_name (const char *filename, DWORD& len)
+{
+ char *sbuf, buf[MAX_PATH];
+ static HINSTANCE k32 = LoadLibrary ("kernel32.dll");
+ static DWORD (WINAPI *GetLongPathName) (LPCSTR, LPSTR, DWORD) =
+ (DWORD (WINAPI *) (LPCSTR, LPSTR, DWORD)) GetProcAddress (k32, "GetLongPathNameA");
+ if (!GetLongPathName)
+ GetLongPathName = get_long_path_name_w32impl;
+
+ len = GetLongPathName (filename, buf, MAX_PATH);
+ if (len == 0)
+ {
+ DWORD err = GetLastError ();
+
+ if (err == ERROR_INVALID_PARAMETER)
+ {
+ fprintf (stderr, "%s: cannot create long name of %s\n", prog_name,
+ filename);
+ exit (2);
+ }
+ else if (err == ERROR_FILE_NOT_FOUND)
+ len = get_long_path_name_w32impl (filename, buf, MAX_PATH);
+ else
+ {
+ buf[0] = '\0';
+ strncat (buf, filename, MAX_PATH - 1);
+ len = strlen (buf);
+ }
+ }
+ sbuf = (char *) malloc (len + 1);
+ if (!sbuf)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+ return strcpy (sbuf, buf);
+}
+
+static char *
+get_long_paths (char *path)
+{
+ char *sbuf;
+ char *ptr;
+ int n = 1;
+
+ ptr = path;
+ while ((ptr = strchr (ptr, ';')))
+ {
+ ptr++;
+ n++;
+ }
+
+ char *paths[n];
+ DWORD acc = 0;
+ int i;
+ if (!n)
+ return strdup ("");
+
+ for (i = 0, ptr = path; ptr; i++)
+ {
+ DWORD len;
+ char *next = ptr;
+ ptr = strchr (ptr, ';');
+ if (ptr)
+ *ptr++ = 0;
+ paths[i] = get_long_name (next, len);
+ acc += len + 1;
+ }
+
+ sbuf = (char *) malloc (acc + 1);
+ if (sbuf == NULL)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+
+ sbuf[0] = '\0';
+ for (i = 0; i < n; i++)
+ {
+ strcat (strcat (sbuf, paths[i]), ";");
+ free (paths[i]);
+ }
+
+ strchr (sbuf, '\0')[-1] = '\0';
+ return sbuf;
+}
+
+static void
+convert_slashes (char* name)
+{
+ while ((name = strchr (name, '\\')) != NULL)
+ {
+ if (*name == '\\')
+ *name = '/';
+ name++;
+ }
+}
+
+static char *
+get_mixed_name (const char* filename)
+{
+ char* mixed_buf = strdup (filename);
+
+ if (mixed_buf == NULL)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+
+ convert_slashes (mixed_buf);
+
+ return mixed_buf;
+}
+
+static void
+dowin (char option)
+{
+ char *buf, buf1[MAX_PATH], buf2[MAX_PATH];
+ DWORD len = MAX_PATH;
+ WIN32_FIND_DATA w32_fd;
+ LPITEMIDLIST id;
+ HINSTANCE k32;
+ BOOL (*GetProfilesDirectoryAPtr) (LPSTR, LPDWORD) = 0;
+
+ buf = buf1;
+ switch (option)
+ {
+ case 'D':
+ SHGetSpecialFolderLocation (NULL, allusers_flag ?
+ CSIDL_COMMON_DESKTOPDIRECTORY : CSIDL_DESKTOPDIRECTORY, &id);
+ SHGetPathFromIDList (id, buf);
+ /* This if clause is a Fix for Win95 without any "All Users" */
+ if (strlen (buf) == 0)
+ {
+ SHGetSpecialFolderLocation (NULL, CSIDL_DESKTOPDIRECTORY, &id);
+ SHGetPathFromIDList (id, buf);
+ }
+ break;
+
+ case 'P':
+ SHGetSpecialFolderLocation (NULL, allusers_flag ?
+ CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, &id);
+ SHGetPathFromIDList (id, buf);
+ /* This if clause is a Fix for Win95 without any "All Users" */
+ if (strlen (buf) == 0)
+ {
+ SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &id);
+ SHGetPathFromIDList (id, buf);
+ }
+ break;
+
+ case 'H':
+ k32 = LoadLibrary ("userenv");
+ if (k32)
+ GetProfilesDirectoryAPtr = (BOOL (*) (LPSTR, LPDWORD))
+ GetProcAddress (k32, "GetProfilesDirectoryA");
+ if (GetProfilesDirectoryAPtr)
+ (*GetProfilesDirectoryAPtr) (buf, &len);
+ else
+ {
+ GetWindowsDirectory (buf, MAX_PATH);
+ strcat (buf, "\\Profiles");
+ }
+ break;
+
+ case 'S':
+ GetSystemDirectory (buf, MAX_PATH);
+ FindFirstFile (buf, &w32_fd);
+ strcpy (strrchr (buf, '\\') + 1, w32_fd.cFileName);
+ break;
+
+ case 'W':
+ GetWindowsDirectory (buf, MAX_PATH);
+ break;
+
+ default:
+ usage (stderr, 1);
+ }
+
+ if (!windows_flag)
+ {
+ if (cygwin_conv_to_posix_path (buf, buf2))
+ fprintf (stderr, "%s: error converting \"%s\" - %s\n",
+ prog_name, buf, strerror (errno));
+ else
+ buf = buf2;
+ }
+ else
+ {
+ if (shortname_flag)
+ buf = get_short_name (buf);
+ if (mixed_flag)
+ buf = get_mixed_name (buf);
+ }
+ printf ("%s\n", buf);
+ exit (0);
+}
+
+static void
+report_mode (char *filename)
+{
+ switch (cygwin_internal (CW_GET_BINMODE, filename))
+ {
+ case O_BINARY:
+ printf ("%s: binary\n", filename);
+ break;
+ case O_TEXT:
+ printf ("%s: text\n", filename);
+ break;
+ default:
+ fprintf (stderr, "%s: file '%s' - %s\n", prog_name, filename,
+ strerror (errno));
+ break;
+ }
+}
+
+static void
+doit (char *filename)
+{
+ char *buf;
+ DWORD len;
+ int err;
+ int (*conv_func) (const char *, char *);
+
+ if (!path_flag)
+ {
+ len = strlen (filename);
+ if (len)
+ len += MAX_PATH + 1001;
+ else if (ignore_flag)
+ exit (0);
+ else
+ {
+ fprintf (stderr, "%s: can't convert empty path\n", prog_name);
+ exit (1);
+ }
+ }
+ else if (unix_flag)
+ len = cygwin_win32_to_posix_path_list_buf_size (filename);
+ else
+ len = cygwin_posix_to_win32_path_list_buf_size (filename);
+
+ buf = (char *) malloc (len);
+ if (buf == NULL)
+ {
+ fprintf (stderr, "%s: out of memory\n", prog_name);
+ exit (1);
+ }
+
+ if (path_flag)
+ {
+ if (unix_flag)
+ err = cygwin_win32_to_posix_path_list (filename, buf);
+ else
+ {
+ err = cygwin_posix_to_win32_path_list (filename, buf);
+ if (err)
+ /* oops */;
+ if (shortname_flag)
+ buf = get_short_paths (buf);
+ if (longname_flag)
+ buf = get_long_paths (buf);
+ if (mixed_flag)
+ buf = get_mixed_name (buf);
+ }
+ if (err)
+ {
+ fprintf (stderr, "%s: error converting \"%s\" - %s\n",
+ prog_name, filename, strerror (errno));
+ exit (1);
+ }
+ }
+ else
+ {
+ if (unix_flag)
+ conv_func = (absolute_flag ? cygwin_conv_to_full_posix_path :
+ cygwin_conv_to_posix_path);
+ else
+ conv_func = (absolute_flag ? cygwin_conv_to_full_win32_path :
+ cygwin_conv_to_win32_path);
+ err = conv_func (filename, buf);
+ if (err)
+ {
+ fprintf (stderr, "%s: error converting \"%s\" - %s\n",
+ prog_name, filename, strerror (errno));
+ exit (1);
+ }
+ if (!unix_flag)
+ {
+ if (shortname_flag)
+ buf = get_short_name (buf);
+ if (longname_flag)
+ buf = get_long_name (buf, len);
+ if (mixed_flag)
+ buf = get_mixed_name (buf);
+ }
+ }
+
+ puts (buf);
+}
+
+static void
+print_version ()
+{
+ const char *v = strchr (version, ':');
+ int len;
+ if (!v)
+ {
+ v = "?";
+ len = 1;
+ }
+ else
+ {
+ v += 2;
+ len = strchr (v, ' ') - v;
+ }
+ printf ("\
+cygpath (cygwin) %.*s\n\
+Path Conversion Utility\n\
+Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.\n\
+Compiled on %s\n\
+", len, v, __DATE__);
+}
+
+int
+main (int argc, char **argv)
+{
+ int c, o = 0;
+ int options_from_file_flag;
+ int mode_flag;
+
+ prog_name = strrchr (argv[0], '/');
+ if (prog_name == NULL)
+ prog_name = strrchr (argv[0], '\\');
+ if (prog_name == NULL)
+ prog_name = argv[0];
+ else
+ prog_name++;
+
+ path_flag = 0;
+ unix_flag = 1;
+ windows_flag = 0;
+ shortname_flag = 0;
+ longname_flag = 0;
+ mixed_flag = 0;
+ ignore_flag = 0;
+ options_from_file_flag = 0;
+ allusers_flag = 0;
+ output_flag = 0;
+ mode_flag = 0;
+ while ((c = getopt_long (argc, argv, options,
+ long_options, (int *) NULL)) != EOF)
+ {
+ switch (c)
+ {
+ case 'a':
+ absolute_flag = 1;
+ break;
+
+ case 'c':
+ CloseHandle ((HANDLE) strtoul (optarg, NULL, 16));
+ break;
+
+ case 'd':
+ if (windows_flag)
+ usage (stderr, 1);
+ unix_flag = 0;
+ windows_flag = 1;
+ shortname_flag = 1;
+ break;
+
+ case 'f':
+ file_arg = optarg;
+ break;
+
+ case 'M':
+ mode_flag = 1;
+ break;
+
+ case 'o':
+ options_from_file_flag = 1;
+ break;
+
+ case 'p':
+ path_flag = 1;
+ break;
+
+ case 'u':
+ if (windows_flag || mixed_flag)
+ usage (stderr, 1);
+ unix_flag = 1;
+ break;
+
+ case 'w':
+ if (windows_flag || mixed_flag)
+ usage (stderr, 1);
+ unix_flag = 0;
+ windows_flag = 1;
+ break;
+
+ case 'm':
+ unix_flag = 0;
+ windows_flag = 1;
+ mixed_flag = 1;
+ break;
+
+ case 'l':
+ longname_flag = 1;
+ break;
+
+ case 's':
+ shortname_flag = 1;
+ break;
+
+ case 't':
+ if (optarg == NULL)
+ usage (stderr, 1);
+
+ format_type_arg = (*optarg == '=') ? (optarg + 1) : (optarg);
+ if (strcasecmp (format_type_arg, "dos") == 0)
+ {
+ if (windows_flag || longname_flag)
+ usage (stderr, 1);
+ unix_flag = 0;
+ windows_flag = 1;
+ shortname_flag = 1;
+ }
+ else if (strcasecmp (format_type_arg, "mixed") == 0)
+ {
+ unix_flag = 0;
+ mixed_flag = 1;
+ }
+ else if (strcasecmp (format_type_arg, "unix") == 0)
+ {
+ if (windows_flag)
+ usage (stderr, 1);
+ unix_flag = 1;
+ }
+ else if (strcasecmp (format_type_arg, "windows") == 0)
+ {
+ if (mixed_flag)
+ usage (stderr, 1);
+ unix_flag = 0;
+ windows_flag = 1;
+ }
+ else
+ usage (stderr, 1);
+ break;
+
+ case 'A':
+ allusers_flag = 1;
+ break;
+
+ case 'D':
+ case 'H':
+ case 'P':
+ case 'S':
+ case 'W':
+ if (output_flag)
+ usage (stderr, 1);
+ output_flag = 1;
+ o = c;
+ break;
+
+ case 'i':
+ ignore_flag = 1;
+ break;
+
+ case 'h':
+ usage (stdout, 0);
+ break;
+
+ case 'v':
+ print_version ();
+ exit (0);
+
+ default:
+ usage (stderr, 1);
+ break;
+ }
+ }
+
+ if (options_from_file_flag && !file_arg)
+ usage (stderr, 1);
+
+ if (longname_flag && !windows_flag)
+ usage (stderr, 1);
+
+ if (shortname_flag && !windows_flag)
+ usage (stderr, 1);
+
+ if (!unix_flag && !windows_flag && !mixed_flag && !options_from_file_flag)
+ usage (stderr, 1);
+
+ if (!file_arg)
+ {
+ if (output_flag)
+ dowin (o);
+
+ if (optind > argc - 1)
+ usage (stderr, 1);
+
+ for (int i = optind; argv[i]; i++)
+ if (mode_flag)
+ report_mode (argv[i]);
+ else
+ doit (argv[i]);
+ }
+ else
+ {
+ FILE *fp;
+ char buf[PATH_MAX * 2 + 1];
+
+ if (argv[optind])
+ usage (stderr, 1);
+
+ if (strcmp (file_arg, "-") != 0)
+ fp = fopen (file_arg, "rt");
+ else
+ {
+ fp = stdin;
+ setmode (0, O_TEXT);
+ }
+ if (fp == NULL)
+ {
+ perror ("cygpath");
+ exit (1);
+ }
+
+ setbuf (stdout, NULL);
+ while (fgets (buf, sizeof (buf), fp) != NULL)
+ {
+ char *s = buf;
+ char *p = strchr (s, '\n');
+ if (p)
+ *p = '\0';
+ if (options_from_file_flag && *s == '-')
+ {
+ char c;
+ for (c = *++s; c && !isspace (c); c = *++s)
+ switch (c)
+ {
+ case 'a':
+ absolute_flag = 1;
+ break;
+ case 'i':
+ ignore_flag = 1;
+ break;
+ case 's':
+ shortname_flag = 1;
+ longname_flag = 0;
+ break;
+ case 'l':
+ shortname_flag = 0;
+ longname_flag = 1;
+ break;
+ case 'm':
+ unix_flag = 0;
+ windows_flag = 1;
+ mixed_flag = 1;
+ case 'w':
+ unix_flag = 0;
+ windows_flag = 1;
+ break;
+ case 'u':
+ windows_flag = 0;
+ unix_flag = 1;
+ break;
+ case 'p':
+ path_flag = 1;
+ break;
+ case 'D':
+ case 'H':
+ case 'P':
+ case 'S':
+ case 'W':
+ output_flag = 1;
+ o = c;
+ break;
+ }
+ if (*s)
+ do
+ s++;
+ while (*s && isspace (*s));
+ }
+ if (*s && !output_flag)
+ doit (s);
+ if (!*s && output_flag)
+ dowin (o);
+ }
+ }
+
+ exit (0);
+}
diff --git a/winsup/utils/dumper.cc b/winsup/utils/dumper.cc
new file mode 100644
index 00000000000..9d5de81098f
--- /dev/null
+++ b/winsup/utils/dumper.cc
@@ -0,0 +1,947 @@
+/* dumper.cc
+
+ Copyright 1999, 2001, 2002, 2004, 2006, 2007 Hat Inc.
+
+ Written by Egor Duda <deo@logos-m.ru>
+
+ This file is part of Cygwin.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (file COPYING.dumper) for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <bfd.h>
+#include <ansidecl.h>
+#include <elf/common.h>
+#include <elf/external.h>
+#include <sys/procfs.h>
+#include <sys/cygwin.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <windows.h>
+
+#include "dumper.h"
+#define NOTE_NAME_SIZE 16
+
+typedef struct _note_header
+ {
+ Elf_External_Note elf_note_header;
+ char name[NOTE_NAME_SIZE - 1]; /* external note contains first byte of data */
+ }
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif
+ note_header;
+
+static const char version[] = "$Revision$";
+
+BOOL verbose = FALSE;
+
+int deb_printf (const char *format,...)
+{
+ if (!verbose)
+ return 0;
+ va_list va;
+ va_start (va, format);
+ int ret_val = vprintf (format, va);
+ va_end (va);
+ return ret_val;
+}
+
+dumper::dumper (DWORD pid, DWORD tid, const char *file_name)
+{
+ this->file_name = strdup (file_name);
+
+ this->pid = pid;
+ this->tid = tid;
+ core_bfd = NULL;
+ excl_list = new exclusion (20);
+
+ list = last = NULL;
+
+ status_section = NULL;
+
+ memory_num = module_num = thread_num = 0;
+
+ hProcess = OpenProcess (PROCESS_ALL_ACCESS,
+ FALSE, /* no inheritance */
+ pid);
+ if (!hProcess)
+ {
+ fprintf (stderr, "Failed to open process #%lu, error %ld\n", pid, GetLastError ());
+ return;
+ }
+
+ init_core_dump ();
+
+ if (!sane ())
+ dumper_abort ();
+}
+
+dumper::~dumper ()
+{
+ close ();
+ free (file_name);
+}
+
+void
+dumper::dumper_abort ()
+{
+ close ();
+ unlink (file_name);
+}
+
+void
+dumper::close ()
+{
+ if (core_bfd)
+ bfd_close (core_bfd);
+ if (excl_list)
+ delete excl_list;
+ if (hProcess)
+ CloseHandle (hProcess);
+ core_bfd = NULL;
+ hProcess = NULL;
+ excl_list = NULL;
+}
+
+int
+dumper::sane ()
+{
+ if (hProcess == NULL || core_bfd == NULL || excl_list == NULL)
+ return 0;
+ return 1;
+}
+
+void
+print_section_name (bfd* abfd, asection* sect, PTR obj)
+{
+ deb_printf (" %s", bfd_get_section_name (abfd, sect));
+}
+
+void
+dumper::print_core_section_list ()
+{
+ deb_printf ("current sections:");
+ bfd_map_over_sections (core_bfd, &print_section_name, NULL);
+ deb_printf ("\n");
+}
+
+process_entity *
+dumper::add_process_entity_to_list (process_entity_type type)
+{
+ if (!sane ())
+ return NULL;
+
+ process_entity *new_entity = (process_entity *) malloc (sizeof (process_entity));
+ if (new_entity == NULL)
+ return NULL;
+ new_entity->next = NULL;
+ new_entity->section = NULL;
+ if (last == NULL)
+ list = new_entity;
+ else
+ last->next = new_entity;
+ last = new_entity;
+ return new_entity;
+}
+
+int
+dumper::add_thread (DWORD tid, HANDLE hThread)
+{
+ if (!sane ())
+ return 0;
+
+ CONTEXT *pcontext;
+
+ process_entity *new_entity = add_process_entity_to_list (pr_ent_thread);
+ if (new_entity == NULL)
+ return 0;
+ new_entity->type = pr_ent_thread;
+ thread_num++;
+
+ new_entity->u.thread.tid = tid;
+ new_entity->u.thread.hThread = hThread;
+
+ pcontext = &(new_entity->u.thread.context);
+ pcontext->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ if (!GetThreadContext (hThread, pcontext))
+ {
+ deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid, GetLastError ());
+ return 0;
+ }
+
+ deb_printf ("added thread %u\n", tid);
+ return 1;
+}
+
+int
+dumper::add_mem_region (LPBYTE base, DWORD size)
+{
+ if (!sane ())
+ return 0;
+
+ if (base == NULL || size == 0)
+ return 1; // just ignore empty regions
+
+ process_entity *new_entity = add_process_entity_to_list (pr_ent_memory);
+ if (new_entity == NULL)
+ return 0;
+ new_entity->type = pr_ent_memory;
+ memory_num++;
+
+ new_entity->u.memory.base = base;
+ new_entity->u.memory.size = size;
+
+ deb_printf ("added memory region %08x-%08x\n", (DWORD) base, (DWORD) base + size);
+ return 1;
+}
+
+/* split_add_mem_region scans list of regions to be excluded from dumping process
+ (excl_list) and removes all "excluded" parts from given region. */
+int
+dumper::split_add_mem_region (LPBYTE base, DWORD size)
+{
+ if (!sane ())
+ return 0;
+
+ if (base == NULL || size == 0)
+ return 1; // just ignore empty regions
+
+ LPBYTE last_base = base;
+
+ for (process_mem_region * p = excl_list->region;
+ p < excl_list->region + excl_list->last;
+ p++)
+ {
+ if (p->base >= base + size || p->base + p->size <= base)
+ continue;
+
+ if (p->base <= base)
+ {
+ last_base = p->base + p->size;
+ continue;
+ }
+
+ add_mem_region (last_base, p->base - last_base);
+ last_base = p->base + p->size;
+ }
+
+ if (last_base < base + size)
+ add_mem_region (last_base, base + size - last_base);
+
+ return 1;
+}
+
+int
+dumper::add_module (LPVOID base_address)
+{
+ if (!sane ())
+ return 0;
+
+ char *module_name = psapi_get_module_name (hProcess, (DWORD) base_address);
+ if (module_name == NULL)
+ return 1;
+
+ process_entity *new_entity = add_process_entity_to_list (pr_ent_module);
+ if (new_entity == NULL)
+ return 0;
+ new_entity->type = pr_ent_module;
+ module_num++;
+
+ new_entity->u.module.base_address = base_address;
+ new_entity->u.module.name = module_name;
+
+ parse_pe (module_name, excl_list);
+
+ deb_printf ("added module %08x %s\n", base_address, module_name);
+ return 1;
+}
+
+#define PAGE_BUFFER_SIZE 4096
+
+int
+dumper::collect_memory_sections ()
+{
+ if (!sane ())
+ return 0;
+
+ LPBYTE current_page_address;
+ LPBYTE last_base = (LPBYTE) 0xFFFFFFFF;
+ DWORD last_size = 0;
+ DWORD done;
+
+ char mem_buf[PAGE_BUFFER_SIZE];
+
+ MEMORY_BASIC_INFORMATION mbi;
+
+ if (hProcess == NULL)
+ return 0;
+
+ for (current_page_address = 0; current_page_address < (LPBYTE) 0xFFFF0000;)
+ {
+ if (!VirtualQueryEx (hProcess, current_page_address, &mbi, sizeof (mbi)))
+ break;
+
+ int skip_region_p = 0;
+
+ if (mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD) ||
+ mbi.State != MEM_COMMIT)
+ skip_region_p = 1;
+
+ if (!skip_region_p)
+ {
+ /* just to make sure that later we'll be able to read it.
+ According to MS docs either region is all-readable or
+ all-nonreadable */
+ if (!ReadProcessMemory (hProcess, current_page_address, mem_buf, sizeof (mem_buf), &done))
+ {
+ DWORD err = GetLastError ();
+ const char *pt[10];
+ pt[0] = (mbi.Protect & PAGE_READONLY) ? "RO " : "";
+ pt[1] = (mbi.Protect & PAGE_READWRITE) ? "RW " : "";
+ pt[2] = (mbi.Protect & PAGE_WRITECOPY) ? "WC " : "";
+ pt[3] = (mbi.Protect & PAGE_EXECUTE) ? "EX " : "";
+ pt[4] = (mbi.Protect & PAGE_EXECUTE_READ) ? "EXRO " : "";
+ pt[5] = (mbi.Protect & PAGE_EXECUTE_READWRITE) ? "EXRW " : "";
+ pt[6] = (mbi.Protect & PAGE_EXECUTE_WRITECOPY) ? "EXWC " : "";
+ pt[7] = (mbi.Protect & PAGE_GUARD) ? "GRD " : "";
+ pt[8] = (mbi.Protect & PAGE_NOACCESS) ? "NA " : "";
+ pt[9] = (mbi.Protect & PAGE_NOCACHE) ? "NC " : "";
+ char buf[10 * 6];
+ buf[0] = '\0';
+ for (int i = 0; i < 10; i++)
+ strcat (buf, pt[i]);
+
+ deb_printf ("warning: failed to read memory at %08x-%08x (protect = %s), error %ld.\n",
+ (DWORD) current_page_address,
+ (DWORD) current_page_address + mbi.RegionSize,
+ buf, err);
+ skip_region_p = 1;
+ }
+ }
+
+ if (!skip_region_p)
+ {
+ if (last_base + last_size == current_page_address)
+ last_size += mbi.RegionSize;
+ else
+ {
+ split_add_mem_region (last_base, last_size);
+ last_base = (LPBYTE) mbi.BaseAddress;
+ last_size = mbi.RegionSize;
+ }
+ }
+ else
+ {
+ split_add_mem_region (last_base, last_size);
+ last_base = NULL;
+ last_size = 0;
+ }
+
+ current_page_address += mbi.RegionSize;
+ }
+
+ /* dump last sections, if any */
+ split_add_mem_region (last_base, last_size);
+ return 1;
+};
+
+int
+dumper::dump_memory_region (asection * to, process_mem_region * memory)
+{
+ if (!sane ())
+ return 0;
+
+ DWORD size = memory->size;
+ DWORD todo;
+ DWORD done;
+ LPBYTE pos = memory->base;
+ DWORD sect_pos = 0;
+
+ if (to == NULL || memory == NULL)
+ return 0;
+
+ char mem_buf[PAGE_BUFFER_SIZE];
+
+ while (size > 0)
+ {
+ todo = min (size, PAGE_BUFFER_SIZE);
+ if (!ReadProcessMemory (hProcess, pos, mem_buf, todo, &done))
+ {
+ deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos, todo, GetLastError ());
+ return 0;
+ }
+ size -= done;
+ pos += done;
+ if (!bfd_set_section_contents (core_bfd, to, mem_buf, sect_pos, done))
+ {
+ bfd_perror ("writing memory region to bfd");
+ dumper_abort ();
+ return 0;
+ };
+ sect_pos += done;
+ }
+ return 1;
+}
+
+int
+dumper::dump_thread (asection * to, process_thread * thread)
+{
+ if (!sane ())
+ return 0;
+
+ if (to == NULL || thread == NULL)
+ return 0;
+
+ win32_pstatus thread_pstatus;
+
+ note_header header;
+ bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
+ bfd_putl32 (sizeof (thread_pstatus), header.elf_note_header.descsz);
+ bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
+ strncpy ((char *) &header.elf_note_header.name, "win32thread", NOTE_NAME_SIZE);
+
+ thread_pstatus.data_type = NOTE_INFO_THREAD;
+ thread_pstatus.data.thread_info.tid = thread->tid;
+
+ if (tid == 0)
+ {
+ /* this is a special case. we don't know, which thread
+ was active when exception occured, so let's blame
+ the first one */
+ thread_pstatus.data.thread_info.is_active_thread = TRUE;
+ tid = (DWORD) - 1;
+ }
+ else if (tid > 0 && thread->tid == tid)
+ thread_pstatus.data.thread_info.is_active_thread = TRUE;
+ else
+ thread_pstatus.data.thread_info.is_active_thread = FALSE;
+
+ memcpy (&(thread_pstatus.data.thread_info.thread_context),
+ &(thread->context),
+ sizeof (thread->context));
+
+ if (!bfd_set_section_contents (core_bfd, to, &header,
+ 0,
+ sizeof (header)) ||
+ !bfd_set_section_contents (core_bfd, to, &thread_pstatus,
+ sizeof (header),
+ sizeof (thread_pstatus)))
+ {
+ bfd_perror ("writing thread info to bfd");
+ dumper_abort ();
+ return 0;
+ };
+ return 1;
+}
+
+int
+dumper::dump_module (asection * to, process_module * module)
+{
+ if (!sane ())
+ return 0;
+
+ if (to == NULL || module == NULL)
+ return 0;
+
+ struct win32_pstatus *module_pstatus_ptr;
+
+ int note_length = sizeof (struct win32_pstatus) + strlen (module->name);
+
+ char *buf = (char *) malloc (note_length);
+
+ if (!buf)
+ {
+ fprintf (stderr, "Error alloating memory. Dumping aborted.\n");
+ goto out;
+ };
+
+ module_pstatus_ptr = (struct win32_pstatus *) buf;
+
+ note_header header;
+ bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
+ bfd_putl32 (note_length, header.elf_note_header.descsz);
+ bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
+ strncpy ((char *) &header.elf_note_header.name, "win32module", NOTE_NAME_SIZE);
+
+ module_pstatus_ptr->data_type = NOTE_INFO_MODULE;
+ module_pstatus_ptr->data.module_info.base_address = module->base_address;
+ module_pstatus_ptr->data.module_info.module_name_size = strlen (module->name) + 1;
+ strcpy (module_pstatus_ptr->data.module_info.module_name, module->name);
+
+ if (!bfd_set_section_contents (core_bfd, to, &header,
+ 0,
+ sizeof (header)) ||
+ !bfd_set_section_contents (core_bfd, to, module_pstatus_ptr,
+ sizeof (header),
+ note_length))
+ {
+ bfd_perror ("writing module info to bfd");
+ goto out;
+ };
+ return 1;
+
+out:
+ if (buf)
+ free (buf);
+ dumper_abort ();
+ return 0;
+
+}
+
+int
+dumper::collect_process_information ()
+{
+ int exception_level = 0;
+
+ if (!sane ())
+ return 0;
+
+ if (!DebugActiveProcess (pid))
+ {
+ fprintf (stderr, "Cannot attach to process #%lu, error %ld", pid, GetLastError ());
+ return 0;
+ }
+
+ char event_name[sizeof ("cygwin_error_start_event") + 20];
+ sprintf (event_name, "cygwin_error_start_event%16lx", pid);
+ HANDLE sync_with_debugee = OpenEvent (EVENT_MODIFY_STATE, FALSE, event_name);
+
+ DEBUG_EVENT current_event;
+
+ while (1)
+ {
+ if (!WaitForDebugEvent (&current_event, 20000))
+ return 0;
+
+ deb_printf ("got debug event %d\n", current_event.dwDebugEventCode);
+
+ switch (current_event.dwDebugEventCode)
+ {
+ case CREATE_THREAD_DEBUG_EVENT:
+
+ if (!add_thread (current_event.dwThreadId,
+ current_event.u.CreateThread.hThread))
+ goto failed;
+
+ break;
+
+ case CREATE_PROCESS_DEBUG_EVENT:
+
+ if (!add_module (current_event.u.CreateProcessInfo.lpBaseOfImage) ||
+ !add_thread (current_event.dwThreadId,
+ current_event.u.CreateProcessInfo.hThread))
+ goto failed;
+
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+
+ deb_printf ("debugee quits");
+ ContinueDebugEvent (current_event.dwProcessId,
+ current_event.dwThreadId,
+ DBG_CONTINUE);
+
+ return 1;
+
+ break;
+
+ case LOAD_DLL_DEBUG_EVENT:
+
+ if (!add_module (current_event.u.LoadDll.lpBaseOfDll))
+ goto failed;
+
+ break;
+
+ case EXCEPTION_DEBUG_EVENT:
+
+ exception_level++;
+ if (exception_level == 2)
+ break;
+ else if (exception_level > 2)
+ return 0;
+
+ collect_memory_sections ();
+
+ /* got all info. time to dump */
+
+ if (!prepare_core_dump ())
+ {
+ fprintf (stderr, "Failed to prepare core dump\n");
+ goto failed;
+ };
+
+ if (!write_core_dump ())
+ {
+ fprintf (stderr, "Failed to write core dump\n");
+ goto failed;
+ };
+
+ /* signal a debugee that we've finished */
+ if (sync_with_debugee)
+ SetEvent (sync_with_debugee);
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+ ContinueDebugEvent (current_event.dwProcessId,
+ current_event.dwThreadId,
+ DBG_CONTINUE);
+ }
+failed:
+ /* set debugee free */
+ if (sync_with_debugee)
+ SetEvent (sync_with_debugee);
+
+ return 0;
+}
+
+int
+dumper::init_core_dump ()
+{
+ bfd_init ();
+
+ core_bfd = bfd_openw (file_name, "elf32-i386");
+ if (core_bfd == NULL)
+ {
+ bfd_perror ("opening bfd");
+ goto failed;
+ }
+
+ if (!bfd_set_format (core_bfd, bfd_core))
+ {
+ bfd_perror ("setting bfd format");
+ goto failed;
+ }
+
+ if (!bfd_set_arch_mach (core_bfd, bfd_arch_i386, 0))
+ {
+ bfd_perror ("setting bfd architecture");
+ goto failed;
+ }
+
+ return 1;
+
+failed:
+ dumper_abort ();
+ return 0;
+
+}
+
+int
+dumper::prepare_core_dump ()
+{
+ if (!sane ())
+ return 0;
+
+ int sect_no = 0;
+ char sect_name[50];
+
+ flagword sect_flags;
+ DWORD sect_size;
+ bfd_vma sect_vma;
+
+ asection *new_section;
+
+ for (process_entity * p = list; p != NULL; p = p->next)
+ {
+ sect_no++;
+
+ unsigned long phdr_type = PT_LOAD;
+
+ switch (p->type)
+ {
+ case pr_ent_memory:
+ sprintf (sect_name, ".mem/%u", sect_no);
+ sect_flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD;
+ sect_size = p->u.memory.size;
+ sect_vma = (bfd_vma) (p->u.memory.base);
+ phdr_type = PT_LOAD;
+ break;
+
+ case pr_ent_thread:
+ sprintf (sect_name, ".note/%u", sect_no);
+ sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
+ sect_size = sizeof (note_header) + sizeof (struct win32_pstatus);
+ sect_vma = 0;
+ phdr_type = PT_NOTE;
+ break;
+
+ case pr_ent_module:
+ sprintf (sect_name, ".note/%u", sect_no);
+ sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
+ sect_size = sizeof (note_header) + sizeof (struct win32_pstatus) +
+ (bfd_size_type) (strlen (p->u.module.name));
+ sect_vma = 0;
+ phdr_type = PT_NOTE;
+ break;
+
+ default:
+ continue;
+ }
+
+ if (p->type == pr_ent_module && status_section != NULL)
+ {
+ if (!bfd_set_section_size (core_bfd,
+ status_section,
+ (bfd_get_section_size (status_section)
+ + sect_size)))
+ {
+ bfd_perror ("resizing status section");
+ goto failed;
+ };
+ continue;
+ }
+
+ deb_printf ("creating section (type%u) %s(%u), flags=%08x\n",
+ p->type, sect_name, sect_size, sect_flags);
+
+ bfd_set_error (bfd_error_no_error);
+ char *buf = strdup (sect_name);
+ new_section = bfd_make_section (core_bfd, buf);
+ if (new_section == NULL)
+ {
+ if (bfd_get_error () == bfd_error_no_error)
+ fprintf (stderr, "error creating new section (%s), section already exists.\n", buf);
+ else
+ bfd_perror ("creating section");
+ goto failed;
+ }
+
+ if (!bfd_set_section_flags (core_bfd, new_section, sect_flags) ||
+ !bfd_set_section_size (core_bfd, new_section, sect_size))
+ {
+ bfd_perror ("setting section attributes");
+ goto failed;
+ };
+
+ new_section->vma = sect_vma;
+ new_section->lma = 0;
+ new_section->output_section = new_section;
+ new_section->output_offset = 0;
+ p->section = new_section;
+ int section_count = 1;
+
+ bfd_boolean filehdr = 0;
+ bfd_boolean phdrs = 0;
+
+ bfd_vma at = 0;
+ bfd_boolean valid_at = 0;
+
+ flagword flags = 0;
+ bfd_boolean valid_flags = 1;
+
+ if (p->type == pr_ent_memory)
+ {
+ MEMORY_BASIC_INFORMATION mbi;
+ if (!VirtualQueryEx (hProcess, (LPVOID)sect_vma, &mbi, sizeof (mbi)))
+ {
+ bfd_perror ("getting mem region flags");
+ goto failed;
+ }
+
+ static const struct
+ {
+ DWORD protect;
+ flagword flags;
+ } mappings[] =
+ {
+ { PAGE_READONLY, PF_R },
+ { PAGE_READWRITE, PF_R | PF_W },
+ { PAGE_WRITECOPY, PF_W },
+ { PAGE_EXECUTE, PF_X },
+ { PAGE_EXECUTE_READ, PF_X | PF_R },
+ { PAGE_EXECUTE_READWRITE, PF_X | PF_R | PF_W },
+ { PAGE_EXECUTE_WRITECOPY, PF_X | PF_W }
+ };
+
+ for (size_t i = 0;
+ i < sizeof (mappings) / sizeof (mappings[0]);
+ i++)
+ if ((mbi.Protect & mappings[i].protect) != 0)
+ flags |= mappings[i].flags;
+ }
+
+ if (!bfd_record_phdr (core_bfd, phdr_type,
+ valid_flags, flags,
+ valid_at, at,
+ filehdr, phdrs,
+ section_count, &new_section))
+ {
+ bfd_perror ("recording program headers");
+ goto failed;
+ }
+ }
+ return 1;
+
+failed:
+ dumper_abort ();
+ return 0;
+}
+
+int
+dumper::write_core_dump ()
+{
+ if (!sane ())
+ return 0;
+
+ for (process_entity * p = list; p != NULL; p = p->next)
+ {
+ if (p->section == NULL)
+ continue;
+
+ deb_printf ("writing section type=%u base=%08x size=%08x flags=%08x\n",
+ p->type,
+ p->section->vma,
+ bfd_get_section_size (p->section),
+ p->section->flags);
+
+ switch (p->type)
+ {
+ case pr_ent_memory:
+ dump_memory_region (p->section, &(p->u.memory));
+ break;
+
+ case pr_ent_thread:
+ dump_thread (p->section, &(p->u.thread));
+ break;
+
+ case pr_ent_module:
+ dump_module (p->section, &(p->u.module));
+ break;
+
+ default:
+ continue;
+
+ }
+ }
+ return 1;
+}
+
+static void
+usage (FILE *stream, int status)
+{
+ fprintf (stream, "\
+Usage: dumper [OPTION] FILENAME WIN32PID\n\
+Dump core from WIN32PID to FILENAME.core\n\
+\n\
+ -d, --verbose be verbose while dumping\n\
+ -h, --help output help information and exit\n\
+ -q, --quiet be quiet while dumping (default)\n\
+ -v, --version output version information and exit\n\
+");
+ exit (status);
+}
+
+struct option longopts[] = {
+ {"verbose", no_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"version", no_argument, 0, 'v'},
+ {0, no_argument, NULL, 0}
+};
+
+static void
+print_version ()
+{
+ const char *v = strchr (version, ':');
+ int len;
+ if (!v)
+ {
+ v = "?";
+ len = 1;
+ }
+ else
+ {
+ v += 2;
+ len = strchr (v, ' ') - v;
+ }
+ printf ("\
+dumper (cygwin) %.*s\n\
+Core Dumper for Cygwin\n\
+Copyright 1999, 2001, 2002 Red Hat, Inc.\n", len, v);
+}
+
+int
+main (int argc, char **argv)
+{
+ int opt;
+ const char *p = "";
+ DWORD pid;
+ char win32_name [MAX_PATH];
+
+ while ((opt = getopt_long (argc, argv, "dqhv", longopts, NULL) ) != EOF)
+ switch (opt)
+ {
+ case 'd':
+ verbose = TRUE;
+ break;
+ case 'q':
+ verbose = FALSE;
+ break;
+ case 'h':
+ usage (stdout, 0);
+ case 'v':
+ print_version ();
+ exit (0);
+ default:
+ usage (stderr, 1);
+ break;
+ }
+
+ if (argv && *(argv + optind) && *(argv + optind +1))
+ {
+ *win32_name = '\0';
+ cygwin_conv_to_win32_path (*(argv + optind), win32_name);
+ if ((p = strrchr (win32_name, '\\')))
+ p++;
+ else
+ p = win32_name;
+ pid = strtoul (*(argv + optind + 1), NULL, 10);
+ }
+ else
+ {
+ usage (stderr, 1);
+ return -1;
+ }
+
+ char *core_file = (char *) malloc (strlen (p) + sizeof (".core"));
+ if (!core_file)
+ {
+ fprintf (stderr, "error allocating memory\n");
+ return -1;
+ }
+ sprintf (core_file, "%s.core", p);
+
+ DWORD tid = 0;
+
+ if (verbose)
+ printf ("dumping process #%lu to %s\n", pid, core_file);
+
+ dumper d (pid, tid, core_file);
+ if (!d.sane ())
+ return -1;
+ d.collect_process_information ();
+ free (core_file);
+
+ return 0;
+};
diff --git a/winsup/utils/dumper.h b/winsup/utils/dumper.h
new file mode 100644
index 00000000000..4b8d2bdf728
--- /dev/null
+++ b/winsup/utils/dumper.h
@@ -0,0 +1,142 @@
+/* dumper.h
+
+ Copyright 1999,2001 Red Hat Inc.
+
+ Written by Egor Duda <deo@logos-m.ru>
+
+ This file is part of Cygwin.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (file COPYING.dumper) for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _DUMPER_H_
+#define _DUMPER_H_
+
+#include <windows.h>
+
+typedef struct
+{
+ LPBYTE base;
+ DWORD size;
+} process_mem_region;
+
+typedef struct
+{
+ DWORD tid;
+ HANDLE hThread;
+ CONTEXT context;
+} process_thread;
+
+typedef struct
+{
+ LPVOID base_address;
+ char* name;
+} process_module;
+
+enum process_entity_type
+{
+ pr_ent_memory,
+ pr_ent_thread,
+ pr_ent_module
+};
+
+typedef struct _process_entity
+{
+ process_entity_type type;
+ union
+ {
+ process_thread thread;
+ process_mem_region memory;
+ process_module module;
+ } u;
+ asection* section;
+ struct _process_entity* next;
+} process_entity;
+
+class exclusion
+{
+public:
+ int last;
+ int size;
+ int step;
+ process_mem_region* region;
+
+ exclusion ( int step ) { last = size = 0;
+ this->step = step;
+ region = NULL; }
+ ~exclusion () { free ( region ); }
+ int add ( LPBYTE mem_base, DWORD mem_size );
+ int sort_and_check ();
+};
+
+#define PAGE_BUFFER_SIZE 4096
+
+class dumper
+{
+ DWORD pid;
+ DWORD tid; /* thread id of active thread */
+ HANDLE hProcess;
+ process_entity* list;
+ process_entity* last;
+ exclusion* excl_list;
+
+ char* file_name;
+ bfd* core_bfd;
+
+ asection* status_section;
+
+ int memory_num;
+ int module_num;
+ int thread_num;
+
+ void close ();
+ void dumper_abort ();
+
+ process_entity* add_process_entity_to_list ( process_entity_type type );
+ int add_thread ( DWORD tid, HANDLE hThread );
+ int add_mem_region ( LPBYTE base, DWORD size );
+
+ /* break mem_region by excl_list and add add all subregions */
+ int split_add_mem_region ( LPBYTE base, DWORD size );
+
+ int add_module ( LPVOID base_address );
+
+ int collect_memory_sections ();
+ int dump_memory_region ( asection* to, process_mem_region* memory );
+ int dump_thread ( asection* to, process_thread* thread );
+ int dump_module ( asection* to, process_module* module );
+
+public:
+ int sane ();
+
+ int collect_process_information ();
+ void print_core_section_list ();
+
+ dumper ( DWORD pid, DWORD tid, const char* name );
+ ~dumper ();
+
+ int init_core_dump ();
+ int prepare_core_dump ();
+ int write_core_dump ();
+};
+
+extern int deb_printf ( const char* format, ... );
+
+extern char* psapi_get_module_name ( HANDLE hProcess, DWORD BaseAddress );
+
+extern int parse_pe ( const char* file_name, exclusion* excl_list );
+
+extern BOOL verbose;
+
+#endif
diff --git a/winsup/utils/mkgroup.c b/winsup/utils/mkgroup.c
new file mode 100644
index 00000000000..1926d915668
--- /dev/null
+++ b/winsup/utils/mkgroup.c
@@ -0,0 +1,797 @@
+/* mkgroup.c:
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+ 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. */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+#include <windows.h>
+#include <sys/cygwin.h>
+#include <getopt.h>
+#include <lmaccess.h>
+#include <lmapibuf.h>
+#include <ntsecapi.h>
+#include <ntdef.h>
+
+#define print_win_error(x) _print_win_error(x, __LINE__)
+
+static const char version[] = "$Revision$";
+
+typedef struct {
+ LPWSTR DomainControllerName;
+ LPWSTR DomainControllerAddress;
+ ULONG DomainControllerAddressType;
+ GUID DomainGuid;
+ LPWSTR DomainName;
+ LPWSTR DnsForestName;
+ ULONG Flags;
+ LPWSTR DcSiteName;
+ LPWSTR ClientSiteName;
+} *PDOMAIN_CONTROLLER_INFOW;
+
+SID_IDENTIFIER_AUTHORITY sid_world_auth = {SECURITY_WORLD_SID_AUTHORITY};
+SID_IDENTIFIER_AUTHORITY sid_nt_auth = {SECURITY_NT_AUTHORITY};
+
+NET_API_STATUS WINAPI (*netapibufferallocate)(DWORD,PVOID*);
+NET_API_STATUS WINAPI (*netapibufferfree)(PVOID);
+NET_API_STATUS WINAPI (*netgroupenum)(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
+NET_API_STATUS WINAPI (*netgroupgetinfo)(LPWSTR,LPWSTR,DWORD,PBYTE*);
+NET_API_STATUS WINAPI (*netlocalgroupenum)(LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
+NET_API_STATUS WINAPI (*netlocalgroupgetmembers)(LPWSTR,LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
+NET_API_STATUS WINAPI (*netgetdcname)(LPWSTR,LPWSTR,PBYTE*);
+NET_API_STATUS WINAPI (*netgroupgetusers)(LPWSTR,LPWSTR,DWORD,PBYTE*,DWORD,PDWORD,PDWORD,PDWORD);
+
+NTSTATUS NTAPI (*lsaclose)(LSA_HANDLE);
+NTSTATUS NTAPI (*lsaopenpolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE);
+NTSTATUS NTAPI (*lsaqueryinformationpolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
+NTSTATUS NTAPI (*lsafreememory)(PVOID);
+
+NET_API_STATUS WINAPI (*dsgetdcname)(LPWSTR,LPWSTR,GUID*,LPWSTR,ULONG,PDOMAIN_CONTROLLER_INFOW*);
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+BOOL
+load_netapi ()
+{
+ HANDLE h = LoadLibrary ("netapi32.dll");
+
+ if (!h)
+ return FALSE;
+
+ if (!(netapibufferallocate = (void *) GetProcAddress (h, "NetApiBufferAllocate")))
+ return FALSE;
+ if (!(netapibufferfree = (void *) GetProcAddress (h, "NetApiBufferFree")))
+ return FALSE;
+ if (!(netgroupenum = (void *) GetProcAddress (h, "NetGroupEnum")))
+ return FALSE;
+ if (!(netgroupgetinfo = (void *) GetProcAddress (h, "NetGroupGetInfo")))
+ return FALSE;
+ if (!(netgroupgetusers = (void *) GetProcAddress (h, "NetGroupGetUsers")))
+ return FALSE;
+ if (!(netlocalgroupenum = (void *) GetProcAddress (h, "NetLocalGroupEnum")))
+ return FALSE;
+ if (!(netlocalgroupgetmembers = (void *) GetProcAddress (h, "NetLocalGroupGetMembers")))
+ return FALSE;
+ if (!(netgetdcname = (void *) GetProcAddress (h, "NetGetDCName")))
+ return FALSE;
+
+ dsgetdcname = (void *) GetProcAddress (h, "DsGetDcNameW");
+
+ if (!(h = LoadLibrary ("advapi32.dll")))
+ return FALSE;
+
+ if (!(lsaclose = (void *) GetProcAddress (h, "LsaClose")))
+ return FALSE;
+ if (!(lsaopenpolicy = (void *) GetProcAddress (h, "LsaOpenPolicy")))
+ return FALSE;
+ if (!(lsaqueryinformationpolicy = (void *) GetProcAddress (h, "LsaQueryInformationPolicy")))
+ return FALSE;
+ if (!(lsafreememory = (void *) GetProcAddress (h, "LsaFreeMemory")))
+ return FALSE;
+
+ return TRUE;
+}
+
+char *
+put_sid (PSID sid)
+{
+ static char s[512];
+ char t[32];
+ DWORD i;
+
+ strcpy (s, "S-1-");
+ sprintf(t, "%u", GetSidIdentifierAuthority (sid)->Value[5]);
+ strcat (s, t);
+ for (i = 0; i < *GetSidSubAuthorityCount (sid); ++i)
+ {
+ sprintf(t, "-%lu", *GetSidSubAuthority (sid, i));
+ strcat (s, t);
+ }
+ return s;
+}
+
+void
+psx_dir (char *in, char *out)
+{
+ if (isalpha (in[0]) && in[1] == ':')
+ {
+ sprintf (out, "/cygdrive/%c", in[0]);
+ in += 2;
+ out += strlen (out);
+ }
+
+ while (*in)
+ {
+ if (*in == '\\')
+ *out = '/';
+ else
+ *out = *in;
+ in++;
+ out++;
+ }
+
+ *out = '\0';
+}
+
+void
+uni2ansi (LPWSTR wcs, char *mbs, int size)
+{
+ if (wcs)
+ WideCharToMultiByte (CP_ACP, 0, wcs, -1, mbs, size, NULL, NULL);
+ else
+ *mbs = '\0';
+}
+
+void
+_print_win_error(DWORD code, int line)
+{
+ char buf[4096];
+
+ if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ code,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) buf, sizeof (buf), NULL))
+ fprintf (stderr, "mkgroup (%d): [%lu] %s", line, code, buf);
+ else
+ fprintf (stderr, "mkgroup (%d): error %lu", line, code);
+}
+
+void
+enum_local_users (LPWSTR groupname)
+{
+ LOCALGROUP_MEMBERS_INFO_1 *buf1;
+ DWORD entries = 0;
+ DWORD total = 0;
+ DWORD reshdl = 0;
+
+ if (!netlocalgroupgetmembers (NULL, groupname,
+ 1, (void *) &buf1,
+ MAX_PREFERRED_LENGTH,
+ &entries, &total, &reshdl))
+ {
+ unsigned i, first = 1;
+
+ for (i = 0; i < entries; ++i)
+ if (buf1[i].lgrmi1_sidusage == SidTypeUser)
+ {
+ char user[256];
+
+ if (!first)
+ printf (",");
+ first = 0;
+ uni2ansi (buf1[i].lgrmi1_name, user, sizeof (user));
+ printf ("%s", user);
+ }
+ netapibufferfree (buf1);
+ }
+}
+
+int
+enum_local_groups (int print_sids, int print_users, char *disp_groupname)
+{
+ LOCALGROUP_INFO_0 *buffer;
+ DWORD entriesread = 0;
+ DWORD totalentries = 0;
+ DWORD resume_handle = 0;
+ WCHAR uni_name[512];
+ DWORD rc;
+
+ do
+ {
+ DWORD i;
+
+ if (disp_groupname != NULL)
+ {
+ MultiByteToWideChar (CP_ACP, 0, disp_groupname, -1, uni_name, 512 );
+ rc = netapibufferallocate(sizeof(LOCALGROUP_INFO_0), (void *) &buffer );
+ buffer[0].lgrpi0_name = (LPWSTR) & uni_name;
+ entriesread=1;
+ }
+ else
+ rc = netlocalgroupenum (NULL, 0, (void *) &buffer, 1024,
+ &entriesread, &totalentries, &resume_handle);
+ switch (rc)
+ {
+ case ERROR_ACCESS_DENIED:
+ print_win_error(rc);
+ exit (1);
+
+ case ERROR_MORE_DATA:
+ case ERROR_SUCCESS:
+ break;
+
+ default:
+ print_win_error(rc);
+ exit (1);
+ }
+
+ for (i = 0; i < entriesread; i++)
+ {
+ char localgroup_name[100];
+ char domain_name[100];
+ DWORD domname_len = 100;
+ char psid_buffer[1024];
+ PSID psid = (PSID) psid_buffer;
+ DWORD sid_length = 1024;
+ DWORD gid;
+ SID_NAME_USE acc_type;
+ uni2ansi (buffer[i].lgrpi0_name, localgroup_name, sizeof (localgroup_name));
+
+ if (!LookupAccountName (NULL, localgroup_name, psid,
+ &sid_length, domain_name, &domname_len,
+ &acc_type))
+ {
+ print_win_error(rc);
+ fprintf(stderr, " (%s)\n", localgroup_name);
+ continue;
+ }
+ else if (acc_type == SidTypeDomain)
+ {
+ char domname[356];
+
+ strcpy (domname, domain_name);
+ strcat (domname, "\\");
+ strcat (domname, localgroup_name);
+ sid_length = 1024;
+ domname_len = 100;
+ if (!LookupAccountName (NULL, domname,
+ psid, &sid_length,
+ domain_name, &domname_len,
+ &acc_type))
+ {
+ print_win_error(rc);
+ fprintf(stderr, " (%s)\n", domname);
+ continue;
+ }
+ }
+
+ gid = *GetSidSubAuthority (psid, *GetSidSubAuthorityCount(psid) - 1);
+
+ printf ("%s:%s:%ld:", localgroup_name,
+ print_sids ? put_sid (psid) : "",
+ gid);
+ if (print_users)
+ enum_local_users (buffer[i].lgrpi0_name);
+ printf ("\n");
+ }
+
+ netapibufferfree (buffer);
+
+ }
+ while (rc == ERROR_MORE_DATA);
+
+ return 0;
+}
+
+void
+enum_users (LPWSTR servername, LPWSTR groupname)
+{
+ GROUP_USERS_INFO_0 *buf1;
+ DWORD entries = 0;
+ DWORD total = 0;
+ DWORD reshdl = 0;
+
+ if (!netgroupgetusers (servername, groupname,
+ 0, (void *) &buf1,
+ MAX_PREFERRED_LENGTH,
+ &entries, &total, &reshdl))
+ {
+ unsigned i, first = 1;
+
+ for (i = 0; i < entries; ++i)
+ {
+ char user[256];
+
+ if (!first)
+ printf (",");
+ first = 0;
+ uni2ansi (buf1[i].grui0_name, user, sizeof (user));
+ printf ("%s", user);
+ }
+ netapibufferfree (buf1);
+ }
+}
+
+void
+enum_groups (LPWSTR servername, int print_sids, int print_users, int id_offset,
+ char *disp_groupname)
+{
+ GROUP_INFO_2 *buffer;
+ DWORD entriesread = 0;
+ DWORD totalentries = 0;
+ DWORD resume_handle = 0;
+ WCHAR uni_name[512];
+ DWORD rc;
+ char ansi_srvname[256];
+
+ if (servername)
+ uni2ansi (servername, ansi_srvname, sizeof (ansi_srvname));
+
+ do
+ {
+ DWORD i;
+
+ if (disp_groupname != NULL)
+ {
+ MultiByteToWideChar (CP_ACP, 0, disp_groupname, -1, uni_name, 512 );
+ rc = netgroupgetinfo(servername, (LPWSTR) & uni_name, 2,
+ (void *) &buffer );
+ entriesread=1;
+ }
+ else
+ rc = netgroupenum (servername, 2, (void *) & buffer, MAX_PREFERRED_LENGTH,
+ &entriesread, &totalentries, &resume_handle);
+ switch (rc)
+ {
+ case ERROR_ACCESS_DENIED:
+ print_win_error(rc);
+ exit (1);
+
+ case ERROR_MORE_DATA:
+ case ERROR_SUCCESS:
+ break;
+
+ default:
+ print_win_error(rc);
+ exit (1);
+ }
+
+ for (i = 0; i < entriesread; i++)
+ {
+ char groupname[100];
+ char domain_name[100];
+ DWORD domname_len = 100;
+ char psid_buffer[1024];
+ PSID psid = (PSID) psid_buffer;
+ DWORD sid_length = 1024;
+ SID_NAME_USE acc_type;
+
+ int gid = buffer[i].grpi2_group_id;
+ uni2ansi (buffer[i].grpi2_name, groupname, sizeof (groupname));
+ if (print_sids)
+ {
+ if (!LookupAccountName (servername ? ansi_srvname : NULL,
+ groupname,
+ psid, &sid_length,
+ domain_name, &domname_len,
+ &acc_type))
+ {
+ print_win_error(rc);
+ fprintf(stderr, " (%s)\n", groupname);
+ continue;
+ }
+ else if (acc_type == SidTypeDomain)
+ {
+ char domname[356];
+
+ strcpy (domname, domain_name);
+ strcat (domname, "\\");
+ strcat (domname, groupname);
+ sid_length = 1024;
+ domname_len = 100;
+ if (!LookupAccountName (servername ? ansi_srvname : NULL,
+ domname,
+ psid, &sid_length,
+ domain_name, &domname_len,
+ &acc_type))
+ {
+ print_win_error(rc);
+ fprintf(stderr, " (%s)\n", domname);
+ continue;
+ }
+ }
+ }
+ printf ("%s:%s:%u:", groupname,
+ print_sids ? put_sid (psid) : "",
+ gid + id_offset);
+ if (print_users)
+ enum_users (servername, buffer[i].grpi2_name);
+ printf ("\n");
+ }
+
+ netapibufferfree (buffer);
+
+ }
+ while (rc == ERROR_MORE_DATA);
+}
+
+void
+print_special (int print_sids,
+ PSID_IDENTIFIER_AUTHORITY auth, BYTE cnt,
+ DWORD sub1, DWORD sub2, DWORD sub3, DWORD sub4,
+ DWORD sub5, DWORD sub6, DWORD sub7, DWORD sub8)
+{
+ char name[256], dom[256];
+ DWORD len, len2, rid;
+ PSID sid;
+ SID_NAME_USE use;
+
+ if (AllocateAndInitializeSid (auth, cnt, sub1, sub2, sub3, sub4,
+ sub5, sub6, sub7, sub8, &sid))
+ {
+ if (LookupAccountSid (NULL, sid,
+ name, (len = 256, &len),
+ dom, (len2 = 256, &len),
+ &use))
+ {
+ if (sub8)
+ rid = sub8;
+ else if (sub7)
+ rid = sub7;
+ else if (sub6)
+ rid = sub6;
+ else if (sub5)
+ rid = sub5;
+ else if (sub4)
+ rid = sub4;
+ else if (sub3)
+ rid = sub3;
+ else if (sub2)
+ rid = sub2;
+ else
+ rid = sub1;
+ printf ("%s:%s:%lu:\n", name,
+ print_sids ? put_sid (sid) : "",
+ rid);
+ }
+ FreeSid (sid);
+ }
+}
+
+void
+current_group (int print_sids, int print_users, int id_offset)
+{
+ char name[UNLEN + 1], *envname, *envdomain;
+ DWORD len;
+ HANDLE ptok;
+ int errpos = 0;
+ struct {
+ PSID psid;
+ int buffer[10];
+ } tg;
+
+
+ if ((!GetUserName (name, (len = sizeof (name), &len)) && (errpos = __LINE__))
+ || !name[0]
+ || !(envname = getenv("USERNAME"))
+ || strcasecmp (envname, name)
+ || (!GetComputerName (name, (len = sizeof (name), &len))
+ && (errpos = __LINE__))
+ || !(envdomain = getenv("USERDOMAIN"))
+ || !envdomain[0]
+ || !strcasecmp (envdomain, name)
+ || (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok)
+ && (errpos = __LINE__))
+ || (!GetTokenInformation (ptok, TokenPrimaryGroup, &tg, sizeof tg, &len)
+ && (errpos = __LINE__))
+ || (!CloseHandle (ptok) && (errpos = __LINE__)))
+ {
+ if (errpos)
+ {
+ print_win_error (GetLastError ());
+ }
+ return;
+ }
+
+ int gid = *GetSidSubAuthority (tg.psid, *GetSidSubAuthorityCount(tg.psid) - 1);
+
+ printf ("mkgroup_l_d:%s:%u:", print_sids ? put_sid (tg.psid) : "",
+ gid + id_offset);
+ if (print_users)
+ printf("%s", envname);
+ printf ("\n");
+}
+
+int
+usage (FILE * stream, int isNT)
+{
+ fprintf (stream, "Usage: mkgroup [OPTION]... [domain]...\n"
+ "Print /etc/group file to stdout\n\n"
+ "Options:\n");
+ if (isNT)
+ fprintf (stream, " -l,--local print local group information\n"
+ " -c,--current print current group, if a domain account\n"
+ " -d,--domain print global group information (from current\n"
+ " domain if no domains specified)\n"
+ " -o,--id-offset offset change the default offset (10000) added to gids\n"
+ " in domain accounts.\n"
+ " -s,--no-sids don't print SIDs in pwd field\n"
+ " (this affects ntsec)\n"
+ " -u,--users print user list in gr_mem field\n"
+ " -g,--group groupname only return information for the specified group\n");
+ fprintf (stream, " -h,--help print this message\n"
+ " -v,--version print version information and exit\n\n");
+ if (isNT)
+ fprintf (stream, "One of '-l' or '-d' must be given.\n");
+
+ return 1;
+}
+
+struct option longopts[] = {
+ {"local", no_argument, NULL, 'l'},
+ {"current", no_argument, NULL, 'c'},
+ {"domain", no_argument, NULL, 'd'},
+ {"id-offset", required_argument, NULL, 'o'},
+ {"no-sids", no_argument, NULL, 's'},
+ {"users", no_argument, NULL, 'u'},
+ {"group", required_argument, NULL, 'g'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {0, no_argument, NULL, 0}
+};
+
+char opts[] = "lcdo:sug:hv";
+
+void
+print_version ()
+{
+ const char *v = strchr (version, ':');
+ int len;
+ if (!v)
+ {
+ v = "?";
+ len = 1;
+ }
+ else
+ {
+ v += 2;
+ len = strchr (v, ' ') - v;
+ }
+ printf ("\
+mkgroup (cygwin) %.*s\n\
+group File Generator\n\
+Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.\n\
+Compiled on %s\n\
+", len, v, __DATE__);
+}
+
+int
+main (int argc, char **argv)
+{
+ LPWSTR servername;
+ DWORD rc = ERROR_SUCCESS;
+ WCHAR domain_name[100];
+ int print_local = 0;
+ int print_current = 0;
+ int print_domain = 0;
+ int print_sids = 1;
+ int print_users = 0;
+ int domain_specified = 0;
+ int id_offset = 10000;
+ char *disp_groupname = NULL;
+ int isRoot = 0;
+ int isNT;
+ int i;
+
+ char name[256], dom[256];
+ DWORD len, len2;
+ char buf[1024];
+ PSID psid = NULL;
+ SID_NAME_USE use;
+
+ LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
+ LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
+ NTSTATUS ret;
+ PPOLICY_PRIMARY_DOMAIN_INFO pdi;
+
+ isNT = (GetVersion () < 0x80000000);
+
+ if (isNT && argc == 1)
+ return usage(stderr, isNT);
+ else
+ {
+ while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
+ switch (i)
+ {
+ case 'l':
+ print_local = 1;
+ break;
+ case 'c':
+ print_current = 1;
+ break;
+ case 'd':
+ print_domain = 1;
+ break;
+ case 'o':
+ id_offset = strtol (optarg, NULL, 10);
+ break;
+ case 's':
+ print_sids = 0;
+ break;
+ case 'u':
+ print_users = 1;
+ break;
+ case 'g':
+ disp_groupname = optarg;
+ isRoot = !strcmp(disp_groupname, "root");
+ break;
+ case 'h':
+ usage (stdout, isNT);
+ return 0;
+ case 'v':
+ print_version ();
+ return 0;
+ default:
+ fprintf (stderr, "Try '%s --help' for more information.\n", argv[0]);
+ return 1;
+ }
+ }
+
+ /* This takes Windows 9x/ME into account. */
+ if (!isNT)
+ {
+ printf ("all::%ld:\n", DOMAIN_ALIAS_RID_ADMINS);
+ return 0;
+ }
+
+ if (!print_local && !print_domain)
+ {
+ fprintf (stderr, "%s: Specify one of '-l' or '-d'\n", argv[0]);
+ return 1;
+ }
+ if (optind < argc)
+ {
+ if (!print_domain)
+ {
+ fprintf (stderr, "%s: A domain name is only accepted "
+ "when '-d' is given.\n", argv[0]);
+ return 1;
+ }
+ domain_specified = 1;
+ }
+ if (!load_netapi ())
+ {
+ print_win_error(GetLastError ());
+ return 1;
+ }
+
+ if (print_local)
+ {
+ if (isRoot)
+ {
+ /*
+ * Very special feature for the oncoming future:
+ * Create a "root" group account, being actually the local
+ * Administrators group. Since user name, sid and gid are
+ * fixed, there's no need to call print_special() for this.
+ */
+ printf ("root:S-1-5-32-544:0:\n");
+ }
+
+ if (disp_groupname == NULL)
+ {
+ /*
+ * Get 'system' group
+ */
+ print_special (print_sids, &sid_nt_auth, 1, SECURITY_LOCAL_SYSTEM_RID,
+ 0, 0, 0, 0, 0, 0, 0);
+ /*
+ * Get 'None' group
+ */
+ len = 256;
+ GetComputerName (name, &len);
+ len = 1024;
+ len2 = 256;
+ if (LookupAccountName (NULL, name, (PSID) buf, &len, dom, &len, &use))
+ psid = (PSID) buf;
+ else
+ {
+ ret = lsaopenpolicy (NULL, &oa, POLICY_VIEW_LOCAL_INFORMATION, &lsa);
+ if (ret == STATUS_SUCCESS && lsa != INVALID_HANDLE_VALUE)
+ {
+ ret = lsaqueryinformationpolicy (lsa,
+ PolicyPrimaryDomainInformation,
+ (void *) &pdi);
+ if (ret == STATUS_SUCCESS)
+ {
+ if (pdi->Sid)
+ {
+ CopySid (1024, (PSID) buf, pdi->Sid);
+ psid = (PSID) buf;
+ }
+ lsafreememory (pdi);
+ }
+ lsaclose (lsa);
+ }
+ }
+ if (!psid)
+ fprintf (stderr,
+ "WARNING: Group 513 couldn't get retrieved. Try mkgroup -d\n");
+ else
+ print_special (print_sids, GetSidIdentifierAuthority (psid), 5,
+ *GetSidSubAuthority (psid, 0),
+ *GetSidSubAuthority (psid, 1),
+ *GetSidSubAuthority (psid, 2),
+ *GetSidSubAuthority (psid, 3),
+ 513,
+ 0,
+ 0,
+ 0);
+ }
+
+ if (!isRoot)
+ {
+ enum_local_groups (print_sids, print_users, disp_groupname);
+ }
+ }
+
+ i = 1;
+ if (print_domain)
+ do
+ {
+ PDOMAIN_CONTROLLER_INFOW pdci = NULL;
+
+ if (dsgetdcname)
+ {
+ if (domain_specified)
+ {
+ mbstowcs (domain_name, argv[optind], strlen (argv[optind]) + 1);
+ rc = dsgetdcname (NULL, domain_name, NULL, NULL, 0, &pdci);
+ }
+ else
+ rc = dsgetdcname (NULL, NULL, NULL, NULL, 0, &pdci);
+ if (rc != ERROR_SUCCESS)
+ {
+ print_win_error(rc);
+ return 1;
+ }
+ servername = pdci->DomainControllerName;
+ }
+ else
+ {
+ rc = netgetdcname (NULL, NULL, (void *) &servername);
+ if (rc == ERROR_SUCCESS && domain_specified)
+ {
+ LPWSTR server = servername;
+ mbstowcs (domain_name, argv[optind], strlen (argv[optind]) + 1);
+ rc = netgetdcname (NULL, domain_name, (void *) &servername);
+ netapibufferfree (server);
+ }
+ if (rc != ERROR_SUCCESS)
+ {
+ print_win_error(rc);
+ return 1;
+ }
+ }
+ enum_groups (servername, print_sids, print_users, id_offset * i++,
+ disp_groupname);
+ netapibufferfree (pdci ? (PVOID) pdci : (PVOID) servername);
+ }
+ while (++optind < argc);
+
+ if (print_current && !print_domain)
+ current_group (print_sids, print_users, id_offset);
+
+ return 0;
+}
diff --git a/winsup/utils/parse_pe.cc b/winsup/utils/parse_pe.cc
new file mode 100644
index 00000000000..44b4068a466
--- /dev/null
+++ b/winsup/utils/parse_pe.cc
@@ -0,0 +1,104 @@
+/* parse_pe.cc
+
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+
+ Written by Egor Duda <deo@logos-m.ru>
+
+ This file is part of Cygwin.
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License (file COPYING.dumper) for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <bfd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dumper.h"
+
+int
+exclusion::add (LPBYTE mem_base, DWORD mem_size)
+{
+ while (last >= size)
+ size += step;
+ region = (process_mem_region *) realloc (region, size * sizeof (process_mem_region));
+ if (region == NULL)
+ return 0;
+ region[last].base = mem_base;
+ region[last].size = mem_size;
+ last++;
+ return 1;
+};
+
+int
+cmp_regions (const void *r1, const void *r2)
+{
+ if (((process_mem_region *) r1)->base < ((process_mem_region *) r2)->base)
+ return -1;
+ if (((process_mem_region *) r1)->base > ((process_mem_region *) r2)->base)
+ return 1;
+ return 0;
+}
+
+int
+exclusion::sort_and_check ()
+{
+ qsort (region, last, sizeof (process_mem_region), &cmp_regions);
+ for (process_mem_region * p = region; p < region + last - 1; p++)
+ {
+ process_mem_region *q = p + 1;
+ if (q == p + 1)
+ continue;
+ if (p->base + size > q->base)
+ {
+ fprintf (stderr, "region error @ (%8p + %d) > %8p\n", p->base, size, q->base);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void
+select_data_section (bfd * abfd, asection * sect, PTR obj)
+{
+ exclusion *excl_list = (exclusion *) obj;
+
+ if ((sect->flags & (SEC_CODE | SEC_DEBUGGING)) &&
+ sect->vma && bfd_get_section_size (sect))
+ {
+ excl_list->add ((LPBYTE) sect->vma, (DWORD) bfd_get_section_size (sect));
+ deb_printf ("excluding section: %20s %08lx\n", sect->name,
+ bfd_get_section_size (sect));
+ }
+}
+
+int
+parse_pe (const char *file_name, exclusion * excl_list)
+{
+ if (file_name == NULL || excl_list == NULL)
+ return 0;
+
+ bfd *abfd = bfd_openr (file_name, "pei-i386");
+ if (abfd == NULL)
+ {
+ bfd_perror ("failed to open file");
+ return 0;
+ }
+
+ bfd_check_format (abfd, bfd_object);
+ bfd_map_over_sections (abfd, &select_data_section, (PTR) excl_list);
+ excl_list->sort_and_check ();
+
+ bfd_close (abfd);
+ return 1;
+}
diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc
new file mode 100644
index 00000000000..57bd3a4ff65
--- /dev/null
+++ b/winsup/utils/path.cc
@@ -0,0 +1,353 @@
+/* path.cc
+
+ Copyright 2001, 2002, 2003, 2005 Red Hat, Inc.
+
+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. */
+
+/* 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. */
+
+#define str(a) #a
+#define scat(a,b) str(a##b)
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "cygwin/include/cygwin/version.h"
+#include "cygwin/include/sys/mount.h"
+#include "cygwin/include/mntent.h"
+
+/* 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 (".");
+ m->issys = issystem;
+ return m + 1;
+}
+
+static 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_READ,
+ 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;
+
+ /* 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)
+ *d++ = *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;
+
+ if (!mount_table[0].posix)
+ read_mounts ();
+ 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++)
+ {
+ if (m->flags & MOUNT_CYGDRIVE)
+ continue;
+
+ 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");
+ else if (m->flags & MOUNT_NOTEXEC)
+ strcat (mnt.mnt_opts, (char *) ",noexec");
+ if (m->flags & MOUNT_ENC)
+ strcat (mnt.mnt_opts, ",managed");
+ if ((m->flags & MOUNT_CYGDRIVE)) /* cygdrive */
+ strcat (mnt.mnt_opts, (char *) ",cygdrive");
+ mnt.mnt_freq = 1;
+ mnt.mnt_passno = 1;
+ m++;
+ return &mnt;
+}
diff --git a/winsup/utils/strace.cc b/winsup/utils/strace.cc
new file mode 100644
index 00000000000..38332641632
--- /dev/null
+++ b/winsup/utils/strace.cc
@@ -0,0 +1,1061 @@
+/* strace.cc
+
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat Inc.
+
+ Written by Chris Faylor <cgf@redhat.com>
+
+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. */
+
+#define cygwin_internal cygwin_internal_dontuse
+#include <stdio.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <windows.h>
+#include <signal.h>
+#include <errno.h>
+#include "cygwin/include/sys/strace.h"
+#include "cygwin/include/sys/cygwin.h"
+#include "path.h"
+#undef cygwin_internal
+
+/* we *know* we're being built with GCC */
+#define alloca __builtin_alloca
+
+// Version string.
+static const char version[] = "$Revision$";
+
+static const char *pgm;
+static int forkdebug = 1;
+static int numerror = 1;
+static int show_usecs = 1;
+static int delta = 1;
+static int hhmmss;
+static int bufsize;
+static int new_window;
+static long flush_period;
+static int include_hex;
+static int quiet = -1;
+
+static unsigned char strace_active = 1;
+static int processes;
+
+static BOOL close_handle (HANDLE h, DWORD ok);
+
+#define CloseHandle(h) close_handle(h, 0)
+
+struct child_list
+{
+ DWORD id;
+ HANDLE hproc;
+ int saw_stars;
+ char nfields;
+ long long start_time;
+ DWORD last_usecs;
+ struct child_list *next;
+ child_list ():id (0), hproc (NULL), saw_stars (0), nfields (0),
+ start_time (0), last_usecs (0), next (NULL)
+ {
+ }
+};
+
+child_list children;
+
+static void
+warn (int geterrno, const char *fmt, ...)
+{
+ va_list args;
+ char buf[4096];
+
+ va_start (args, fmt);
+ sprintf (buf, "%s: ", pgm);
+ vsprintf (strchr (buf, '\0'), fmt, args);
+ if (geterrno)
+ perror (buf);
+ else
+ {
+ fputs (buf, stderr);
+ fputs ("\n", stderr);
+ }
+}
+
+static void __attribute__ ((noreturn))
+error (int geterrno, const char *fmt, ...)
+{
+ va_list args;
+ char buf[4096];
+
+ va_start (args, fmt);
+ sprintf (buf, "%s: ", pgm);
+ vsprintf (strchr (buf, '\0'), fmt, args);
+ if (geterrno)
+ perror (buf);
+ else
+ {
+ fputs (buf, stderr);
+ fputs ("\n", stderr);
+ }
+ exit (1);
+}
+
+DWORD lastid = 0;
+HANDLE lasth;
+
+static child_list *
+get_child (DWORD id)
+{
+ child_list *c;
+ for (c = &children; (c = c->next) != NULL;)
+ if (c->id == id)
+ return c;
+
+ return NULL;
+}
+
+static void
+add_child (DWORD id, HANDLE hproc)
+{
+ if (!get_child (id))
+ {
+ child_list *c = children.next;
+ children.next = (child_list *) calloc (1, sizeof (child_list));
+ children.next->next = c;
+ lastid = children.next->id = id;
+ lasth = children.next->hproc = hproc;
+ processes++;
+ if (!quiet)
+ fprintf (stderr, "Windows process %d attached\n", id);
+ }
+}
+
+static void
+remove_child (DWORD id)
+{
+ child_list *c;
+ if (id == lastid)
+ lastid = 0;
+ for (c = &children; c->next != NULL; c = c->next)
+ if (c->next->id == id)
+ {
+ child_list *c1 = c->next;
+ c->next = c1->next;
+ free (c1);
+ if (!quiet)
+ fprintf (stderr, "Windows process %d detached\n", id);
+ processes--;
+ return;
+ }
+
+ error (0, "no process id %d found", id);
+}
+
+#define LINE_BUF_CHUNK 128
+
+class linebuf
+{
+ size_t alloc;
+public:
+ size_t ix;
+ char *buf;
+ linebuf ()
+ {
+ ix = 0;
+ alloc = 0;
+ buf = NULL;
+ }
+ ~linebuf ()
+ {
+ if (buf)
+ free (buf);
+ }
+ void add (const char *what, int len);
+ void add (const char *what)
+ {
+ add (what, strlen (what));
+ }
+ void prepend (const char *what, int len);
+};
+
+void
+linebuf::add (const char *what, int len)
+{
+ size_t newix;
+ if ((newix = ix + len) >= alloc)
+ {
+ alloc += LINE_BUF_CHUNK + len;
+ buf = (char *) realloc (buf, alloc + 1);
+ }
+ memcpy (buf + ix, what, len);
+ ix = newix;
+ buf[ix] = '\0';
+}
+
+void
+linebuf::prepend (const char *what, int len)
+{
+ int buflen;
+ size_t newix;
+ if ((newix = ix + len) >= alloc)
+ {
+ alloc += LINE_BUF_CHUNK + len;
+ buf = (char *) realloc (buf, alloc + 1);
+ buf[ix] = '\0';
+ }
+ if ((buflen = strlen (buf)))
+ memmove (buf + len, buf, buflen + 1);
+ else
+ buf[newix] = '\0';
+ memcpy (buf, what, len);
+ ix = newix;
+}
+
+static void
+make_command_line (linebuf & one_line, char **argv)
+{
+ for (; *argv; argv++)
+ {
+ char *p = NULL;
+ const char *a = *argv;
+
+ int len = strlen (a);
+ if (len != 0 && !(p = strpbrk (a, " \t\n\r\"")))
+ one_line.add (a, len);
+ else
+ {
+ one_line.add ("\"", 1);
+ for (; p; a = p, p = strchr (p, '"'))
+ {
+ one_line.add (a, ++p - a);
+ if (p[-1] == '"')
+ one_line.add ("\"", 1);
+ }
+ if (*a)
+ one_line.add (a);
+ one_line.add ("\"", 1);
+ }
+ one_line.add (" ", 1);
+ }
+
+ if (one_line.ix)
+ one_line.buf[one_line.ix - 1] = '\0';
+ else
+ one_line.add ("", 1);
+}
+
+static DWORD child_pid;
+
+static BOOL WINAPI
+ctrl_c (DWORD)
+{
+ static int tic = 1;
+ if ((tic ^= 1) && !GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0))
+ error (0, "couldn't send CTRL-C to child, win32 error %d\n",
+ GetLastError ());
+ return TRUE;
+}
+
+extern "C" {
+unsigned long (*cygwin_internal) (int, ...);
+};
+
+static int
+load_cygwin ()
+{
+ static HMODULE h;
+
+ if (cygwin_internal)
+ return 1;
+
+ if (h)
+ return 0;
+
+ if (!(h = LoadLibrary ("cygwin1.dll")))
+ {
+ errno = ENOENT;
+ return 0;
+ }
+ if (!(cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal")))
+ {
+ errno = ENOSYS;
+ return 0;
+ }
+ return 1;
+}
+
+static void
+attach_process (pid_t pid)
+{
+ child_pid = (DWORD) cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid);
+ if (!child_pid)
+ child_pid = pid;
+
+ if (!DebugActiveProcess (child_pid))
+ error (0, "couldn't attach to pid %d for debugging", child_pid);
+
+ return;
+}
+
+
+static void
+create_child (char **argv)
+{
+ linebuf one_line;
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL ret;
+ DWORD flags;
+
+ if (strchr (*argv, '/'))
+ *argv = cygpath (*argv, NULL);
+ memset (&si, 0, sizeof (si));
+ si.cb = sizeof (si);
+
+ flags = CREATE_DEFAULT_ERROR_MODE
+ | (forkdebug ? DEBUG_PROCESS : DEBUG_ONLY_THIS_PROCESS);
+ if (new_window)
+ flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
+
+ make_command_line (one_line, argv);
+
+ SetConsoleCtrlHandler (NULL, 0);
+ ret = CreateProcess (0, one_line.buf, /* command line */
+ NULL, /* Security */
+ NULL, /* thread */
+ TRUE, /* inherit handles */
+ flags, /* start flags */
+ NULL, NULL, /* current directory */
+ &si, &pi);
+ if (!ret)
+ error (0, "error creating process %s, (error %d)", *argv,
+ GetLastError ());
+
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+ child_pid = pi.dwProcessId;
+ SetConsoleCtrlHandler (ctrl_c, 1);
+}
+
+static int
+output_winerror (FILE *ofile, char *s)
+{
+ char *winerr = strstr (s, "Win32 error ");
+ if (!winerr)
+ return 0;
+
+ DWORD errnum = atoi (winerr + sizeof ("Win32 error ") - 1);
+ if (!errnum)
+ return 0;
+
+ /*
+ * NOTE: Currently there is no policy for how long the
+ * the buffers are, and looks like 256 is a smallest one
+ * (dlfcn.cc). Other than error 1395 (length 213) and
+ * error 1015 (length 249), the rest are all under 188
+ * characters, and so I'll use 189 as the buffer length.
+ * For those longer error messages, FormatMessage will
+ * return FALSE, and we'll get the old behaviour such as
+ * ``Win32 error 1395'' etc.
+ */
+ char buf[4096];
+ if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ errnum,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) buf, sizeof (buf), NULL))
+ return 0;
+
+ /* Get rid the trailing CR/NL pair. */
+ char *p = strchr (buf, '\0');
+ p[-2] = '\n';
+ p[-1] = '\0';
+
+ *winerr = '\0';
+ fputs (s, ofile);
+ fputs (buf, ofile);
+ return 1;
+}
+
+static SYSTEMTIME *
+syst (long long t)
+{
+ FILETIME n;
+ static SYSTEMTIME st;
+ long long now = t /*+ ((long long) usecs * 10)*/;
+ n.dwHighDateTime = now >> 32;
+ n.dwLowDateTime = now & 0xffffffff;
+ FileTimeToSystemTime (&n, &st);
+ return &st;
+}
+
+static void __stdcall
+handle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile)
+{
+ int len;
+ int special;
+ char alen[3 + 8 + 1];
+ DWORD nbytes;
+ child_list *child = get_child (id);
+ if (!child)
+ error (0, "no process id %d found", id);
+ HANDLE hchild = child->hproc;
+#define INTROLEN (sizeof (alen) - 1)
+
+ if (id == lastid && hchild != lasth)
+ warn (0, "%p != %p", hchild, lasth);
+
+ alen[INTROLEN] = '\0';
+ if (!ReadProcessMemory (hchild, p, alen, INTROLEN, &nbytes))
+#ifndef DEBUGGING
+ return;
+#else
+ error (0,
+ "couldn't get message length from subprocess %d<%p>, windows error %d",
+ id, hchild, GetLastError ());
+#endif
+
+ if (strncmp (alen, "cYg", 3))
+ return;
+ len = (int) strtoul (alen + 3, NULL, 16);
+ if (!len)
+ return;
+
+ if (len > 0)
+ special = 0;
+ else
+ {
+ special = len;
+ if (special == _STRACE_INTERFACE_ACTIVATE_ADDR || special == _STRACE_CHILD_PID)
+ len = 17;
+ }
+
+ char *buf;
+ buf = (char *) alloca (len + 85) + 20;
+
+ if (!ReadProcessMemory (hchild, ((char *) p) + INTROLEN, buf, len, &nbytes))
+ error (0, "couldn't get message from subprocess, windows error %d",
+ GetLastError ());
+
+ buf[len] = '\0';
+ char *s = strtok (buf, " ");
+
+ unsigned long n = strtoul (s, NULL, 16);
+
+ s = strchr (s, '\0') + 1;
+
+ if (special == _STRACE_CHILD_PID)
+ {
+ if (!DebugActiveProcess (n))
+ error (0, "couldn't attach to subprocess %d for debugging, "
+ "windows error %d", n, GetLastError ());
+ return;
+ }
+
+ if (special == _STRACE_INTERFACE_ACTIVATE_ADDR)
+ {
+ if (!WriteProcessMemory (hchild, (LPVOID) n, &strace_active,
+ sizeof (strace_active), &nbytes))
+ error (0, "couldn't write strace flag to subprocess at %p, "
+ "windows error %d", n, GetLastError ());
+ return;
+ }
+
+ char *origs = s;
+
+ if (mask & n)
+ /* got it */ ;
+ else if (!(mask & _STRACE_ALL) || (n & _STRACE_NOTALL))
+ return; /* This should not be included in "all" output */
+
+ DWORD dusecs, usecs;
+ char *ptusec, *ptrest;
+
+ dusecs = strtoul (s, &ptusec, 10);
+ char *q = ptusec;
+ while (*q == ' ')
+ q++;
+ if (*q != '[')
+ {
+ usecs = strtoul (q, &ptrest, 10);
+ while (*ptrest == ' ')
+ ptrest++;
+ }
+ else
+ {
+ ptrest = q;
+ ptusec = show_usecs ? s : ptrest;
+ usecs = dusecs;
+ }
+
+ if (child->saw_stars == 0)
+ {
+ FILETIME st;
+ char *news;
+
+ GetSystemTimeAsFileTime (&st);
+ FileTimeToLocalFileTime (&st, &st);
+ child->start_time = st.dwHighDateTime;
+ child->start_time <<= 32;
+ child->start_time |= st.dwLowDateTime;
+ if (*(news = ptrest) != '[')
+ child->saw_stars = 2;
+ else
+ {
+ child->saw_stars++;
+ while ((news = strchr (news, ' ')) != NULL && *++news != '*')
+ child->nfields++;
+ if (news == NULL)
+ child->saw_stars++;
+ else
+ {
+ s = news;
+ child->nfields++;
+ }
+ }
+ }
+ else if (child->saw_stars < 2)
+ {
+ int i;
+ char *news;
+ if (*(news = ptrest) != '[')
+ child->saw_stars = 2;
+ else
+ {
+ for (i = 0; i < child->nfields; i++)
+ if ((news = strchr (news, ' ')) == NULL)
+ break; // Should never happen
+ else
+ news++;
+
+ if (news == NULL)
+ child->saw_stars = 2;
+ else
+ {
+ s = news;
+ if (*s == '*')
+ {
+ SYSTEMTIME *st = syst (child->start_time);
+ fprintf (ofile,
+ "Date/Time: %d-%02d-%02d %02d:%02d:%02d\n",
+ st->wYear, st->wMonth, st->wDay, st->wHour,
+ st->wMinute, st->wSecond);
+ child->saw_stars++;
+ }
+ }
+ }
+ }
+
+ long long d = usecs - child->last_usecs;
+ char intbuf[40];
+
+ if (child->saw_stars < 2 || s != origs)
+ /* Nothing */ ;
+ else if (hhmmss)
+ {
+ s = ptrest - 9;
+ SYSTEMTIME *st = syst (child->start_time + (long long) usecs * 10);
+ sprintf (s, "%02d:%02d:%02d", st->wHour, st->wMinute, st->wSecond);
+ *strchr (s, '\0') = ' ';
+ }
+ else if (!delta)
+ s = ptusec;
+ else
+ {
+ s = ptusec;
+ sprintf (intbuf, "%5d ", (int) d);
+ int len = strlen (intbuf);
+
+ memcpy ((s -= len), intbuf, len);
+ }
+
+ if (include_hex)
+ {
+ s -= 8;
+ sprintf (s, "%p", (void *) n);
+ strchr (s, '\0')[0] = ' ';
+ }
+ child->last_usecs = usecs;
+ if (numerror || !output_winerror (ofile, s))
+ fputs (s, ofile);
+ if (!bufsize)
+ fflush (ofile);
+}
+
+static DWORD
+proc_child (unsigned mask, FILE *ofile, pid_t pid)
+{
+ DWORD res = 0;
+ DEBUG_EVENT ev;
+ time_t cur_time, last_time;
+
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
+ last_time = time (NULL);
+ while (1)
+ {
+ BOOL debug_event = WaitForDebugEvent (&ev, 1000);
+ DWORD status = DBG_CONTINUE;
+
+ if (bufsize && flush_period > 0 &&
+ (cur_time = time (NULL)) >= last_time + flush_period)
+ {
+ last_time = cur_time;
+ fflush (ofile);
+ }
+
+ if (!debug_event)
+ continue;
+
+ if (pid)
+ {
+ (void) cygwin_internal (CW_STRACE_TOGGLE, pid);
+ pid = 0;
+ }
+
+ switch (ev.dwDebugEventCode)
+ {
+ case CREATE_PROCESS_DEBUG_EVENT:
+ if (ev.u.CreateProcessInfo.hFile)
+ CloseHandle (ev.u.CreateProcessInfo.hFile);
+ add_child (ev.dwProcessId, ev.u.CreateProcessInfo.hProcess);
+ break;
+
+ case CREATE_THREAD_DEBUG_EVENT:
+ break;
+
+ case LOAD_DLL_DEBUG_EVENT:
+ if (ev.u.LoadDll.hFile)
+ CloseHandle (ev.u.LoadDll.hFile);
+ break;
+
+ case OUTPUT_DEBUG_STRING_EVENT:
+ handle_output_debug_string (ev.dwProcessId,
+ ev.u.DebugString.lpDebugStringData,
+ mask, ofile);
+ break;
+
+ case EXIT_PROCESS_DEBUG_EVENT:
+ res = ev.u.ExitProcess.dwExitCode >> 8;
+ remove_child (ev.dwProcessId);
+ break;
+ case EXCEPTION_DEBUG_EVENT:
+ if (ev.u.Exception.ExceptionRecord.ExceptionCode != STATUS_BREAKPOINT)
+ {
+ status = DBG_EXCEPTION_NOT_HANDLED;
+ if (ev.u.Exception.dwFirstChance)
+ fprintf (ofile, "--- Process %u, exception %p at %p\n", ev.dwProcessId,
+ ev.u.Exception.ExceptionRecord.ExceptionCode,
+ ev.u.Exception.ExceptionRecord.ExceptionAddress);
+ }
+ break;
+ }
+ if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, status))
+ error (0, "couldn't continue debug event, windows error %d",
+ GetLastError ());
+ if (!processes)
+ break;
+ }
+
+ return res;
+}
+
+static void
+dotoggle (pid_t pid)
+{
+ child_pid = (DWORD) cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid);
+ if (!child_pid)
+ {
+ warn (0, "no such cygwin pid - %d", pid);
+ child_pid = pid;
+ }
+ if (cygwin_internal (CW_STRACE_TOGGLE, child_pid))
+ error (0, "failed to toggle tracing for process %d<%d>", pid, child_pid);
+
+ return;
+}
+
+static DWORD
+dostrace (unsigned mask, FILE *ofile, pid_t pid, char **argv)
+{
+ if (!pid)
+ create_child (argv);
+ else
+ attach_process (pid);
+
+ return proc_child (mask, ofile, pid);
+}
+
+typedef struct tag_mask_mnemonic
+{
+ unsigned long val;
+ const char *text;
+}
+mask_mnemonic;
+
+static const mask_mnemonic mnemonic_table[] = {
+ {_STRACE_ALL, "all"},
+ {_STRACE_FLUSH, "flush"},
+ {_STRACE_INHERIT, "inherit"},
+ {_STRACE_UHOH, "uhoh"},
+ {_STRACE_SYSCALL, "syscall"},
+ {_STRACE_STARTUP, "startup"},
+ {_STRACE_DEBUG, "debug"},
+ {_STRACE_PARANOID, "paranoid"},
+ {_STRACE_TERMIOS, "termios"},
+ {_STRACE_SELECT, "select"},
+ {_STRACE_WM, "wm"},
+ {_STRACE_SIGP, "sigp"},
+ {_STRACE_MINIMAL, "minimal"},
+ {_STRACE_EXITDUMP, "exitdump"},
+ {_STRACE_SYSTEM, "system"},
+ {_STRACE_NOMUTEX, "nomutex"},
+ {_STRACE_MALLOC, "malloc"},
+ {_STRACE_THREAD, "thread"},
+ {0, NULL}
+};
+
+static unsigned long
+mnemonic2ul (const char *nptr, char **endptr)
+{
+ // Look up mnemonic in table, return value.
+ // *endptr = ptr to char that breaks match.
+ const mask_mnemonic *mnp = mnemonic_table;
+
+ while (mnp->text != NULL)
+ {
+ if (strcmp (mnp->text, nptr) == 0)
+ {
+ // Found a match.
+ if (endptr != NULL)
+ {
+ *endptr = ((char *) nptr) + strlen (mnp->text);
+ }
+ return mnp->val;
+ }
+ mnp++;
+ }
+
+ // Didn't find it.
+ if (endptr != NULL)
+ {
+ *endptr = (char *) nptr;
+ }
+ return 0;
+}
+
+static unsigned long
+parse_mask (const char *ms, char **endptr)
+{
+ const char *p = ms;
+ char *newp;
+ unsigned long retval = 0, thisval;
+ const size_t bufsize = 16;
+ char buffer[bufsize];
+ size_t len;
+
+ while (*p != '\0')
+ {
+ // First extract the term, terminate it, and lowercase it.
+ strncpy (buffer, p, bufsize);
+ buffer[bufsize - 1] = '\0';
+ len = strcspn (buffer, "+,\0");
+ buffer[len] = '\0';
+ strlwr (buffer);
+
+ // Check if this is a mnemonic. We have to do this first or strtoul()
+ // will false-trigger on anything starting with "a" through "f".
+ thisval = mnemonic2ul (buffer, &newp);
+ if (buffer == newp)
+ {
+ // This term isn't mnemonic, check if it's hex.
+ thisval = strtoul (buffer, &newp, 16);
+ if (newp != buffer + len)
+ {
+ // Not hex either, syntax error.
+ *endptr = (char *) p;
+ return 0;
+ }
+ }
+
+ p += len;
+ retval += thisval;
+
+ // Handle operators
+ if (*p == '\0')
+ break;
+ if ((*p == '+') || (*p == ','))
+ {
+ // For now these both equate to addition/ORing. Until we get
+ // fancy and add things like "all-<something>", all we need do is
+ // continue the looping.
+ p++;
+ continue;
+ }
+ else
+ {
+ // Syntax error
+ *endptr = (char *) p;
+ return 0;
+ }
+ }
+
+ *endptr = (char *) p;
+ return retval;
+}
+
+static void
+usage (FILE *where = stderr)
+{
+ fprintf (where, "\
+Usage: %s [OPTIONS] <command-line>\n\
+Usage: %s [OPTIONS] -p <pid>\n\
+Trace system calls and signals\n\
+\n\
+ -b, --buffer-size=SIZE set size of output file buffer\n\
+ -d, --no-delta don't display the delta-t microsecond timestamp\n\
+ -f, --trace-children trace child processes (toggle - default true)\n\
+ -h, --help output usage information and exit\n\
+ -m, --mask=MASK set message filter mask\n\
+ -n, --crack-error-numbers output descriptive text instead of error\n\
+ numbers for Windows errors\n\
+ -o, --output=FILENAME set output file to FILENAME\n\
+ -p, --pid=n attach to executing program with cygwin pid n\n\
+ -q, --quiet suppress messages about attaching, detaching, etc.\n\
+ -S, --flush-period=PERIOD flush buffered strace output every PERIOD secs\n\
+ -t, --timestamp use an absolute hh:mm:ss timestamp insted of \n\
+ the default microsecond timestamp. Implies -d\n\
+ -T, --toggle toggle tracing in a process already being\n\
+ traced. Requires -p <pid>\n\
+ -u, --usecs toggle printing of microseconds timestamp\n\
+ -v, --version output version information and exit\n\
+ -w, --new-window spawn program under test in a new window\n\
+\n", pgm, pgm);
+ if ( where == stdout)
+ fprintf (stdout, "\
+ MASK can be any combination of the following mnemonics and/or hex values\n\
+ (0x is optional). Combine masks with '+' or ',' like so:\n\
+\n\
+ --mask=wm+system,malloc+0x00800\n\
+\n\
+ Mnemonic Hex Corresponding Def Description\n\
+ =========================================================================\n\
+ all 0x00001 (_STRACE_ALL) All strace messages.\n\
+ flush 0x00002 (_STRACE_FLUSH) Flush output buffer after each message.\n\
+ inherit 0x00004 (_STRACE_INHERIT) Children inherit mask from parent.\n\
+ uhoh 0x00008 (_STRACE_UHOH) Unusual or weird phenomenon.\n\
+ syscall 0x00010 (_STRACE_SYSCALL) System calls.\n\
+ startup 0x00020 (_STRACE_STARTUP) argc/envp printout at startup.\n\
+ debug 0x00040 (_STRACE_DEBUG) Info to help debugging. \n\
+ paranoid 0x00080 (_STRACE_PARANOID) Paranoid info.\n\
+ termios 0x00100 (_STRACE_TERMIOS) Info for debugging termios stuff.\n\
+ select 0x00200 (_STRACE_SELECT) Info on ugly select internals.\n\
+ wm 0x00400 (_STRACE_WM) Trace Windows msgs (enable _strace_wm).\n\
+ sigp 0x00800 (_STRACE_SIGP) Trace signal and process handling.\n\
+ minimal 0x01000 (_STRACE_MINIMAL) Very minimal strace output.\n\
+ exitdump 0x04000 (_STRACE_EXITDUMP) Dump strace cache on exit.\n\
+ system 0x08000 (_STRACE_SYSTEM) Serious error; goes to console and log.\n\
+ nomutex 0x10000 (_STRACE_NOMUTEX) Don't use mutex for synchronization.\n\
+ malloc 0x20000 (_STRACE_MALLOC) Trace malloc calls.\n\
+ thread 0x40000 (_STRACE_THREAD) Thread-locking calls.\n\
+");
+ if (where == stderr)
+ fprintf (stderr, "Try '%s --help' for more information.\n", pgm);
+ exit (where == stderr ? 1 : 0 );
+}
+
+struct option longopts[] = {
+ {"buffer-size", required_argument, NULL, 'b'},
+ {"help", no_argument, NULL, 'h'},
+ {"flush-period", required_argument, NULL, 'S'},
+ {"hex", no_argument, NULL, 'H'},
+ {"mask", required_argument, NULL, 'm'},
+ {"new-window", no_argument, NULL, 'w'},
+ {"output", required_argument, NULL, 'o'},
+ {"no-delta", no_argument, NULL, 'd'},
+ {"pid", required_argument, NULL, 'p'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"timestamp", no_argument, NULL, 't'},
+ {"toggle", no_argument, NULL, 'T'},
+ {"trace-children", no_argument, NULL, 'f'},
+ {"translate-error-numbers", no_argument, NULL, 'n'},
+ {"usecs", no_argument, NULL, 'u'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, 0, NULL, 0}
+};
+
+static const char *const opts = "+b:dhHfm:no:p:qS:tTuvw";
+
+static void
+print_version ()
+{
+ const char *v = strchr (version, ':');
+ int len;
+ if (!v)
+ {
+ v = "?";
+ len = 1;
+ }
+ else
+ {
+ v += 2;
+ len = strchr (v, ' ') - v;
+ }
+ printf ("\
+%s (cygwin) %.*s\n\
+System Trace\n\
+Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.\n\
+Compiled on %s\n\
+", pgm, len, v, __DATE__);
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned mask = 0;
+ FILE *ofile = NULL;
+ pid_t pid = 0;
+ int opt;
+ int toggle = 0;
+ int sawquiet = -1;
+
+ if (load_cygwin ())
+ {
+ char **av = (char **) cygwin_internal (CW_ARGV);
+ if (av && (DWORD) av != (DWORD) -1)
+ for (argc = 0, argv = av; *av; av++)
+ argc++;
+ }
+
+ if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/')))
+ pgm = *argv;
+ else
+ pgm++;
+
+ while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
+ switch (opt)
+ {
+ case 'b':
+ bufsize = atoi (optarg);
+ break;
+ case 'd':
+ delta ^= 1;
+ break;
+ case 'f':
+ forkdebug ^= 1;
+ break;
+ case 'h':
+ // Print help and exit
+ usage (stdout);
+ break;
+ case 'H':
+ include_hex ^= 1;
+ break;
+ case 'm':
+ {
+ char *endptr;
+ mask = parse_mask (optarg, &endptr);
+ if (*endptr != '\0')
+ {
+ // Bad mask expression.
+ error (0, "syntax error in mask expression \"%s\" near \
+character #%d.\n", optarg, (int) (endptr - optarg), endptr);
+ }
+ break;
+ }
+ case 'n':
+ numerror ^= 1;
+ break;
+ case 'o':
+ if ((ofile = fopen (cygpath (optarg, NULL), "w")) == NULL)
+ error (1, "can't open %s", optarg);
+#ifdef F_SETFD
+ (void) fcntl (fileno (ofile), F_SETFD, 0);
+#endif
+ break;
+ case 'p':
+ pid = strtoul (optarg, NULL, 10);
+ strace_active |= 2;
+ break;
+ case 'q':
+ if (sawquiet < 0)
+ sawquiet = 1;
+ else
+ sawquiet ^= 1;
+ break;
+ case 'S':
+ flush_period = strtoul (optarg, NULL, 10);
+ break;
+ case 't':
+ hhmmss ^= 1;
+ break;
+ case 'T':
+ toggle ^= 1;
+ break;
+ case 'u':
+ // FIXME: currently unimplemented
+ show_usecs ^= 1;
+ delta ^= 1;
+ break;
+ case 'v':
+ // Print version info and exit
+ print_version ();
+ return 0;
+ case 'w':
+ new_window ^= 1;
+ break;
+ case '?':
+ fprintf (stderr, "Try '%s --help' for more information.\n", pgm);
+ exit (1);
+ }
+
+ if (pid && argv[optind])
+ error (0, "cannot provide both a command line and a process id");
+
+ if (!pid && !argv[optind])
+ error (0, "must provide either a command line or a process id");
+
+ if (toggle && !pid)
+ error (0, "must provide a process id to toggle tracing");
+
+ if (!pid)
+ quiet = sawquiet < 0 || !sawquiet;
+ else if (sawquiet < 0)
+ quiet = 0;
+ else
+ quiet = sawquiet;
+
+ if (!mask)
+ mask = _STRACE_ALL;
+
+ if (bufsize)
+ setvbuf (ofile, (char *) alloca (bufsize), _IOFBF, bufsize);
+
+ if (!ofile)
+ ofile = stdout;
+
+ DWORD res = 0;
+ if (toggle)
+ dotoggle (pid);
+ else
+ res = dostrace (mask, ofile, pid, argv + optind);
+ return res;
+}
+
+#undef CloseHandle
+
+static BOOL
+close_handle (HANDLE h, DWORD ok)
+{
+ child_list *c;
+ for (c = &children; (c = c->next) != NULL;)
+ if (c->hproc == h && c->id != ok)
+ error (0, "Closing child handle %p", h);
+ return CloseHandle (h);
+}