pax_global_header00006660000000000000000000000064126250420210014504gustar00rootroot0000000000000052 comment=775b6c0bbdf94c441dc59038bb788b7e9edcf9ef gpart-0.3/000077500000000000000000000000001262504202100124635ustar00rootroot00000000000000gpart-0.3/.gitignore000066400000000000000000000002651262504202100144560ustar00rootroot00000000000000*.o src/gpart Makefile Makefile.in aclocal.m4 autom4te.cache/ compile config.h config.h.in config.log config.status configure depcomp install-sh man/gpart.8 missing .deps/ stamp-h1 gpart-0.3/.travis.yml000066400000000000000000000001071262504202100145720ustar00rootroot00000000000000language: c script: ./autogen.sh && make compiler: - gcc - clang gpart-0.3/COPYING000066400000000000000000000430771262504202100135310ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, 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 Appendix: 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. Copyright (C) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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. , 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. gpart-0.3/Changes000066400000000000000000000036151262504202100137630ustar00rootroot00000000000000v0.2.1 - Fix distribution issues that prevented builds of dist tarball v0.2 - Import some FreeBSD patches - Default scan by sector size to handle new 4k alignment method - Properly consider the real size of the disk to not invalidate partitions v0.1i - Switch to autoconf/automake for cross-platform support - Integrate patches from distributions to fix build and overflow issues v0.1h - New support for the following filesystems: BeOS, QNX 4.x & SGI XFS. - Updated Reiser filesystem support (Francis Devereux ). - Updated LVM support. - Several small fixes from contributors. v0.1g - For access via raw devices: made writing of guessed table also aligned (reading has been aligned since 0.1f). - Fixed stupid copy&paste bug in the partition table check routine. v0.1f - Default scan increment 'h' again. - Fixed wrong head-boundary condition. - Introduced possibility to edit guessed partitions. - Scan now starts on (sectors/head) unless -k was given. - Length of guessed NTFS partitions now includes NTFS backup boot sector. v0.1e - Default scan increment now 's', extended ptbl boundary condition now depends on scan increment (head if 's', else cylinder boundary). - Added LVM physical volume module (LVM by Heinz Mauelshagen). v0.1d - Cope with short reads/read errors from disk (corrupted sectors etc.). - When flagging probable partitions 'invalid' give a reason why. - Fixed buggy ext2 spare superblock location calculation. v0.1c - Don't flag partitions 'invalid' which are smaller than their partition table entry. - Fixed buggy rejection of some valid ext2 superblocks. - Fixed linux swap partition size calculation. - Added ReiserFS module. v0.1b - First public version. - Made 'fast' scan the default behaviour (-f enables the complete scan). - Increased tolerance in recognizing extended partition tables. v0.1a - Initial version. gpart-0.3/INSTALL000066400000000000000000000007521262504202100135200ustar00rootroot00000000000000 gpart Compilation and Installation Up to now a configure script for gpart does not seem necessary, it should compile under Linux and FreeBSD using GNU cc and GNU make. Steps to compile and install: - change the installation directory prefix "prefix" in the file "inst.defs". The default is "/usr/local". - type "make". - if no errors were encountered, type "make install". It is a good idea to read the man page before starting to play around. gpart-0.3/LSM000066400000000000000000000017371262504202100130510ustar00rootroot00000000000000Begin4 Title: gpart Version: 0.1h Entered-date: 2000-02-09 Description: A tool which tries to guess the primary partition table of a PC-type hard disk in case the primary partition table in sector 0 is damaged, incorrect or deleted. The guessed table can be written to a file or device. Supported (guessable) filesystem or partition types: DOS/Windows FAT, Linux ext2 and swap, OS/2 HPFS, Windows NTFS, FreeBSD and Solaris/x86 disklabels, Minix FS, QNX 4 FS, Reiser FS, LVM physical volumes, BeOS FS, SGI XFS. Keywords: hard disk primary partition table reconstruction Author: michail@brzitwa.de (Michail Brzitwa) Maintained-by: michail@brzitwa.de (Michail Brzitwa) Primary-site: http://home.pages.de/~michab/gpart/ ~51k gpart-0.1h.tar.gz Alternate-site: metalab.unc.edu /pub/Linux/system/filesystems Copying-policy: GPL End gpart-0.3/Makefile.am000066400000000000000000000002141262504202100145140ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign SUBDIRS = src man docdir = $(datadir)/doc/@PACKAGE@ doc_DATA = Changes README.md EXTRA_DIST = Changes README.md gpart-0.3/README.md000066400000000000000000000177121262504202100137520ustar00rootroot00000000000000# gpart [![Build Status](https://travis-ci.org/baruch/gpart.svg)](https://travis-ci.org/baruch/gpart) Gpart is a small tool which tries to guess what partitions are on a PC type, MBR-partitioned hard disk in case the primary partition table was damaged. Gpart works by scanning through the device (or file) given on the command line on a sector basis. Each guessing module is asked if it thinks a filesystem it knows about could start at a given sector. Several filesystem guessing modules are built in. Consult the manual page for command line options and usage. ## Installation See file *INSTALL*. ## Currently recognized partitions/filesystems types Modname | Typ | Description :--------|:----:|:------------ fat | 0x01 | Primary DOS with 12 bit FAT | 0x04 | Primary DOS with 16 bit FAT (<= 32MB) | 0x06 | Primary 'big' DOS (> 32MB) | 0x0B | DOS or Windows 95 with 32 bit FAT | 0x0C | DOS or Windows 95 with 32 bit FAT, LBA ntfs | 0x07 | OS/2 HPFS, NTFS, QNX or Advanced UNIX hpfs | 0x07 | OS/2 HPFS, NTFS, QNX or Advanced UNIX ext2 | 0x83 | Linux ext2 filesystem lswap | 0x82 | Linux swap bsddl | 0xA5 | FreeBSD/NetBSD/386BSD s86dl | 0x82 | Solaris/x86 disklabel minix | 0x80 | Minix V1 | 0x81 | Minix V2 reiserfs | 0x83 | ReiserFS filesystem hmlvm | 0xFE | Linux LVM physical volumes qnx4 | 0x4F | QNX 4.x beos | 0xEB | BeOS fs xfs | 0x83 | SGI XFS filesystem ## Guessing modules Each guessing module must provide three functions callable from gpart: int xxx_init(disk_desc *d,g_module *m) > Initialisation function. Will be called before a scan. > It should return the minimum number of bytes it wants > to receive for a test. The module should set the > description of the filesystem/partition type it handles > in `g_module.m_desc`. If the filesystem/partition type > included a partition table like first sector (like the > \*BSD disklabels do), the flag `m_hasptbl` should be set. > Another flag is `m_notinext` which means the tested type > cannot reside in a logical partition. int xxx_term(disk_desc *d) > Termination/cleanup function, called after the scanning > of the device has been done. int xxx_gfun(disk_desc *d,g_module *m) > The actual guessing function, called from within the > scan loop. It should test the plausibility of the > given sectors, and return its guess in `m->m_guess` (a > probability between 0 and 1). See existing modules > for examples. > > The given file descriptor `d->d_fd` can be used for seeking > and reading (see e.g. *gm_ext2.c* which tries to read > the first spare superblock). If a module is convinced > that it has found a filesystem/partition start it should > fill in the assumed begin and size of the partition. > > The test performed should not be too pedantic, for > instance it should not be relied upon that the file- > system is clean/was properly unmounted. On the other > hand too much tolerance leads to misguided guesses, > so a golden middle way must be found. ## Output explanation Here is a sample `gpart -v` run on my first IDE hard disk (comments in block-quotes): dev(/dev/hda) mss(512) chs(1232/255/63)(LBA) #s(19792080) size(9664mb) > `mss` is the medium sector size, `chs` the geometry retrieved > from the OS (or from the command line), `#s` is the total > sector count. Primary partition(1) type: 006(0x06)(Primary 'big' DOS (> 32MB)) (BOOT) size: 502mb #s(1028097) s(63-1028159) chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r hex: 80 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 > `size`: the size of the partition in megabytes, number of > sectors and the sector range. > `chs`: the partition table chs range (`d`) and the real one > (`r`). If the number of cylinders is less than 1024, both > are identical. > `hex`: the hexadecimal representation of the partition entry > as found in the partition table. ... Begin scan... Possible partition(DOS FAT), size(502mb), offset(0mb) type: 006(0x06)(Primary 'big' DOS (> 32MB)) size: 502mb #s(1028097) s(63-1028159) chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r hex: 00 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 Possible extended partition at offset(502mb) Possible partition(Linux ext2), size(31mb), offset(502mb) type: 131(0x83)(Linux ext2 filesystem) size: 31mb #s(64196) s(1028223-1092418) chs: (64/1/1)-(67/254/62)d (64/1/1)-(67/254/62)r hex: 00 01 01 40 83 FE 3E 43 7F B0 0F 00 C4 FA 00 00 Possible partition(Linux swap), size(125mb), offset(533mb) type: 130(0x82)(Linux swap or Solaris/x86) size: 125mb #s(256976) s(1092483-1349458) chs: (68/1/1)-(83/254/62)d (68/1/1)-(83/254/62)r hex: 00 01 01 44 82 FE 3E 53 83 AB 10 00 D0 EB 03 00 > During the scan phase all found partitions are listed by > their real type names. The Linux swap partition above is > recognized as Linux swap but will get the 0x82 partition > identifier which can be both a Solaris disklabel or a > Linux swap partition. > > When examining the hex values of the first primary partition > it can be seen that they are identical to the values of the > actual partition table (good guess) except for the first > value (0x80 vs. 0x00). This entry denotes the partition > 'boot' flag which cannot be guessed. ... End scan. Checking partitions... Partition(Primary 'big' DOS (> 32MB)): primary Partition(Linux ext2 filesystem): logical Partition(Linux swap or Solaris/x86): logical Partition(Linux LVM physical volume): logical Partition(Linux ext2 filesystem): logical Partition(DOS or Windows 95 with 32 bit FAT, LBA): logical Partition(FreeBSD/NetBSD/386BSD): primary Partition(Linux LVM physical volume): primary Ok. > During the scan phase gpart gathers a simple list of possible > partitions, the check phase now tries to decide if found > extended partitions seem consistent, if partitions do not > overlap etc. Overlapping partitions are silently discarded, > all remaining ones are given an attribute 'primary', 'logical', > 'orphaned' or 'invalid'. If gpart is called like `gpart -vv ...`, > it also tells why it thinks a partition guess is invalid. > > If any inconsistencies are found, gpart prints the number > of remaining inconsistencies, otherwise it says 'Ok.' Guessed primary partition table: Primary partition(1) type: 006(0x06)(Primary 'big' DOS (> 32MB)) size: 502mb #s(1028097) s(63-1028159) chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r hex: 00 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 Primary partition(2) type: 005(0x05)(Extended DOS) size: 6157mb #s(12611025) s(1028160-13639184) chs: (64/0/1)-(848/254/63)d (64/0/1)-(848/254/63)r hex: 00 00 01 40 05 FE FF 50 40 B0 0F 00 D1 6D C0 00 Primary partition(3) type: 165(0xA5)(FreeBSD/NetBSD/386BSD) size: 1396mb #s(2859570) s(13639185-16498754) chs: (849/0/1)-(1023/254/63)d (849/0/1)-(1026/254/63)r hex: 00 00 C1 51 A5 FE FF FF 11 1E D0 00 32 A2 2B 00 Primary partition(4) type: 254(0xFE)(Linux LVM physical volume) size: 1608mb #s(3293325) s(16498755-19792079) chs: (1023/254/63)-(1023/254/63)d (1027/0/1)-(1231/254/63)r hex: 00 FE FF FF FE FE FF FF 43 C0 FB 00 8D 40 32 00 > This is a resulting primary partition table. Note that > the logical partition guesses were only used to create > the extended partition entry. Up to now gpart cannot > reconstruct a damaged logical partition chain itself. > > If a guessed primary partition table should be written to > some file or device the user must specify (via the `-W` > option) which partition gets the active (bootable) one. ## Author gpart README, Aug 1999, Michail Brzitwa gpart-0.3/autogen.sh000077500000000000000000000001201262504202100144550ustar00rootroot00000000000000#!/bin/sh set -e aclocal autoconf autoheader automake --add-missing ./configure gpart-0.3/configure.ac000066400000000000000000000016731262504202100147600ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.64]) AC_INIT(gpart, 0.2.3-dev, https://github.com/baruch/gpart/issues) AM_INIT_AUTOMAKE([1.11]) AC_CONFIG_SRCDIR([src/gpart.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC AC_PROG_INSTALL # Checks for header files. AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_INT16_T AC_TYPE_INT8_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_MALLOC AC_CHECK_FUNCS([getpagesize memset strchr strdup strerror strtoul]) # Configure system services. AC_SYS_LARGEFILE AC_CONFIG_FILES([Makefile man/Makefile src/Makefile man/gpart.8]) AC_OUTPUT gpart-0.3/man/000077500000000000000000000000001262504202100132365ustar00rootroot00000000000000gpart-0.3/man/Makefile.am000066400000000000000000000000231262504202100152650ustar00rootroot00000000000000man_MANS = gpart.8 gpart-0.3/man/gpart.8.in000066400000000000000000000342221262504202100150540ustar00rootroot00000000000000.\" .\" gpart v@VERSION@ man page (c) Jan 1999 Michail Brzitwa .\" .TH GPART 8 "January 2001" "Administration Tools" .SH NAME gpart \- guess PC-type hard disk partitions .SH SYNOPSIS .B gpart [options] .I device Options: [\-b ][\-C c,h,s][\-c][\-d][\-E][\-e][\-f] [\-g][\-h][\-i][\-K ][\-k <# of sectors>] [\-L] [\-l ][\-n ] [\-q][\-s ] [\-t ][\-V][\-v] [\-W ][\-w ] .SH DESCRIPTION .B gpart tries to guess which partitions are on a hard disk. If the primary partition table has been lost, overwritten or destroyed the partitions still exist on the disk but the operating system cannot access them. .B gpart ignores the primary partition table and scans the disk (or disk image, file) sector after sector for several filesystem/partition types. It does so by "asking" filesystem recognition modules if they think a given sequence of sectors resembles the beginning of a filesystem or partition type. Currently the following filesystem types are known to .B gpart (listed by module names) : .TP .I beos BeOS filesystem type. .TP .I bsddl FreeBSD/NetBSD/386BSD disklabel sub-partitioning scheme used on Intel platforms. .TP .I ext2 Linux second extended filesystem. .TP .I fat MS-DOS FAT12/16/32 "filesystems". .TP .I hpfs IBM OS/2 High Performance filesystem. .TP .I hmlvm Linux LVM physical volumes (LVM by Heinz Mauelshagen). .TP .I lswap Linux swap partitions (versions 0 and 1). .TP .I minix The Minix operating system filesystem type. .TP .I ntfs MS Windows NT/2000 filesystem. .TP .I qnx4 QNX 4.x filesystem. .TP .I reiserfs The Reiser filesystem (version 3.5.X, X > 11, 3.6.X). .TP .I s86dl Sun Solaris on Intel platforms uses a sub-partitioning scheme on PC hard disks similar to the BSD disklabels. .TP .I xfs Silicon Graphic's journalling filesystem for Linux. .PP More filesystem guessing modules can be added at runtime (see the .I -t option). Please consult the .B gpart README file for detailed explanations on how to create guessing modules. All modules are accompanied by a guessing weight factor which denotes how "educated" their guesses are compared to other modules. This weight can be changed if a certain module keeps on mis-identifying a partition. Naturally only partitions which have been formatted in some way can be recognized. If the type of a partition entry in the primary partition table is changed from x to y while the filesystem is still of type x, .B gpart will also still guess a type x. No checks are performed whether a found filesystem is clean or even consistent/mountable, so it is quite possible that .B gpart may identify partitions which existed prior to the current partitioning scheme of the disk. Especially on large disks old file system headers/superblocks may be present a long time until they are finally overwritten with user data. It should be stressed that .B gpart does a very heuristic job, never believe its output without any plausability checks. It can be easily right in its guesswork but it can also be terribly wrong. You have been warned. After having found a list of possible partition types, the list is checked for consistency. For example, a partition which overlaps with the previous one will be discarded. All remaining partitions are labelled with one of the following attributes: "primary", "logical", "orphaned" or "invalid". A partition labelled "orphaned" is a logical partition which seems ok but is missed in the chain of logical partitions. This may occur if a logical partition is deleted from the extended partition table without overwriting the actual disk space. An "invalid" partition is one that cannot be accepted because of various reasons. If a consistent primary partition table was created in this process it is printed and can be written to a file or device. .SH EXTENDED PARTITIONS If the disk/file to be examined consists of primary partitions only, .B gpart has quite a good chance to identify them. Extended partitions on the other hand can result in a lot of problems. Extended partitions are realized as a linked list of extended partition tables, each of which include an entry pointing to a logical partition. The size of an extended partition depends on where the last logical partition ends. This means that extended partitions may include "holes", unallocated disk space which should only be assigned to logical, not primary partitions. .B gpart tries to do its best to check a found chain of logical partitions but there are very many possible points of failure. If "good" fdisk programs are used to create extended partitions, the resulting tables consist of a zeroed boot record and the four partition entries of which at least two should be marked unused. Unfortunately e.g. the fdisk program shipped with Windows NT does not seem to zero out the boot record area so .B gpart has to be overly tolerant in recognizing extended partition tables. This tolerance may result in quite stupid guesses. .SH DISK TRANSFERS If you want to investigate hard disks from other systems you should note down the geometry (number of cylinders, heads per cylinder and sectors per head) used for that disk, and tell .B gpart about this geometry. Investigating disks from machines with a different endianness than the scanning one has not been tested at all, and is currently not recommended. .SH LARGE DISKS .B gpart relies on the OS reporting the correct disk geometry. Unfortunately sometimes the OS may report a geometry smaller the the actual one (e.g. disks with more than 1024 or 16384 cylinder). .B gpart checks if guessed partitions extend beyond the disk size and marks those "invalid", but may be mistaken in case the disk size is calculated from an incorrect geometry. For instance if a disk with the geometry 1028/255/63 should be scanned, and the OS reports 1024/255/63 .B gpart should be called like .RS gpart \-C 1028,255,63 .RE .SH PRECAUTIONS .B gpart may be of some help when the primary partition table was lost or destroyed but it can under .B no circumstances replace proper disk/partition table backups. To save the master boot record (MBR) including the primary partition table to a file type .RS dd if=/dev/hda of=mbr bs=512 count=1 .RE exchanging /dev/hda with the block device name of the disk in question. This should be done for all disks in the system. To restore the primary partition table without overwriting the MBR type .RS dd if=mbr of=/dev/hda bs=1 count=64 skip=446 seek=446 .RE .B Warning: make sure that all parameters are typed as shown and that the disk device is correct. Failing to do so may result in severe filesystem corruption. The saved file should be stored in a safe place like a floppy disk. .SH OPTIONS .IP "-b backupfile" If the guessed primary partition table seems consistent and should be written (see the .I \-W option) backup the current MBR into the specified file. .IP "-C c,h,s" Set the disk geometry (cylinders, heads, sectors) for the scan. This is useful if a disk should be scanned which was partitioned using a different geometry, if the .I device is a disk-image or if the disk geometry cannot be retrieved through the PCs BIOS. No spaces are allowed between the numbers, unless all three are enclosed in quotes. .IP -c Check/compare mode (implies the .I -q quiet option). After the scan is done, the resulting primary partition table is compared to the existing one. The return code of .B gpart then contains the number of differences (0 if they are identical except for the boot/active flag which cannot be guessed). This option has no effect if .I -d is given on the command line. .IP -d Do not start the guessing loop. Useful if the partition table should be printed (in combination with the .I -v option) without actually scanning for partitions. .IP -E Do not try to identify extended partition tables. If there are extended partitions on the given device .B gpart will most certainly complain about too many primary partitions because there can be only four primary partitions. Existing logical partitions will be listed as primary ones. .IP -e Do not skip disk read errors. If this option is given, and short disk reads or general disk read errors (EIO) are encountered, .B gpart will exit. If not given, the program tries to continue. .IP -f Full scan. When a possible partition is found, .B gpart normally skips all sectors this entry seems to occupy and continues the scan from the end of the last possible partition. The disk scan can take quite a while if this option is given, be patient. .IP -g Do not try to get the disk geometry from the OS. If the .I device is no block or character device but a plain file this option should be supplied. If the file to be scanned is an image of a disk, the geometry can be given by the .I -C option. .IP -h Show some help. .IP -i Run interactively. Each time a possible partition is identified the user is asked for confirmation. .IP "-K last sector" Scan only up to the given sector or the end of the file or device whichever comes first. .IP "-k sectors" Skip given number of sectors before the scan. Potentially useful if a partition is looked for at the end of a large disk. .IP -L List available filesystem/partition type modules and their weights, then exit. .IP "-l logfile" Log output to the given file (even if .I -q was supplied). .IP "-n increment" Scan increment: number of sectors or "s" for single sector increment, "h" for an increment of sectors per head (depends on geometry) or "c" for cylinder increment. The increment also influences the condition where extended partition tables are searched: if the scan increment is "s" (i.e. 1) extended partition tables are required to be on a head boundary, otherwise they must be on a cylinder boundary. If the disk geometry could not be retrieved and no geometry was given on the command line, the default increment is one sector. .IP -q Quiet/no output mode. However if a logfile was specified (see .I -l option) all output is written to that file. This option overrides the .I -i interactive mode. .IP "-s sector size" Preset medium sector size. .B gpart tries to find out the sector size but may fail in doing so. Probed sector sizes are 2^i, i=9..14 (512 to 16384 bytes). The default medium sector size is 512 bytes. .IP -V Show version number. .IP -v Be verbose. This option can be given more than once resulting in quite a lot of information. .IP "-W device" Write partition table. If a consistent primary partition table has been guessed it can be written to the specified file or device. The supplied device can be the same as the scanned one. Additionally the guessed partition entries can be edited. No checks are performed on the entered values, thus the resulting table is allowed to be highly inconsistent. Please beware. .B Warning: The guessed partition table should be checked very carefully before writing it back. You can always write the guessed partition table into a plain file and write this into sector 0 using .BR dd (1) (see section PRECAUTIONS above). .IP "-w module name,weight" Put the given module at the head of the module chain and assign a new weight to that module. All modules are given an initial weight of 1.0. Again no spaces are allowed. .PP Default settings are "\-n h". .SH EXAMPLES \-\ To scan the first IDE hard disk under Linux using default settings type .RS gpart /dev/hda .RE \-\ To print the primary partition table of the third IDE drive without starting the scan loop in FreeBSD type .RS gpart \-vvd /dev/wd2 .RE .RE \-\ If .BR lilo(8) was installed in the master boot record (MBR) of a hard disk it saves the contents of the first sector in a file called /boot/boot.. To list the partitions contained in such a file type e.g. .RS gpart \-vdg /boot/boot.0300 .RE If the partition table contains an extended partition, .B gpart will complain about invalid extended partition tables because the extended entry points to sectors not within that file. \-\ Usually the first primary partition starts on the second head. If .B gpart cannot identify the first partition properly this may not be the case. .B gpart can be told to start the scan directly from sector one of the disk, using the sector-wise scan mode: .RS gpart \-k 1 \-n s /dev/hdb .RE \-\ Suppose .B gpart identifies an NTFS partition as FAT on a certain disk. In this situation the "ntfs" module should be made the first module to be probed and given a weight higher than the usual weight of 1.0: .RS gpart \-w ntfs,1.5 /dev/hdb .RE To list the available modules and their weights use the .I -L option. \-\ After having checked the output of .B gpart at least thrice, the primary partition table can be written back to the device this way: .RS gpart \-W /dev/sdc /dev/sdc .RE This of course may be extremely dangerous to your health and social security, so beware. \-\ A hard disk with 63 sectors per head is scanned in steps of 63 sectors. To perform the scan on every second head while skipping the first 1008 sectors type .RS gpart \-k 1008 \-n 126 /dev/sda .RE \-\ If you want to see how easily .B gpart can be mislead, and how many probable partition starts are on a disk, search the whole disk really sector by sector, writing all output to a logfile: .RS gpart \-vvfn s \-ql /tmp/gpart.log /dev/sd2 & .RE Usually .B gpart will not be able to produce an educated guess of the primary partition table in this mode. The logfile however may contain enough hints to manually reconstruct the partition table. .SH FILES .I /dev/* .RS Hard disk block devices. The naming scheme of hard disk block devices is OS dependent, consult your system manuals for more information. .RE .SH DIAGNOSTICS There are many error message types, all of them should be self-explanatory. Complain if they are not. .SH BUGS .B gpart is beta software, so expect buggy behaviour. \-\ .B gpart only accepts extended partition links with one logical partition. There may be .B fdisk variants out there creating links with up to three logical partition entries but these are not accepted. .SH TO DO .br \-\ Support big-endian architectures. .br \-\ Test on 64-bit architectures. .br \-\ Look for boot manager partitions (e.g. OS/2 BM). .br \-\ Think about reconstructing logical partition chains. .SH AUTHOR Please send bug reports, suggestions, comments etc. to .RS Michail Brzitwa .RE .SH "SEE ALSO" .BR fdisk (8). gpart-0.3/src/000077500000000000000000000000001262504202100132525ustar00rootroot00000000000000gpart-0.3/src/Makefile.am000066400000000000000000000007241262504202100153110ustar00rootroot00000000000000AM_CFLAGS = -Wall -O2 AM_LDFLAGS = sbin_PROGRAMS = gpart gpart_SOURCES = disku.c gm_beos.c gm_bsddl.c gm_ext2.c gm_btrfs.c gm_fat.c gm_hmlvm.c gm_lvm2.c gm_hpfs.c gm_lswap.c gm_minix.c gm_ntfs.c gmodules.c gm_qnx4.c gm_reiserfs.c gm_s86dl.c gm_xfs.c gpart.c l64seek.c EXTRA_DIST = errmsgs.h gm_bsddl.h gm_fat.h gm_hpfs.h gm_ntfs.h gm_qnx4.h gm_s86dl.h gpart.h gm_beos.h gm_ext2.h gm_btrfs.h gm_hmlvm.h gm_lvm2.h gm_minix.h gmodules.h gm_reiserfs.h gm_xfs.h l64seek.h gpart-0.3/src/disku.c000066400000000000000000000056451262504202100145470ustar00rootroot00000000000000/* * disku.c -- gpart disk util routines * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 13.12.2000 * Calculation of disk cylinder count changed for Linux. * */ #include #include #include #include #include #include "gpart.h" #if defined(__linux__) #include #include #endif #if defined(__FreeBSD__) #include #include #include #endif #include /* * get disk geometry. The medium is opened for reading, * descriptor in d_fd. */ struct disk_geom *disk_geometry(disk_desc *d) { static struct disk_geom g; uint64_t nsects; memset(&g, 0, sizeof(g)); #if defined(__linux__) struct hd_geometry hg; #endif #if defined(__FreeBSD__) struct disklabel dl; #endif struct stat st; int ret; uint64_t lba; ret = stat(d->d_dev, &st); if (ret == 0) { if (S_ISREG(st.st_mode)) { nsects = st.st_size / 512; if (nsects == 0) pr(FATAL, EM_FATALERROR, "Not a block device image file"); lba = nsects - 1; g.d_h = (lba / 63) % 255; g.d_s = lba % 63 + 1; g.d_c = lba / (255 * 63); g.d_nsecs = nsects; return (&g); } } #if defined(__linux__) if (ioctl(d->d_fd,HDIO_GETGEO,&hg) == -1) pr(FATAL,EM_IOCTLFAILED,"HDIO_GETGEO",strerror(errno)); #ifdef BLKGETSIZE if (ioctl(d->d_fd,BLKGETSIZE,&nsects) == -1) pr(FATAL,EM_IOCTLFAILED,"BLKGETSIZE",strerror(errno)); g.d_nsecs = nsects; g.d_c = nsects / (hg.heads * hg.sectors); #else g.d_c = hg.cylinders; #endif g.d_h = hg.heads; g.d_s = hg.sectors; #endif #if defined(__FreeBSD__) struct disklabel loclab; u_int u; off_t o; /* total disk size */ if (ioctl(d->d_fd, DIOCGFWSECTORS, &u) == 0) g.d_s = u; else pr(FATAL, EM_IOCTLFAILED, "DIOCGFWSECTORS", strerror(errno)); // loclab.d_nsectors = 63; if (ioctl(d->d_fd, DIOCGFWHEADS, &u) == 0) g.d_h = u; else pr(FATAL, EM_IOCTLFAILED, "DIOCGFWHEADS", strerror(errno)); if (ioctl(d->d_fd, DIOCGSECTORSIZE, &u) == 0) if (u != 512) pr(FATAL, "sector size not a multiple of 512"); if (ioctl(d->d_fd, DIOCGMEDIASIZE, &o)) pr(FATAL, EM_IOCTLFAILED, "DIOCGMEDIASIZE", strerror(errno)); g.d_nsecs = o / u; g.d_c = g.d_nsecs / g.d_h / g.d_s; #endif return (&g); } /* * tell the OS to reread a changed partition table. Do * nothing if there is no such possibility. */ int reread_partition_table(int fd) { #if defined(__linux__) && defined(BLKRRPART) if (ioctl(fd,BLKRRPART) == -1) { pr(ERROR,"rereading partition table: %s",strerror(errno)); return (0); } #endif return (1); } gpart-0.3/src/errmsgs.h000066400000000000000000000116231262504202100151100ustar00rootroot00000000000000/* * errmsgs.h -- gpart error/warning messages header file * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _ERRMSGS_H #define _ERRMSGS_H /* dialog messages */ #define DM_YESNO "(y,n)" #define DM_YES "yY" #define DM_NUMORQUIT " (%d..%d, q to quit) : " #define DM_QUIT "qQ" #define DM_STARTSCAN "\nBegin scan...\n" #define DM_ENDSCAN "End scan.\n" #define DM_EDITPTBL "Edit this table" #define DM_ACCEPTGUESS "\nAccept this guess" #define DM_ACTWHICHPART "Activate which partition" #define DM_EDITWHICHPART "Edit which partition" #define DM_WRITEIT "Write this partition table" #define DM_ASKTOREBOOT "partition table written, you should reboot now" #define DM_NOTWRITTEN "Partition table not written\n" #define DM_STARTCHECK "\nChecking partitions...\n" #define DM_NOOFINCONS "Number of inconsistencies found: %d.\n" #define DM_GUESSEDPTBL "\nGuessed primary partition table:\n" #define DM_NOCHECKWARNING "\nWarning: entered values will not be checked; enter at your own risk!\n" #define DM_EDITWHICHITEM "\nEdit which value" /* partition list messages */ #define PM_DEVDESC1 "\ndev(%s) mss(%d)" #define PM_DEVDESC2 " chs(%d/%d/%d)%s#s(%qd) size(%qdmb)" #define PM_MBRPRINT "\ndev(%s) master boot record (w/o partition table):\n" #define PM_PRIMPART "Primary partition(%d)\n" #define PM_EXTPART " Logical partition\n" #define PM_POSSIBLEPART "Possible partition(%s), size(%qdmb), offset(%qdmb)\n" #define PM_POSSIBLEEXTPART "Possible extended partition at offset(%qdmb)\n" #define PM_PT_TYPE " type: %03d(0x%02X)(%s)" #define PM_PT_SIZE " size: %qdmb #s(%qd)" #define PM_PT_CHS " chs: (%d/%d/%d)-(%d/%d/%d)d" #define PM_PT_HEX " hex: " #define PM_G_PRIMARY "primary " #define PM_G_LOGICAL "logical " #define PM_G_INVALID "invalid " #define PM_G_ORPHANED "orphaned " #define PM_EDITITEM1 "1 - Absolute start sector (%12lu)\n" #define PM_EDITITEM2 "2 - Absolute sector count (%12lu)\n" #define PM_EDITITEM3 "3 - Partition type (%12d)(%s)\n" /* error/warning messages */ #define EM_FATALERROR "\n*** Fatal error: %s.\n" #define EM_SIMPLEERROR "\n** Error: %s.\n" #define EM_WARNING "\n* Warning: %s.\n" #define EM_PINVALID "\n* Partition invalid(%s):\n" #define EM_MALLOCFAILED "malloc(%d) failed" #define EM_IOCTLFAILED "ioctl(%s) failed: %s" #define EM_OPENFAIL "open(%s): %s" #define EM_STRANGEPTBLMAGIC "strange partition table magic 0x%04X" #define EM_WRONGSECTSIZE "sector size must be > 0 and <= %d" #define EM_FAILSSIZEATTEMPT "failed trying to use sector size %d" #define EM_SEEKFAILURE "dev(%s): seek failure" #define EM_STATFAILURE "stat(%s): %s" #define EM_READERROR "dev(%s): read error near sector(%qd): %s" #define EM_CANTGETSSIZE "cannot get sector size on dev(%s)" #define EM_CANTGETGEOM "cannot get disk geometry" #define EM_MINITFAILURE "module(%s) failed to init" #define EM_INVVALUE "invalid number value" #define EM_PSTART2BIG "partition(%s) starts beyond disk end" #define EM_PSIZE2BIG "partition(%s) is bigger than the disk" #define EM_PEND2BIG "partition(%s) ends beyond disk end" #define EM_STRANGEPTYPE "partition(%s) contains strange flag" #define EM_PTBLREAD "failed to read partition table" #define EM_PTBLWRITE "could not write partition table" #define EM_MBRWRITE "could not write master boot record" #define EM_TOOMANYEXTP "found more than one extended partition, skipping" #define EM_TOOMANYLOGP "more than %d logical partitions encountered" #define EM_EPILLEGALOFS "extended ptbl illegal sector offset" #define EM_INVXPTBL "invalid extended ptbl found at sector(%qd)" #define EM_DISCARDOVLP "Discarded %d overlapping partition guesses" #define EM_TOOMANYXPTS "more than one extended partition: %d" #define EM_TOOMANYPPTS "more than %d primary partitions: %d" #define EM_OPENLOG "cannot open logfile %s" #define EM_NOSUCHMOD "no such module: %s" #define EM_SHORTBREAD "short read near sector(%qd), %d bytes instead of %d. Skipping.." #define EM_BADREADIO "read error (EIO) near sector(%qd), skipping.." #define EM_PINCONS "partition still overlaps with previous one or seems invalid:" #define EM_P_EATEND "extended ptbl without any following partitions" #define EM_P_EWLP "extended ptbl without logical partition" #define EM_P_MTOE "encountered a second extended ptbl" #define EM_P_LISAE "logical partition is an extended partition" #define EM_P_UTS "wrong size, no valid type or (ptbl,link) type mismatch" #define EM_P_2MANYPP "too many primary partitions" #define EM_P_NOTSANE "invalid partition entry (see comments above)" #define EM_P_ENDNOTF "primary partition within extended ptbl link" #endif /* _ERRMSGS_H */ gpart-0.3/src/gm_beos.c000066400000000000000000000034221262504202100150320ustar00rootroot00000000000000/* * gm_beos.c -- gpart BeOS filesystem guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 29.01.2001 * Modified: * */ #include #include #include #include "gpart.h" #include "gm_beos.h" #include int beos_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "BeOS filesystem"; return (2 * 512); } int beos_term(disk_desc *d) { return (1); } int beos_gfun(disk_desc *d,g_module *m) { beos_super_block *sb; s64_t size; m->m_guess = GM_NO; /* * BeOS superblock without little/big endian conversions */ sb = (beos_super_block *)(d->d_sbuf + 512); if ((sb->magic1 != BEOS_SUPER_BLOCK_MAGIC1) || (sb->magic2 != BEOS_SUPER_BLOCK_MAGIC2) || (sb->magic3 != BEOS_SUPER_BLOCK_MAGIC3)) return (1); /* * some consistency checks */ if ((sb->block_size != 1024) && (sb->block_size != 2048) && (sb->block_size != 4096) && (sb->block_size != 8192)) return (1); if (sb->block_size != 1 << sb->block_shift) return (1); if (sb->num_blocks < sb->used_blocks) return (1); if ((sb->flags != BEOS_CLEAN) && (sb->flags != BEOS_DIRTY)) return (1); /* * I hope this is enough, if not I have to read the root dir * as well later. */ size = sb->num_blocks; size *= sb->block_size; size /= d->d_ssize; m->m_guess = GM_YES; m->m_part.p_typ = 0xEB; m->m_part.p_start = d->d_nsb; m->m_part.p_size = (unsigned long)size; return (1); } gpart-0.3/src/gm_beos.h000066400000000000000000000044241262504202100150420ustar00rootroot00000000000000/* * gm_beos.h -- gpart BeOS filesystem guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 29.01.2001 * Modified: * */ #ifndef _GM_BEOS_H #define _GM_BEOS_H /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; /* * BeOS filesystem structures, taken from "BEOS filesystem for Linux 1999-05-28" * by Makoto Kato */ /* * Flags of superblock */ #define BEOS_CLEAN 0x434c454e #define BEOS_DIRTY 0x44495254 /* * Magic headers of BEOS's superblock, inode and index */ #define BEOS_SUPER_BLOCK_MAGIC1 0x42465331 /* BEOS1 */ #define BEOS_SUPER_BLOCK_MAGIC2 0xdd121031 #define BEOS_SUPER_BLOCK_MAGIC3 0x15b6830e #define BEOS_INODE_MAGIC1 0x3bbe0ad9 #define BEOS_INDEX_MAGIC 0x69f6c2e8 #define BEOS_SUPER_MAGIC BEOS_SUPER_BLOCK_MAGIC1 #define BEOS_NUM_DIRECT_BLOCKS 12 #define BEOS_NAME_LENGTH 32 /* * BEOS filesystem type */ #define BEOS_PPC 1 #define BEOS_X86 2 /* * special type of BEOS */ typedef s64_t beos_off_t; typedef s64_t beos_bigtime_t; typedef void beos_binode_etc; typedef struct _beos_block_run { __u32 allocation_group; __u16 start; __u16 len; } beos_block_run; typedef beos_block_run beos_inode_addr; /* * The Superblock Structure */ typedef struct _beos_super_block { char name[BEOS_NAME_LENGTH]; __u32 magic1; __u32 fs_byte_order; __u32 block_size; __u32 block_shift; beos_off_t num_blocks; beos_off_t used_blocks; __u32 inode_size; __u32 magic2; __u32 blocks_per_ag; __u32 ag_shift; __u32 num_ags; __u32 flags; beos_block_run log_blocks; beos_off_t log_start; beos_off_t log_end; __u32 magic3; beos_inode_addr root_dir; beos_inode_addr indices; __u32 pad[8]; } __attribute__ ((packed)) beos_super_block; #endif /* _GM_BEOS_H */ gpart-0.3/src/gm_bsddl.c000066400000000000000000000033121262504202100151700ustar00rootroot00000000000000/* * gm_bsddl.c -- gpart BSD disk label guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include "gpart.h" #include "gm_bsddl.h" int bsddl_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "*BSD disklabel"; m->m_hasptbl = 1; m->m_notinext = 1; return (BBSIZE); } int bsddl_term(disk_desc *d) { return (1); } int bsddl_gfun(disk_desc *d,g_module *m) { struct disklabel *dl; struct partition *bsdpt; unsigned short *cp, *ep, cs1, cs2; m->m_guess = GM_NO; dl = (struct disklabel *)(d->d_sbuf + LABELSECTOR * d->d_ssize); if ((dl->d_magic == le32(DISKMAGIC)) && (dl->d_magic2 == le32(DISKMAGIC))) { /* * partition RAW_PART(2) usually denotes the whole disk (slice) */ if (dl->d_npartitions <= RAW_PART) return (1); bsdpt = &dl->d_partitions[RAW_PART]; /* * some sanity checks: disklabel checksum and start * of partition. */ cs1 = 0; cs2 = le16(dl->d_checksum); dl->d_checksum = 0; cp = (unsigned short *)dl; ep = (unsigned short *)&dl->d_partitions[dl->d_npartitions]; for ( ; cp < ep; cp++) cs1 ^= le16(*cp); dl->d_checksum = le16(cs2); if ((le32(bsdpt->p_offset) == d->d_nsb) && (cs1 == cs2)) { m->m_part.p_typ = 0xA5; m->m_part.p_start = le32(bsdpt->p_offset); m->m_part.p_size = le32(bsdpt->p_size); m->m_guess = GM_YES; } } return (1); } gpart-0.3/src/gm_bsddl.h000066400000000000000000000131071262504202100152000ustar00rootroot00000000000000/* * gm_bsddl.h -- gpart BSD disk label guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_BSDDL_H #define _GM_BSDDL_H /* * BSD 4.4 disklabel support. Copied from the sources of the * FreeBSD (2.2.7) disklabel(8) program sources. These sources * are under the BSD licence, not the GPL. Please see http:// * www.freebsd.org/ for copyright/licence notes. */ #define STANDALONE #define BBSIZE 8192 /* size of boot area, with label */ #ifdef __i386__ #define LABELSECTOR 1 /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #endif #ifndef LABELSECTOR #define LABELSECTOR 0 /* sector containing label */ #endif #ifndef LABELOFFSET #define LABELOFFSET 64 /* offset of label in sector */ #endif #define DISKMAGIC ((u_int32_t)0x82564557) /* The disk magic number */ #ifndef MAXPARTITIONS #define MAXPARTITIONS 8 #endif #define LABEL_PART 2 /* partition containing label */ #define RAW_PART 2 /* partition containing whole disk */ #define SWAP_PART 1 /* partition normally containing swap */ struct disklabel { u_int32_t d_magic; /* the magic number */ u_int16_t d_type; /* drive type */ u_int16_t d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ /* * d_packname contains the pack identifier and is returned when * the disklabel is read off the disk or in-core copy. * d_boot0 and d_boot1 are the (optional) names of the * primary (block 0) and secondary (block 1-15) bootstraps * as found in /usr/mdec. These are returned when using * getdiskbyname(3) to retrieve the values from /etc/disktab. */ #if defined(KERNEL) || defined(STANDALONE) char d_packname[16]; /* pack identifier */ #else union { char un_d_packname[16]; /* pack identifier */ struct { char *un_d_boot0; /* primary bootstrap name */ char *un_d_boot1; /* secondary bootstrap name */ } un_b; } d_un; #define d_packname d_un.un_d_packname #define d_boot0 d_un.un_b.un_d_boot0 #define d_boot1 d_un.un_b.un_d_boot1 #endif /* ! KERNEL or STANDALONE */ /* disk geometry: */ u_int32_t d_secsize; /* # of bytes per sector */ u_int32_t d_nsectors; /* # of data sectors per track */ u_int32_t d_ntracks; /* # of tracks per cylinder */ u_int32_t d_ncylinders; /* # of data cylinders per unit */ u_int32_t d_secpercyl; /* # of data sectors per cylinder */ u_int32_t d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below are not counted in * d_nsectors or d_secpercyl. Spare sectors are assumed to * be physical sectors which occupy space at the end of each * track and/or cylinder. */ u_int16_t d_sparespertrack; /* # of spare sectors per track */ u_int16_t d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternate cylinders include maintenance, replacement, configuration * description areas, etc. */ u_int32_t d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* * d_interleave, d_trackskew and d_cylskew describe perturbations * in the media format used to compensate for a slow controller. * Interleave is physical sector interleave, set up by the * formatter or controller when formatting. When interleaving is * in use, logically adjacent sectors are not physically * contiguous, but instead are separated by some number of * sectors. It is specified as the ratio of physical sectors * traversed per logical sector. Thus an interleave of 1:1 * implies contiguous layout, while 2:1 implies that logical * sector 0 is separated by one sector from logical sector 1. * d_trackskew is the offset of sector 0 on track N relative to * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew * is the offset of sector 0 on cylinder N relative to sector 0 * on cylinder N-1. */ u_int16_t d_rpm; /* rotational speed */ u_int16_t d_interleave; /* hardware sector interleave */ u_int16_t d_trackskew; /* sector 0 skew, per track */ u_int16_t d_cylskew; /* sector 0 skew, per cylinder */ u_int32_t d_headswitch; /* head switch time, usec */ u_int32_t d_trkseek; /* track-to-track seek, usec */ u_int32_t d_flags; /* generic flags */ #define NDDATA 5 u_int32_t d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 u_int32_t d_spare[NSPARE]; /* reserved for future use */ u_int32_t d_magic2; /* the magic number (again) */ u_int16_t d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ u_int16_t d_npartitions; /* number of partitions in following */ u_int32_t d_bbsize; /* size of boot area at sn0, bytes */ u_int32_t d_sbsize; /* max size of fs superblock, bytes */ struct partition { /* the partition table */ u_int32_t p_size; /* number of sectors in partition */ u_int32_t p_offset; /* starting sector */ u_int32_t p_fsize; /* filesystem basic fragment size */ u_int8_t p_fstype; /* filesystem type, see below */ u_int8_t p_frag; /* filesystem fragments per block */ union { u_int16_t cpg; /* UFS: FS cylinders per group */ u_int16_t sgs; /* LFS: FS segment shift */ } __partition_u1; #define p_cpg __partition_u1.cpg #define p_sgs __partition_u1.sgs } d_partitions[MAXPARTITIONS]; /* actually may be more */ }; #endif /* _GM_BSDDL_H */ gpart-0.3/src/gm_btrfs.c000066400000000000000000000032651262504202100152270ustar00rootroot00000000000000/* * gm_btrfs.c -- gpart Linux Btrfs volume guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 20.11.2015 * */ #include #include #include #include "gpart.h" #include "gm_btrfs.h" int btrfs_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Btrfs volume"; return BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE; } int btrfs_term(disk_desc *d) { return (1); } int btrfs_gfun(disk_desc *d,g_module *m) { struct btrfs_super_block *sb; dos_part_entry *pt = &m->m_part; s64_t psize; m->m_guess = GM_NO; sb = (struct btrfs_super_block*) (d->d_sbuf + BTRFS_SUPER_INFO_OFFSET); if (le64toh(sb->magic) != BTRFS_MAGIC) return 1; if (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_FSID_SIZE)) return 1; psize = le64toh(sb->dev_item.total_bytes); if (psize > btrfs_sb_offset(1)) { struct btrfs_super_block sb_copy; if (l64seek(d->d_fd, d->d_nsb * d->d_ssize + btrfs_sb_offset(1), SEEK_SET) == -1) pr(FATAL,"btrfs: cannot seek: %s", strerror(errno)); read(d->d_fd, &sb_copy, sizeof(sb_copy)); if (le64toh(sb_copy.magic) != BTRFS_MAGIC || memcmp(sb->fsid, sb_copy.fsid, BTRFS_FSID_SIZE)) { pr(MSG,"btrfs: superblock copy mismatch\n"); return 1; } } m->m_guess = GM_YES; pt->p_start = d->d_nsb; pt->p_size = psize / d->d_ssize; pt->p_typ = 0x83; return 1; } gpart-0.3/src/gm_btrfs.h000066400000000000000000000076331262504202100152370ustar00rootroot00000000000000/* * gm_btrfs.h -- gpart Btrfs volume guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 20.11.2015 * Modified: * */ #ifndef _GM_BTRFS_H #define _GM_BTRFS_H /* * structs & defines gathered from btrfs-progs */ #if !defined(__FreeBSD__) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #endif typedef uint64_t __le64; typedef uint32_t __le32; typedef uint16_t __le16; typedef uint8_t u8; #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) #define BTRFS_SUPER_INFO_SIZE 4096 #define btrfs_sb_offset(i) ((i) ? ((16*1024) << (BTRFS_SUPER_MIRROR_SHIFT * (i))) : BTRFS_SUPER_INFO_SIZE) #define BTRFS_SUPER_MIRROR_SHIFT 12 #define BTRFS_CSUM_SIZE 32 #define BTRFS_FSID_SIZE 16 #define BTRFS_UUID_SIZE 16 #define BTRFS_MAGIC 0x4D5F53665248425FULL #define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 #define BTRFS_LABEL_SIZE 256 #define BTRFS_NUM_BACKUP_ROOTS 4 struct btrfs_root_backup { __le64 tree_root; __le64 tree_root_gen; __le64 chunk_root; __le64 chunk_root_gen; __le64 extent_root; __le64 extent_root_gen; __le64 fs_root; __le64 fs_root_gen; __le64 dev_root; __le64 dev_root_gen; __le64 csum_root; __le64 csum_root_gen; __le64 total_bytes; __le64 bytes_used; __le64 num_devices; /* future */ __le64 unsed_64[4]; u8 tree_root_level; u8 chunk_root_level; u8 extent_root_level; u8 fs_root_level; u8 dev_root_level; u8 csum_root_level; /* future and to align */ u8 unused_8[10]; } __attribute__ ((__packed__)); #define BTRFS_UUID_SIZE 16 struct btrfs_dev_item { /* the internal btrfs device id */ __le64 devid; /* size of the device */ __le64 total_bytes; /* bytes used */ __le64 bytes_used; /* optimal io alignment for this device */ __le32 io_align; /* optimal io width for this device */ __le32 io_width; /* minimal io size for this device */ __le32 sector_size; /* type and info about this device */ __le64 type; /* expected generation for this device */ __le64 generation; /* * starting byte of this partition on the device, * to allowr for stripe alignment in the future */ __le64 start_offset; /* grouping information for allocation decisions */ __le32 dev_group; /* seek speed 0-100 where 100 is fastest */ u8 seek_speed; /* bandwidth 0-100 where 100 is fastest */ u8 bandwidth; /* btrfs generated uuid for this device */ u8 uuid[BTRFS_UUID_SIZE]; /* uuid of FS who owns this device */ u8 fsid[BTRFS_UUID_SIZE]; } __attribute__ ((__packed__)); struct btrfs_super_block { u8 csum[BTRFS_CSUM_SIZE]; /* the first 3 fields must match struct btrfs_header */ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ __le64 bytenr; /* this block number */ __le64 flags; /* allowed to be different from the btrfs_header from here own down */ __le64 magic; __le64 generation; __le64 root; __le64 chunk_root; __le64 log_root; /* this will help find the new super based on the log root */ __le64 log_root_transid; __le64 total_bytes; __le64 bytes_used; __le64 root_dir_objectid; __le64 num_devices; __le32 sectorsize; __le32 nodesize; __le32 leafsize; __le32 stripesize; __le32 sys_chunk_array_size; __le64 chunk_root_generation; __le64 compat_flags; __le64 compat_ro_flags; __le64 incompat_flags; __le16 csum_type; u8 root_level; u8 chunk_root_level; u8 log_root_level; struct btrfs_dev_item dev_item; char label[BTRFS_LABEL_SIZE]; __le64 cache_generation; __le64 uuid_tree_generation; /* future expansion */ __le64 reserved[30]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; } __attribute__ ((__packed__)); #endif /* _GM_BTRFS_H */ gpart-0.3/src/gm_ext2.c000066400000000000000000000075501262504202100147720ustar00rootroot00000000000000/* * gm_ext2.c -- gpart ext2 guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 30.04.1999 * Added suggestions from Andries.Brouwer@cwi.nl * * 18.06.1999 * Fixed buggy ext2 spare superblock location calculation. * * 29.06.1999 * Made every disk read/write buffer aligned to pagesize. * */ #include #include #include #include "gpart.h" #include "gm_ext2.h" int ext2_init(disk_desc *d,g_module *m) { int bsize = SUPERBLOCK_SIZE; if ((d == 0) || (m == 0)) return (0); /* * the medium sector size must either be a multiple * of the superblock size or vice versa. */ if (((d->d_ssize > bsize) && (d->d_ssize % bsize)) || ((d->d_ssize < bsize) && (bsize % d->d_ssize))) { pr(ERROR,"ext2_init: cannot work on that sector size"); return (0); } m->m_desc = "Linux ext2"; return (SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE); } int ext2_term(disk_desc *d) { return (1); } int ext2_gfun(disk_desc *d,g_module *m) { struct ext2fs_sb *sb, *sparesb; int psize, bsize = 1024; s64_t ls, ofs; dos_part_entry *pt = &m->m_part; byte_t *ubuf, *sbuf; m->m_guess = GM_NO; sb = (struct ext2fs_sb *)(d->d_sbuf + SUPERBLOCK_OFFSET); if (sb->s_magic != le16(EXT2_SUPER_MAGIC)) return (1); /* * first some plausability checks. */ if (sb->s_free_blocks_count >= sb->s_blocks_count) return (1); if (sb->s_free_inodes_count >= sb->s_inodes_count) return (1); if (sb->s_errors && (sb->s_errors != EXT2_ERRORS_CONTINUE) && (sb->s_errors != EXT2_ERRORS_RO) && (sb->s_errors != EXT2_ERRORS_PANIC)) return (1); if (sb->s_state & ~(EXT2_VALID_FS | EXT2_ERROR_FS)) return (1); /* * empty filesystems seem unlikely to me. */ if (sb->s_blocks_count == 0) return (1); /* * yet they also shouldn't be too large. */ if (d->d_nsecs) { ls = sb->s_blocks_count; ls *= bsize; ls /= d->d_ssize; ls += d->d_nsb; if (ls > d->d_nsecs) return (1); } /* * ext2fs supports 1024, 2048 and 4096b blocks. */ switch (sb->s_log_block_size) { case BSIZE_1024 : bsize = 1024; break; case BSIZE_2048 : bsize = 2048; break; case BSIZE_4096 : bsize = 4096; break; default: return (1); } /* * current mount count shouldn't be greater than max+20 * but ext3 usually has s_max_mnt_count==-1 */ if ((sb->s_max_mnt_count!=-1)&&(sb->s_mnt_count > sb->s_max_mnt_count + 20)) return (1); /* * up to here this looks like a valid ext2 sb, now try to read * the first spare super block to be sure. */ if ((ls = l64tell(d->d_fd)) == -1) pr(FATAL,"ext2: cannot seek: %s",strerror(errno)); ls /= d->d_ssize; ls -= d->d_nsb; ls *= d->d_ssize; ofs = sb->s_blocks_per_group + sb->s_first_data_block; ofs *= bsize; if (l64seek(d->d_fd,ofs - ls,SEEK_CUR) == -1) pr(FATAL,"ext2: cannot seek: %s",strerror(errno)); psize = getpagesize(); ubuf = alloc(SUPERBLOCK_SIZE + psize); sbuf = align(ubuf,psize); if (read(d->d_fd,sbuf,SUPERBLOCK_SIZE) != SUPERBLOCK_SIZE) pr(FATAL,"ext2: cannot read spare super block"); sparesb = (struct ext2fs_sb *)sbuf; /* * test only some values of the spare sb. */ if (sparesb->s_magic != le16(EXT2_SUPER_MAGIC)) goto out; if (sparesb->s_log_block_size != sb->s_log_block_size) goto out; /* * seems ok. */ m->m_guess = GM_YES; pt->p_typ = 0x83; pt->p_start = d->d_nsb; pt->p_size = bsize / d->d_ssize; pt->p_size *= sb->s_blocks_count; out: free((void *)ubuf); return (1); } gpart-0.3/src/gm_ext2.h000066400000000000000000000075511262504202100150000ustar00rootroot00000000000000/* * gm_ext2.h -- gpart ext2 guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_EXT2_H #define _GM_EXT2_H /* * Ext2 filesystem structures, taken from the ext2 utilities v1.10. */ /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; /* imported from ext2fs/ext2_fs.h */ #define SUPERBLOCK_OFFSET 1024 #define SUPERBLOCK_SIZE 1024 #define BSIZE_1024 0 #define BSIZE_2048 1 #define BSIZE_4096 2 #define EXT2_LIB_CURRENT_REV 0 #define EXT2_SUPER_MAGIC 0xEF53 #define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ #define EXT2_ERROR_FS 0x0002 /* Errors detected */ #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ #define EXT2_DFL_CHECKINTERVAL 15552000 /* Don't use interval check */ #define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ #define EXT2_ERRORS_RO 2 /* Remount fs read-only */ #define EXT2_ERRORS_PANIC 3 /* Panic */ #define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ struct ext2fs_sb { __u32 s_inodes_count; /* Inodes count */ __u32 s_blocks_count; /* Blocks count */ __u32 s_r_blocks_count; /* Reserved blocks count */ __u32 s_free_blocks_count; /* Free blocks count */ __u32 s_free_inodes_count; /* Free inodes count */ __u32 s_first_data_block; /* First Data Block */ __u32 s_log_block_size; /* Block size */ __s32 s_log_frag_size; /* Fragment size */ __u32 s_blocks_per_group; /* # Blocks per group */ __u32 s_frags_per_group; /* # Fragments per group */ __u32 s_inodes_per_group; /* # Inodes per group */ __u32 s_mtime; /* Mount time */ __u32 s_wtime; /* Write time */ __u16 s_mnt_count; /* Mount count */ __s16 s_max_mnt_count; /* Maximal mount count */ __u16 s_magic; /* Magic signature */ __u16 s_state; /* File system state */ __u16 s_errors; /* Behaviour when detecting errors */ __u16 s_minor_rev_level; /* minor revision level */ __u32 s_lastcheck; /* time of last check */ __u32 s_checkinterval; /* max. time between checks */ __u32 s_creator_os; /* OS */ __u32 s_rev_level; /* Revision level */ __u16 s_def_resuid; /* Default uid for reserved blocks */ __u16 s_def_resgid; /* Default gid for reserved blocks */ /* * These fields are for EXT2_DYNAMIC_REV superblocks only. * * Note: the difference between the compatible feature set and * the incompatible feature set is that if there is a bit set * in the incompatible feature set that the kernel doesn't * know about, it should refuse to mount the filesystem. * * e2fsck's requirements are more strict; if it doesn't know * about a feature in either the compatible or incompatible * feature set, it must abort and not try to meddle with * things it doesn't understand... */ __u32 s_first_ino; /* First non-reserved inode */ __u16 s_inode_size; /* size of inode structure */ __u16 s_block_group_nr; /* block group # of this superblock */ __u32 s_feature_compat; /* compatible feature set */ __u32 s_feature_incompat; /* incompatible feature set */ __u32 s_feature_ro_compat; /* readonly-compatible feature set */ __u8 s_uuid[16]; /* 128-bit uuid for volume */ char s_volume_name[16]; /* volume name */ char s_last_mounted[64]; /* directory where last mounted */ __u32 s_reserved[206]; /* Padding to the end of the block */ }; #endif /* _GM_EXT2_H */ gpart-0.3/src/gm_fat.c000066400000000000000000000042611262504202100146560ustar00rootroot00000000000000/* * gm_fat.c -- gpart fat guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include "gpart.h" #include "gm_fat.h" int fat_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "DOS FAT"; m->m_align = 'h'; return (sizeof(struct fat_boot_sector)); } int fat_term(disk_desc *d) { return (1); } int fat_gfun(disk_desc *d,g_module *m) { struct fat_boot_sector *sb = (struct fat_boot_sector *)d->d_sbuf; dos_part_entry *pt = &m->m_part; unsigned long nsecs = 0; unsigned char ig1, ig2, media; int sectsize, fat32 = 0, fat12 = 0; s64_t size = 0; m->m_guess = GM_NO; ig1 = sb->ignored[0]; ig2 = sb->ignored[2]; media = sb->media; if ((ig1 == 0xeb) && (ig2 == 0x90) && ((media == 0xf8) || (media == 0xfc))) { if (*((unsigned short *)d->d_sbuf + 255) != le16(DOSPTMAGIC)) return (1); /* * looks like a standard FAT boot sector. Now find out, * which one of the numerous versions this could be. */ pt->p_start = d->d_nsb; nsecs = le16(sb->sectors); if (nsecs == 0) nsecs = le32(sb->total_sect); if (nsecs == 0) return (1); sectsize = le16(sb->sector_size); if ((d->d_sbuf[0x39] == '1') && (d->d_sbuf[0x3a] == '2')) fat12 = 1; if (sb->fat_length == 0) fat32 = 1; if (fat32 && (*(d->d_sbuf + 0x26) == 0x29)) return (1); if (!fat32 && (*(d->d_sbuf + 0x26) != 0x29)) return (1); if (fat12 && fat32) return (1); m->m_guess = GM_YES; /* * what happens when the fat sectsize != medium sectsize? * I don't know. I just say no now. */ if (sectsize != d->d_ssize) m->m_guess = GM_NO; size = nsecs; size *= sectsize; size /= 1024; if (size >= 32768) { pt->p_typ = 0x06; if (fat32) pt->p_typ = d->d_lba ? 0x0C : 0x0B; } else pt->p_typ = fat12 ? 0x01 : 0x04; pt->p_size = nsecs; } return (1); } gpart-0.3/src/gm_fat.h000066400000000000000000000041571262504202100146670ustar00rootroot00000000000000/* * gm_fat.h -- gpart fat guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_FAT_H #define _GM_FAT_H /* * FAT partition boot sector information, taken from the Linux * kernel sources. */ /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; struct fat_boot_sector { __s8 ignored[3]; /* Boot strap short or near jump */ __s8 system_id[8]; /* Name - can be used to special case partition manager volumes */ __u16 sector_size; /* bytes per logical sector */ __u8 cluster_size; /* sectors/cluster */ __u16 reserved; /* reserved sectors */ __u8 fats; /* number of FATs */ __u8 dir_entries[2]; /* root directory entries */ __u16 sectors; /* number of sectors */ __u8 media; /* media code (unused) */ __u16 fat_length; /* sectors/FAT */ __u16 secs_track; /* sectors per track */ __u16 heads; /* number of heads */ __u32 hidden; /* hidden sectors (unused) */ __u32 total_sect; /* number of sectors (if sectors == 0) */ /* The following fields are only used by FAT32 */ __u32 fat32_length; /* sectors/FAT */ __u16 flags; /* bit 8: fat mirroring, low 4: active fat */ __u8 version[2]; /* major, minor filesystem version */ __u32 root_cluster; /* first cluster in root directory */ __u16 info_sector; /* filesystem info sector */ __u16 backup_boot; /* backup boot sector */ __u16 reserved2[6]; /* Unused */ } __attribute__ ((packed)); /* "__attribute__ ((packed))" added by davidc@debian.org, as suggested by falk@zxmjz18.extern.uni-tuebingen.de Fri Jul 07 18:04:15 2000 in debian bug report #66893 "FAT detection broken on Alpha" */ #endif /* _GM_FAT_H */ gpart-0.3/src/gm_hmlvm.c000066400000000000000000000040371262504202100152300ustar00rootroot00000000000000/* * gm_hmlvm.c -- gpart Linux LVM physical volume guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 29.08.1999 * Modified: 29.01.2001 * Minor update to LVM 0.9. * */ #include #include #include "gpart.h" #include "gm_hmlvm.h" int hmlvm_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Linux LVM physical volume"; return (LVM_PV_DISK_BASE + LVM_PV_DISK_SIZE); } int hmlvm_term(disk_desc *d) { return (1); } int hmlvm_gfun(disk_desc *d,g_module *m) { pv_disk_t *pv; dos_part_entry *pt = &m->m_part; unsigned int size; s64_t s; m->m_guess = GM_NO; pv = (pv_disk_t *)&d->d_sbuf[LVM_PV_DISK_BASE]; if ((strncmp((char *)pv->id,LVM_ID,sizeof(pv->id)) == 0) && ((pv->version == 1) || (pv->version == 2))) { /* * looks like a physical volume header. Do the usual * consistency checks. */ if (pv->pv_size > LVM_MAX_SIZE) return (1); if ((pv->pv_status != 0) && (pv->pv_status != PV_ACTIVE)) return (1); if ((pv->pv_allocatable != 0) && (pv->pv_allocatable != PV_ALLOCATABLE)) return (1); if (pv->lv_cur > MAX_LV) return (1); if (strlen((char *)pv->vg_name) > NAME_LEN / 2) return (1); size = pv->pe_size / LVM_MIN_PE_SIZE * LVM_MIN_PE_SIZE; if ((pv->pe_size != size) || (pv->pe_size < LVM_MIN_PE_SIZE) || (pv->pe_size > LVM_MAX_PE_SIZE)) return (1); if (pv->pe_total > ( pv->pe_on_disk.size / sizeof ( disk_pe_t))) return (1); if (pv->pe_allocated > pv->pe_total) return (1); /* * Ok. */ m->m_guess = GM_YES; pt->p_start = d->d_nsb; s = pv->pv_size; s *= 512; s /= d->d_ssize; pt->p_size = s; pt->p_typ = 0x8E; } return (1); } gpart-0.3/src/gm_hmlvm.h000066400000000000000000000042461262504202100152370ustar00rootroot00000000000000/* * gm_hmlvm.h -- gpart Linux LVM physical volume guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 29.08.1999 * Modified: * */ #ifndef _GM_HMLVM_H #define _GM_HMLVM_H /* * structs & defines gathered from LVM 0.7/0.9 lvm.h and liblvm.h */ #if !defined(__FreeBSD__) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #endif /* * Status flags */ /* physical volume */ #define PV_ACTIVE 0x01 /* pv_status */ #define PV_ALLOCATABLE 0x02 /* pv_allocatable */ #define LVM_PV_DISK_BASE 0L #define LVM_PV_DISK_SIZE 1024L #define NAME_LEN 128 /* don't change!!! */ #define UUID_LEN 16 /* don't change!!! */ #define LVM_MAX_SIZE ( 1024LU * 1024 * 1024 * 2) /* 1TB[sectors] */ #define LVM_ID "HM" #define LVM_DIR_PREFIX "/dev/" #define MAX_LV 256 #define LVM_MIN_PE_SIZE ( 8L * 2) /* 8 KB in sectors */ #define LVM_MAX_PE_SIZE ( 16L * 1024L * 1024L * 2) /* 16GB in sectors */ /* disk stored pe information */ typedef struct { uint16_t lv_num; uint16_t le_num; } disk_pe_t; /* disk stored PV, VG, LV and PE size and offset information */ typedef struct { uint32_t base; uint32_t size; } lvm_disk_data_t; /* * Structure Physical Volume (PV) Version 2 */ /* disk */ typedef struct { uint8_t id[2]; /* Identifier */ uint16_t version; /* HM lvm version */ lvm_disk_data_t pv_on_disk; lvm_disk_data_t vg_on_disk; lvm_disk_data_t pv_uuidlist_on_disk; lvm_disk_data_t lv_on_disk; lvm_disk_data_t pe_on_disk; uint8_t pv_uuid[NAME_LEN]; uint8_t vg_name[NAME_LEN]; uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ uint32_t pv_major; uint32_t pv_number; uint32_t pv_status; uint32_t pv_allocatable; uint32_t pv_size; /* HM */ uint32_t lv_cur; uint32_t pe_size; uint32_t pe_total; uint32_t pe_allocated; } pv_disk_v2_t; #define pv_disk_t pv_disk_v2_t #endif /* _GM_HMLVM_H */ gpart-0.3/src/gm_hpfs.c000066400000000000000000000041321262504202100150410ustar00rootroot00000000000000/* * gm_hpfs.c -- gpart hpfs guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 29.06.1999 * Made every disk read/write buffer aligned to pagesize. * * */ #include #include #include #include "gpart.h" #include "gm_hpfs.h" #define OS2SECTSIZE 512 int hpfs_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "OS/2 HPFS"; return (OS2SECTSIZE); } int hpfs_term(disk_desc *d) { return (1); } int hpfs_gfun(disk_desc *d,g_module *m) { struct hpfs_boot_block *bb = (struct hpfs_boot_block *)d->d_sbuf; struct hpfs_super_block *sb; s64_t s; size_t psize; byte_t *ubuf, *sbuf; m->m_guess = GM_NO; if ( (bb->sig_28h == 0x28) && (strncmp((char *)bb->sig_hpfs,"HPFS ",8) == 0) && (bb->magic == le16(0xaa55)) && (bb->bytes_per_sector == le16(OS2SECTSIZE))) { /* * looks like a hpfs boot sector. Test hpfs superblock * at sector offset 16 (from start of partition). */ if ((s = l64tell(d->d_fd)) == -1) pr(FATAL,"hpfs: cannot seek: %s",strerror(errno)); s /= d->d_ssize; s -= d->d_nsb; s *= d->d_ssize; if (l64seek(d->d_fd,16 * OS2SECTSIZE - s,SEEK_CUR) == -1) pr(FATAL,"hpfs: cannot seek: %s",strerror(errno)); psize = getpagesize(); ubuf = alloc(OS2SECTSIZE + psize); sbuf = align(ubuf,psize); if (read(d->d_fd,sbuf,OS2SECTSIZE) != OS2SECTSIZE) pr(FATAL,"hpfs: cannot read super block"); sb = (struct hpfs_super_block *)sbuf; if (sb->magic != le32(SB_MAGIC)) goto out; /* * ok, fill in sizes. */ s = sb->n_sectors; s *= OS2SECTSIZE; s /= d->d_ssize; m->m_part.p_start = d->d_nsb; m->m_part.p_size = s; m->m_guess = GM_YES; out: free((void *)ubuf); } return (1); } gpart-0.3/src/gm_hpfs.h000066400000000000000000000054461262504202100150570ustar00rootroot00000000000000/* * gm_hpfs.h -- gpart hpfs guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_HPFS_H #define _GM_HPFS_H /* * hpfs information/macros, taken from the Linux kernel sources. */ /* Notation */ typedef unsigned secno; /* sector number, partition relative */ typedef secno dnode_secno; /* sector number of a dnode */ typedef secno fnode_secno; /* sector number of an fnode */ typedef secno anode_secno; /* sector number of an anode */ /* sector 0 */ /* The boot block is very like a FAT boot block, except that the 29h signature byte is 28h instead, and the ID string is "HPFS". */ struct hpfs_boot_block { unsigned char jmp[3]; unsigned char oem_id[8]; unsigned short bytes_per_sector; /* 512 */ unsigned char sectors_per_cluster; unsigned char n_reserved_sectors[2]; unsigned char n_fats; unsigned char n_rootdir_entries[2]; unsigned char n_sectors_s[2]; unsigned char media_byte; unsigned short sectors_per_fat; unsigned short sectors_per_track; unsigned short heads_per_cyl; unsigned int n_hidden_sectors; unsigned int n_sectors_l; /* size of partition */ unsigned char drive_number; unsigned char mbz; unsigned char sig_28h; /* 28h */ unsigned char vol_serno[4]; unsigned char vol_label[11]; unsigned char sig_hpfs[8]; /* "HPFS " */ unsigned char pad[448]; unsigned short magic; /* aa55 */ }; /* sector 16 */ /* The super block has the pointer to the root directory. */ #define SB_MAGIC 0xf995e849 struct hpfs_super_block { unsigned magic; /* f995 e849 */ unsigned magic1; /* fa53 e9c5, more magic? */ unsigned huh202; /* ?? 202 = N. of B. in 1.00390625 S.*/ fnode_secno root; /* fnode of root directory */ secno n_sectors; /* size of filesystem */ unsigned n_badblocks; /* number of bad blocks */ secno bitmaps; /* pointers to free space bit maps */ unsigned zero1; /* 0 */ secno badblocks; /* bad block list */ unsigned zero3; /* 0 */ time_t last_chkdsk; /* date last checked, 0 if never */ unsigned zero4; /* 0 */ secno n_dir_band; /* number of sectors in dir band */ secno dir_band_start; /* first sector in dir band */ secno dir_band_end; /* last sector in dir band */ secno dir_band_bitmap; /* free space map, 1 dnode per bit */ unsigned zero5[8]; /* 0 */ secno scratch_dnodes; /* ?? 8 preallocated sectors near dir band, 4-aligned. */ unsigned zero6[103]; /* 0 */ }; #endif /* _GM_HPFS_H */ gpart-0.3/src/gm_lswap.c000066400000000000000000000044161262504202100152340ustar00rootroot00000000000000/* * gm_lswap.c -- gpart linux swap guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 22.01.1999 * Calculation of old swap-partition was wrong. * */ #include #include "gpart.h" static char *sigs[] = { "SWAP-SPACE", "SWAPSPACE2" }; static int pszs[] = { 4096, 8192 }; static int siglen = 10; int lswap_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Linux swap"; /* * return the max. pagesize of platforms running Linux. * Seems to be 8k (Alpha). */ return (8192); } int lswap_term(disk_desc *d) { return (1); } int lswap_gfun(disk_desc *d,g_module *m) { char *sig = 0; int i, j, pagesize, vers; byte_t *p, b; s64_t np = 0; dos_part_entry *pt = &m->m_part; m->m_guess = GM_NO; pagesize = vers = 0; for (i = 0; (pagesize == 0) && (i < sizeof(sigs)/sizeof(char *)); i++) for (j = 0; j < sizeof(pszs)/sizeof(int); j++) { sig = (char *)(d->d_sbuf + pszs[j] - siglen); if (strncmp(sig,sigs[i],siglen) == 0) { pagesize = pszs[j]; vers = i; break; } } if (pagesize == 0) return (1); if (vers == 0) /* old (<128mb) style swap */ { if (*d->d_sbuf != 0xFE) return (1); for (p = (byte_t *)(sig - 1); p >= d->d_sbuf; p--) if (*p) break; np = (p - d->d_sbuf) * 8; for (b = *p; (b & 0x01) == 1; b >>= 1) np++; } else if (vers == 1) /* Linux > 2.2.X swap partitions */ { struct swapinfo { char bootbits[1024]; unsigned int version; unsigned int last_page; unsigned int nr_badpages; unsigned int padding[125]; unsigned int badpages[1]; } *info = (struct swapinfo *)d->d_sbuf; if (info->version != 1) return (1); np = 1 + info->last_page; } else return (1); if (np >= 10) /* mkswap(8) says this */ { np *= pagesize; np /= d->d_ssize; m->m_guess = GM_YES; pt->p_typ = 0x82; pt->p_start = d->d_nsb; pt->p_size = np; } return (1); } gpart-0.3/src/gm_lvm2.c000066400000000000000000000026131262504202100147630ustar00rootroot00000000000000/* * gm_lvm2.c -- gpart Linux LVM2 physical volume guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 20.11.2015 * */ #include #include #include "gpart.h" #include "gm_lvm2.h" int lvm2_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Linux LVM2 physical volume"; return SECTOR_SIZE + LABEL_SIZE; } int lvm2_term(disk_desc *d) { return (1); } int lvm2_gfun(disk_desc *d,g_module *m) { struct label_header *lh; struct pv_header *pvh; dos_part_entry *pt = &m->m_part; s64_t pv_size; byte_t *p = d->d_sbuf + SECTOR_SIZE; m->m_guess = GM_NO; lh = (struct label_header*)p; if (strncmp((char*)lh->id, LABEL_ID, sizeof(lh->id)) || strncmp((char*)lh->type, LVM2_LABEL, sizeof(lh->type))) return 1; pvh = (struct pv_header*) ((char*)lh + le32toh(lh->offset_xl)); pv_size = le64toh(pvh->device_size_xl); pv_size /= d->d_ssize; if (d->d_nsecs != 0 && pv_size > d->d_nsecs - d->d_nsb) return 1; m->m_guess = GM_YES; pt->p_start = d->d_nsb; pt->p_size = pv_size; pt->p_typ = 0x8E; return 1; } gpart-0.3/src/gm_lvm2.h000066400000000000000000000034171262504202100147730ustar00rootroot00000000000000/* * gm_lvm2.h -- gpart Linux LVM physical volume guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 19.11.2015 * Modified: * */ #ifndef _GM_LVM2_H #define _GM_LVM2_H #include /* * structs & defines gathered from LVM2 */ #if !defined(__FreeBSD__) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #endif #define ID_LEN 32 #define SECTOR_SHIFT 9 #define SECTOR_SIZE (1 << SECTOR_SHIFT) #define LABEL_ID "LABELONE" #define LABEL_SIZE SECTOR_SIZE #define LABEL_SCAN_SECTORS 4L #define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT) #define LVM2_LABEL "LVM2 001" /* On disk - 32 bytes */ struct label_header { int8_t id[8]; /* LABELONE */ uint64_t sector_xl; /* Sector number of this label */ uint32_t crc_xl; /* From next field to end of sector */ uint32_t offset_xl; /* Offset from start of struct to contents */ int8_t type[8]; /* LVM2 001 */ } __attribute__ ((packed)); struct disk_locn { uint64_t offset; /* Offset in bytes to start sector */ uint64_t size; /* Bytes */ } __attribute__ ((packed)); struct pv_header { int8_t pv_uuid[ID_LEN]; /* This size can be overridden if PV belongs to a VG */ uint64_t device_size_xl; /* Bytes */ /* NULL-terminated list of data areas followed by */ /* NULL-terminated list of metadata area headers */ struct disk_locn disk_areas_xl[0]; /* Two lists */ } __attribute__ ((packed)); #endif /* _GM_LVM2_H */ gpart-0.3/src/gm_minix.c000066400000000000000000000035121262504202100152260ustar00rootroot00000000000000/* * gm_minix.c -- gpart minix guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include "gpart.h" #include "gm_minix.h" int minix_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Minix filesystem"; return (2 * BLOCK_SIZE); } int minix_term(disk_desc *d) { return (1); } int minix_gfun(disk_desc *d,g_module *m) { long version = 0; struct minix_super_block *ms; byte_t *p; unsigned long zones, size; ms = (struct minix_super_block *)(d->d_sbuf + BLOCK_SIZE); m->m_guess = GM_NO; if (ms->s_magic == le16(MINIX_SUPER_MAGIC)) version = MINIX_V1; if (ms->s_magic == le16(MINIX_SUPER_MAGIC2)) version = MINIX_V1; if (ms->s_magic == le16(MINIX2_SUPER_MAGIC)) version = MINIX_V2; if (ms->s_magic == le16(MINIX2_SUPER_MAGIC2)) version = MINIX_V2; if (version == 0) return (1); if ((ms->s_state != MINIX_VALID_FS) && (ms->s_state != MINIX_ERROR_FS)) return (1); /* * the rest of the disk block where the superblock * was found should be zeroed out. */ for (p = d->d_sbuf + BLOCK_SIZE + sizeof(struct minix_super_block); p < d->d_sbuf + 2 * BLOCK_SIZE; p++) if (*p) return (1); zones = (version == MINIX_V2) ? ms->s_zones : ms->s_nzones; size = zones << ms->s_log_zone_size; size *= BLOCK_SIZE; m->m_guess = GM_YES; m->m_part.p_typ = (version == MINIX_V2) ? 0x81 : 0x80; m->m_part.p_start = d->d_nsb; m->m_part.p_size = size / d->d_ssize; return (1); } gpart-0.3/src/gm_minix.h000066400000000000000000000051011262504202100152270ustar00rootroot00000000000000/* * gm_minix.h -- gpart minix guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_MINIX_H #define _GM_MINIX_H /* * Minix filesystem structures, taken from the Linux kernel. */ /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; #define BLOCK_SIZE 1024 #define MINIX_ROOT_INO 1 /* Not the same as the bogus LINK_MAX in . Oh well. */ #define MINIX_LINK_MAX 250 #define MINIX2_LINK_MAX 65530 #define MINIX_I_MAP_SLOTS 8 #define MINIX_Z_MAP_SLOTS 64 #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ #define MINIX_VALID_FS 0x0001 /* Clean fs. */ #define MINIX_ERROR_FS 0x0002 /* fs has errors. */ #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) #define MINIX_V1 0x0001 /* original minix fs */ #define MINIX_V2 0x0002 /* minix V2 fs */ #define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version /* * This is the original minix inode layout on disk. * Note the 8-bit gid and atime and ctime. */ struct minix_inode { __u16 i_mode; __u16 i_uid; __u32 i_size; __u32 i_time; __u8 i_gid; __u8 i_nlinks; __u16 i_zone[9]; }; /* * The new minix inode has all the time entries, as well as * long block numbers and a third indirect block (7+1+1+1 * instead of 7+1+1). Also, some previously 8-bit values are * now 16-bit. The inode is now 64 bytes instead of 32. */ struct minix2_inode { __u16 i_mode; __u16 i_nlinks; __u16 i_uid; __u16 i_gid; __u32 i_size; __u32 i_atime; __u32 i_mtime; __u32 i_ctime; __u32 i_zone[10]; }; /* * minix super-block data on disk */ struct minix_super_block { __u16 s_ninodes; __u16 s_nzones; __u16 s_imap_blocks; __u16 s_zmap_blocks; __u16 s_firstdatazone; __u16 s_log_zone_size; __u32 s_max_size; __u16 s_magic; __u16 s_state; __u32 s_zones; }; #endif /* _GM_MINIX_H */ gpart-0.3/src/gm_ntfs.c000066400000000000000000000042511262504202100150550ustar00rootroot00000000000000/* * gm_ntfs.c -- gpart ntfs guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 26.02.2000 * Length of guessed partition incremented to include NT4 backup * boot sector. * */ #include #include #include "gpart.h" #include "gm_ntfs.h" #define NTFS_SECTSIZE 512 int ntfs_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Windows NT/W2K FS"; m->m_hasptbl = 1; return (NTFS_SECTSIZE); /* The ntfs driver in Linux just assumes so */ } int ntfs_term(disk_desc *d) { return (1); } int ntfs_gfun(disk_desc *d,g_module *m) { int mft_clusters_per_record; s64_t size, ls; byte_t *ubuf, *sbuf; m->m_guess = GM_NO; if (IS_NTFS_VOLUME(d->d_sbuf)) { /* * ntfs detection is quite weak, should come before * fat or hpfs. */ if (NTFS_GETU32(d->d_sbuf + 0x40) > 256UL) return (1); if (NTFS_GETU32(d->d_sbuf + 0x44) > 256UL) return (1); mft_clusters_per_record = NTFS_GETS8(d->d_sbuf + 0x40); if ((mft_clusters_per_record < 0) && (mft_clusters_per_record != -10)) return (1); size = NTFS_GETU64(d->d_sbuf + 0x28); /* * look for an additional backup boot sector at the end of * this FS (NT4 puts this backup sector after the FS, this * sector must be counted). */ ls = d->d_nsb + size; ls *= d->d_ssize; if (l64seek(d->d_fd,ls,SEEK_SET) >= 0) { ubuf = alloc(NTFS_SECTSIZE + getpagesize()); sbuf = align(ubuf,getpagesize()); if (read(d->d_fd,sbuf,NTFS_SECTSIZE) != NTFS_SECTSIZE) pr(FATAL,"ntfs: cannot read backup boot sector"); if (memcmp(d->d_sbuf,sbuf,NTFS_SECTSIZE) == 0) size += 1; free((void *)ubuf); } m->m_part.p_start = d->d_nsb; m->m_part.p_size = (unsigned long)size; m->m_part.p_typ = 0x07; m->m_guess = GM_YES; } return (1); } gpart-0.3/src/gm_ntfs.h000066400000000000000000000035711262504202100150660ustar00rootroot00000000000000/* * gm_ntfs.h -- gpart ntfs guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include #include #ifndef _GM_NTFS_H #define _GM_NTFS_H /* * ntfs information/macros, taken from the Linux kernel sources. */ #define IS_MAGIC(a,b) (*(int*)(a)==*(int*)(b)) #define IS_MFT_RECORD(a) IS_MAGIC((a),"FILE") #define IS_NTFS_VOLUME(a) IS_MAGIC((a)+3,"NTFS") #define IS_INDEX_RECORD(a) IS_MAGIC((a),"INDX") /* 'NTFS' in little endian */ #define NTFS_SUPER_MAGIC 0x5346544E /* unsigned integral types */ #ifndef NTFS_INTEGRAL_TYPES #define NTFS_INTEGRAL_TYPES typedef uint8_t ntfs_u8; typedef uint16_t ntfs_u16; typedef uint32_t ntfs_u32; typedef uint64_t ntfs_u64; typedef int8_t ntfs_s8; typedef int16_t ntfs_s16; #endif /* NTFS_INTEGRAL_TYPES */ /* Macros reading unsigned integers from a byte pointer */ #define NTFS_GETU8(p) (*(ntfs_u8*)(p)) #define NTFS_GETU16(p) ((ntfs_u16)htole16(*(ntfs_u16*)(p))) #define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | \ ((ntfs_u32)NTFS_GETU8(((char*)p)+2))<<16) #define NTFS_GETU32(p) ((ntfs_u32)htole32(*(ntfs_u32*)(p))) #define NTFS_GETU64(p) ((ntfs_u64)htole64(*(ntfs_u64*)(p))) /* Macros reading signed integers, returning int */ #define NTFS_GETS8(p) (*(ntfs_s8*)(p)) #define NTFS_GETS16(p) ((ntfs_s16)htole16(*(ntfs_s16*)(p))) #define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? \ (int)NTFS_GETU24(p) : \ (int)(NTFS_GETU24(p) - 0x1000000)) #endif /* _GM_NTFS_H */ gpart-0.3/src/gm_qnx4.c000066400000000000000000000047551262504202100150060ustar00rootroot00000000000000/* * gm_qnx4.c -- gpart qnx4 guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.2001 * Modified: * */ #include #include #include #include "gpart.h" #include "gm_qnx4.h" #include int qnx4_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "QNX4 filesystem"; m->m_notinext = 1; return (2 * QNX4_BLOCK_SIZE); } int qnx4_term(disk_desc *d) { return (1); } int qnx4_gfun(disk_desc *d,g_module *m) { struct qnx4_super_block *sb; struct qnx4_inode_entry *rootdir, bitmap; int rd, rl, i, j, psize, found; s64_t ls, ofs, size; byte_t *ubuf, *sbuf; m->m_guess = GM_NO; /* * check QNX signature */ if (memcmp(d->d_sbuf + 4,QNX4_BOOTSECT_SIG,strlen(QNX4_BOOTSECT_SIG))) return (1); sb = (struct qnx4_super_block *)(d->d_sbuf + QNX4_BLOCK_SIZE); if (*sb->RootDir.di_fname != '/') return (1); /* * read root directory */ psize = getpagesize(); ubuf = alloc(QNX4_BLOCK_SIZE + psize); sbuf = align(ubuf,psize); found = 0; rd = le32(sb->RootDir.di_first_xtnt.xtnt_blk) - 1; rl = le32(sb->RootDir.di_first_xtnt.xtnt_size); for (j = 0; j < rl; j++) { if ((ls = l64tell(d->d_fd)) == -1) pr(FATAL,"qnx4: cannot seek: %s",strerror(errno)); ls /= d->d_ssize; ls -= d->d_nsb; ls *= d->d_ssize; ofs = rd + j; ofs *= QNX4_BLOCK_SIZE; if (l64seek(d->d_fd,ofs - ls,SEEK_CUR) == -1) pr(FATAL,"qnx4: cannot seek: %s",strerror(errno)); if (read(d->d_fd,sbuf,QNX4_BLOCK_SIZE) != QNX4_BLOCK_SIZE) pr(FATAL,"qnx4: cannot read root dir entry"); /* * find the ".bitmap" entry */ for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { rootdir = (struct qnx4_inode_entry *) (sbuf + i * QNX4_DIR_ENTRY_SIZE); if (rootdir->di_fname && !strncmp(rootdir->di_fname,QNX4_BITMAP_NAME,strlen(QNX4_BITMAP_NAME))) { memcpy(&bitmap,rootdir,sizeof(struct qnx4_inode_entry)); found = 1; } } } if (! found) return (1); size = le32(bitmap.di_size) * 8 - 6; size *= QNX4_BLOCK_SIZE; size /= d->d_ssize; m->m_guess = GM_YES; m->m_part.p_typ = 0x4F; m->m_part.p_start = d->d_nsb; m->m_part.p_size = size; free((void *)ubuf); return (1); } gpart-0.3/src/gm_qnx4.h000066400000000000000000000040701262504202100150010ustar00rootroot00000000000000/* * gm_qnx4.h -- gpart qnx4 guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.2001 * Modified: * */ #ifndef _GM_QNX4_H #define _GM_QNX4_H /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; #define QNX4_BOOTSECT_SIG "QNX4FS" #define QNX4_BITMAP_NAME ".bitmap" /* * QNX4 filesystem structures, taken from the Linux kernel. */ #define QNX4_VALID_FS 0x0001 /* Clean fs. */ #define QNX4_ERROR_FS 0x0002 /* fs has errors. */ #define QNX4_BLOCK_SIZE 0x200 /* blocksize of 512 bytes */ #define QNX4_INODES_PER_BLOCK 0x08 /* 512 / 64 */ #define QNX4_DIR_ENTRY_SIZE 0x040 /* dir entry size of 64 bytes */ /* for filenames */ #define QNX4_SHORT_NAME_MAX 16 #define QNX4_NAME_MAX 48 typedef __u16 qnx4_nxtnt_t; typedef __u8 qnx4_ftype_t; typedef struct { __u32 xtnt_blk; __u32 xtnt_size; } qnx4_xtnt_t; typedef __u16 qnx4_mode_t; typedef __u16 qnx4_muid_t; typedef __u16 qnx4_mgid_t; typedef __u32 qnx4_off_t; typedef __u16 qnx4_nlink_t; /* * This is the original qnx4 inode layout on disk. */ struct qnx4_inode_entry { char di_fname[QNX4_SHORT_NAME_MAX]; qnx4_off_t di_size; qnx4_xtnt_t di_first_xtnt; __u32 di_xblk; __s32 di_ftime; __s32 di_mtime; __s32 di_atime; __s32 di_ctime; qnx4_nxtnt_t di_num_xtnts; qnx4_mode_t di_mode; qnx4_muid_t di_uid; qnx4_mgid_t di_gid; qnx4_nlink_t di_nlink; __u8 di_zero[4]; qnx4_ftype_t di_type; __u8 di_status; }; struct qnx4_super_block { struct qnx4_inode_entry RootDir; struct qnx4_inode_entry Inode; struct qnx4_inode_entry Boot; struct qnx4_inode_entry AltBoot; }; #endif /* _GM_QNX4_H */ gpart-0.3/src/gm_reiserfs.c000066400000000000000000000037571262504202100157370ustar00rootroot00000000000000/* * gm_reiserfs.c -- gpart ReiserFS guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 21.01.1999 * Modified: 26.12.2000 Francis Devereux * Added reiserfs 3.5.28 support. * Modified: 10.01.2003 Yury Umanets * Added reiserfs 3.6.x support. * */ #include #include #include "gpart.h" #include "gm_reiserfs.h" int reiserfs_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "ReiserFS filesystem"; return (REISERFS_FIRST_BLOCK * 1024 + SB_V35_SIZE); } int reiserfs_term(disk_desc *d) { return (1); } int reiserfs_gfun(disk_desc *d,g_module *m) { struct reiserfs_super_block_v35 *sb; dos_part_entry *pt = &m->m_part; s64_t size; m->m_guess = GM_NO; sb = (struct reiserfs_super_block_v35 *)(d->d_sbuf + REISERFS_FIRST_BLOCK * 1024); if (strncmp(sb->s_magic,REISERFS_SUPER_V35_MAGIC,12) == 0 || strncmp(sb->s_magic,REISERFS_SUPER_V36_MAGIC,12) == 0) { /* * sanity checks. */ if (sb->s_block_count < sb->s_free_blocks) return (1); if (sb->s_block_count < REISERFS_MIN_BLOCK_AMOUNT) return (1); if ((sb->s_state != REISERFS_VALID_FS) && (sb->s_state != REISERFS_ERROR_FS)) return (1); if (sb->s_oid_maxsize % 2) /* must be even */ return (1); if (sb->s_oid_maxsize < sb->s_oid_cursize) return (1); if ((sb->s_blocksize != 4096) && (sb->s_blocksize != 8192)) return (1); /* * ok. */ m->m_guess = GM_YES; pt->p_start = d->d_nsb; size = sb->s_block_count; size *= sb->s_blocksize; size /= d->d_ssize; pt->p_size = (unsigned long)size; pt->p_typ = 0x83; } return (1); } gpart-0.3/src/gm_reiserfs.h000066400000000000000000000056321262504202100157360ustar00rootroot00000000000000/* * gm_reiserfs.h -- gpart ReiserFS guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 21.01.1999 * Modified: 26.12.2000 Francis Devereux * Update support reiserfs version 3.5.28 * Modified: 10.01.2003 Yury Umanets * Added reiserfs 3.6.x support. * */ #ifndef _GM_reiserfs_H #define _GM_reiserfs_H /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; /* * taken from ReiserFS v3.5.28, v3.6.x. Reiserfs Copyright 1996-2000 Hans Reiser */ #define REISERFS_SUPER_V35_MAGIC "ReIsErFs" #define REISERFS_SUPER_V36_MAGIC "ReIsEr2Fs" #define REISERFS_FIRST_BLOCK 64 #define REISERFS_VALID_FS 1 #define REISERFS_ERROR_FS 2 #define REISERFS_MIN_BLOCK_AMOUNT 100 struct reiserfs_super_block_v35 { __u32 s_block_count; /* blocks count */ __u32 s_free_blocks; /* free blocks count */ __u32 s_root_block; /* root block number */ __u32 s_journal_block; /* journal block number */ __u32 s_journal_dev; /* journal device number */ __u32 s_orig_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ __u32 s_journal_trans_max; /* max number of blocks in a transaction. */ __u32 s_journal_block_count; /* total size of the journal. can change over time */ __u32 s_journal_max_batch; /* max number of blocks to batch into a trans */ __u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */ __u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */ __u16 s_blocksize; /* block size */ __u16 s_oid_maxsize; /* max size of object id array, see get_objectid() commentary */ __u16 s_oid_cursize; /* current size of object id array */ __u16 s_state; /* valid or error */ char s_magic[12]; /* reiserfs magic string indicates that file system is reiserfs */ __u32 s_hash_function_code; /* indicate, what hash fuction is being use to sort names in a directory*/ __u16 s_tree_height; /* height of disk tree */ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ __u16 s_reserved; }; #define SB_V35_SIZE (sizeof(struct reiserfs_super_block_v35)) struct reiserfs_super_block_v36 { struct reiserfs_super_block_v35 s_v35; __u32 s_inode_generation; __u32 s_flags; char s_uuid[16]; char s_label[16]; char s_unused[88]; }; #define SB_V36_SIZE (sizeof(struct reiserfs_super_block_v36)) #endif /* _GM_REISERFS_H */ gpart-0.3/src/gm_s86dl.c000066400000000000000000000042171262504202100150450ustar00rootroot00000000000000/* * gm_s86dl.c -- gpart solaris/x86 disklabel guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include "gpart.h" #include "gm_s86dl.h" int s86dl_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "Solaris/x86 disklabel"; m->m_notinext = 1; return (512 + sizeof(struct solaris_x86_vtoc)); } int s86dl_term(disk_desc *d) { return (1); } int s86dl_gfun(disk_desc *d,g_module *m) { struct solaris_x86_vtoc *svtoc; struct solaris_x86_slice *ws = 0, *rs = 0; int i; m->m_guess = GM_NO; svtoc = (struct solaris_x86_vtoc *)(d->d_sbuf + 512); if ((svtoc->v_sanity != SOLARIS_X86_VTOC_SANE) || (svtoc->v_version != SOLARIS_X86_V_VERSION)) return (1); for (i = 0; i < SOLARIS_X86_NUMSLICE; i++) switch (svtoc->v_slice[i].s_tag) { case SOLARIS_X86_V_ROOT : rs = &svtoc->v_slice[i]; break; case SOLARIS_X86_V_BACKUP : ws = &svtoc->v_slice[i]; break; } /* * some simple sanity checks. */ if ((ws == 0) || (rs == 0)) return (1); if (svtoc->v_sectorsz != d->d_ssize) return (1); if (d->d_nsb + ws->s_start + ws->s_size > d->d_nsecs) return (1); if (d->d_nsb + rs->s_start + rs->s_size > d->d_nsecs) return (1); if ((rs->s_start < ws->s_start) || (rs->s_size > ws->s_size)) return (1); if (ws->s_flag && (ws->s_flag != SOLARIS_X86_V_UNMNT) && (ws->s_flag != SOLARIS_X86_V_RONLY)) return (1); if (rs->s_flag && (rs->s_flag != SOLARIS_X86_V_UNMNT) && (rs->s_flag != SOLARIS_X86_V_RONLY)) return (1); /* * If the recognition of the solaris vtoc isn't * enough, I'll have to read a ufs sb, but for * now the vtoc must suffice. */ m->m_part.p_typ = 0x82; m->m_part.p_start = d->d_nsb + le32(ws->s_start); m->m_part.p_size = le32(ws->s_size); m->m_guess = GM_YES; return (1); } gpart-0.3/src/gm_s86dl.h000066400000000000000000000042331262504202100150500ustar00rootroot00000000000000/* * gm_s86dl.h -- gpart solaris/x86 disklabel guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GM_S86DL_H #define _GM_S86DL_H #define SOLARIS_X86_NUMSLICE 8 #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) #define SOLARIS_X86_V_VERSION (0x01) #define SOLARIS_X86_V_UNASSIGNED 0x00 /* unassigned partition */ #define SOLARIS_X86_V_BOOT 0x01 /* Boot partition */ #define SOLARIS_X86_V_ROOT 0x02 /* Root filesystem */ #define SOLARIS_X86_V_SWAP 0x03 /* Swap filesystem */ #define SOLARIS_X86_V_USR 0x04 /* Usr filesystem */ #define SOLARIS_X86_V_BACKUP 0x05 /* full disk */ #define SOLARIS_X86_V_STAND 0x06 /* Stand partition */ #define SOLARIS_X86_V_VAR 0x07 /* Var partition */ #define SOLARIS_X86_V_HOME 0x08 /* Home partition */ #define SOLARIS_X86_V_ALTSCTR 0x09 /* Alternate sector partition */ #define SOLARIS_X86_V_CACHE 0x0a /* Cache (cachefs) partition */ #define SOLARIS_X86_V_UNMNT 0x01 /* Unmountable partition */ #define SOLARIS_X86_V_RONLY 0x10 /* Read only */ struct solaris_x86_slice { ushort s_tag; /* ID tag of partition */ ushort s_flag; /* permision flags */ daddr_t s_start; /* start sector no of partition */ long s_size; /* # of blocks in partition */ }; struct solaris_x86_vtoc { unsigned long v_bootinfo[3]; /* info needed by mboot (unsupported) */ unsigned long v_sanity; /* to verify vtoc sanity */ unsigned long v_version; /* layout version */ char v_volume[8]; /* volume name */ ushort v_sectorsz; /* sector size in bytes */ ushort v_nparts; /* number of partitions */ unsigned long v_reserved[10]; /* free space */ struct solaris_x86_slice v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ char v_asciilabel[128]; /* for compatibility */ }; #endif /* _GM_S86DL_H */ gpart-0.3/src/gm_xfs.c000066400000000000000000000030161262504202100147010ustar00rootroot00000000000000/* * gm_xfs.c -- gpart SGI xfs guessing module * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 30.01.2001 * Modified: * */ #include #include "gpart.h" #include "gm_xfs.h" int xfs_init(disk_desc *d,g_module *m) { if ((d == 0) || (m == 0)) return (0); m->m_desc = "SGI XFS filesystem"; return (512); } int xfs_term(disk_desc *d) { return (1); } int xfs_gfun(disk_desc *d,g_module *m) { xfs_sb_t *sb; s64_t size; m->m_guess = GM_NO; sb = (xfs_sb_t *)d->d_sbuf; /* * Sanity checks from xfs_mount.c */ if (be32(sb->sb_magicnum) != XFS_SB_MAGIC) return (1); if (be32(sb->sb_blocksize) != getpagesize()) return (1); if ((sb->sb_imax_pct > 100) || (sb->sb_sectsize <= 0)) return (1); if ((be16(sb->sb_inodesize) < XFS_DINODE_MIN_SIZE) || (be16(sb->sb_inodesize) > XFS_DINODE_MAX_SIZE)) return (1); if (be32(sb->sb_blocksize) != 1 << sb->sb_blocklog) return (1); size = be64(sb->sb_logstart) ? (s64_t)be32(sb->sb_logblocks) : 0LL; size = be64(sb->sb_dblocks) - size; size *= be32(sb->sb_blocksize); size /= d->d_ssize; m->m_guess = GM_YES; m->m_part.p_start = d->d_nsb; m->m_part.p_size = (unsigned long)size; m->m_part.p_typ = 0x83; return (1); } gpart-0.3/src/gm_xfs.h000066400000000000000000000124011262504202100147040ustar00rootroot00000000000000/* * gm_xfs.h -- gpart SGI xfs guessing module header * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 30.01.2001 * Modified: * */ #ifndef _GM_XFS_H #define _GM_XFS_H /* imported from asm/types.h */ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; typedef __signed__ long long int __s64; typedef unsigned long long int __u64; /* * Taken from SGI's Jan192001prerelease.patch for Linux kernel 2.4.0 */ typedef __u32 xfs_agblock_t; /* blockno in alloc. group */ typedef __u32 xfs_extlen_t; /* extent length in blocks */ typedef __u32 xfs_agnumber_t; /* allocation group number */ typedef __s32 xfs_extnum_t; /* # of extents in a file */ typedef __s16 xfs_aextnum_t; /* # extents in an attribute fork */ typedef __s64 xfs_fsize_t; /* bytes in a file */ typedef __u64 xfs_ufsize_t; /* unsigned bytes in a file */ typedef __s32 xfs_suminfo_t; /* type of bitmap summary info */ typedef __s32 xfs_rtword_t; /* word type for bitmap manipulations */ typedef __s64 xfs_lsn_t; /* log sequence number */ typedef __s32 xfs_tid_t; /* transaction identifier */ typedef __u32 xfs_dablk_t; /* dir/attr block number (in file) */ typedef __u32 xfs_dahash_t; /* dir/attr hash value */ typedef __u16 xfs_prid_t; /* prid_t truncated to 16bits in XFS */ /* * These types are 64 bits on disk but are either 32 or 64 bits in memory. * Disk based types: */ typedef __u64 xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ typedef __u64 xfs_drfsbno_t; /* blockno in filesystem (raw) */ typedef __u64 xfs_drtbno_t; /* extent (block) in realtime area */ typedef __u64 xfs_dfiloff_t; /* block number in a file */ typedef __u64 xfs_dfilblks_t; /* number of blocks in a file */ typedef __u64 xfs_off_t; typedef __s32 xfs32_off_t; typedef __u64 xfs_ino_t; /* type */ typedef __s32 xfs_daddr_t; /* type */ typedef char * xfs_caddr_t; /* type */ typedef __u32 xfs_dev_t; typedef struct { unsigned char __u_bits[16]; } uuid_t; #define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ #define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ #define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ #define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ #define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ /* * Inode minimum and maximum sizes. */ #define XFS_DINODE_MIN_LOG 8 #define XFS_DINODE_MAX_LOG 11 #define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) #define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) typedef struct xfs_sb { __u32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ __u32 sb_blocksize; /* logical block size, bytes */ xfs_drfsbno_t sb_dblocks; /* number of data blocks */ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ xfs_drtbno_t sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* file system unique id */ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ xfs_ino_t sb_rootino; /* root inode number */ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ xfs_agblock_t sb_agblocks; /* size of an allocation group */ xfs_agnumber_t sb_agcount; /* number of allocation groups */ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ xfs_extlen_t sb_logblocks; /* number of log blocks */ __u16 sb_versionnum; /* header version == XFS_SB_VERSION */ __u16 sb_sectsize; /* volume sector size, bytes */ __u16 sb_inodesize; /* inode size, bytes */ __u16 sb_inopblock; /* inodes per block */ char sb_fname[12]; /* file system name */ __u8 sb_blocklog; /* log2 of sb_blocksize */ __u8 sb_sectlog; /* log2 of sb_sectsize */ __u8 sb_inodelog; /* log2 of sb_inodesize */ __u8 sb_inopblog; /* log2 of sb_inopblock */ __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ __u8 sb_rextslog; /* log2 of sb_rextents */ __u8 sb_inprogress; /* mkfs is in progress, don't mount */ __u8 sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ __u64 sb_icount; /* allocated inodes */ __u64 sb_ifree; /* free inodes */ __u64 sb_fdblocks; /* free data blocks */ __u64 sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ xfs_ino_t sb_uquotino; /* user quota inode */ xfs_ino_t sb_pquotino; /* project quota inode */ __u16 sb_qflags; /* quota flags */ __u8 sb_flags; /* misc. flags */ __u8 sb_shared_vn; /* shared version number */ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ __u32 sb_unit; /* stripe or raid unit */ __u32 sb_width; /* stripe or raid width */ __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ __u8 sb_dummy[7]; /* padding */ } xfs_sb_t; #endif /* _GM_XFS_H */ gpart-0.3/src/gmodules.c000066400000000000000000000046641262504202100152470ustar00rootroot00000000000000/* * gmodules.c -- gpart module functions * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 29.01.2001 * New modules: qnx & beos. * */ #include #include #include #include "gpart.h" static g_module *g_head; static int g_count; g_module *g_mod_head() { return (g_head); } int g_mod_count() { return (g_count); } void g_mod_list() { g_module *m; pr(MSG,"Module\tWeight\n"); for (m = g_head; m; m = m->m_next) pr(MSG,"%s\t(%3.1f)\n",m->m_name,m->m_weight); pr(MSG,"\n"); } void g_mod_delete(g_module *m) { if (m) { if (m->m_name) free((void *)m->m_name); free(m); g_count--; } } void g_mod_deleteall() { g_module *m; while (g_head) { m = g_head->m_next; g_mod_delete(g_head); g_head = m; } } /* * set weight of module and re-insert as head. */ g_module *g_mod_setweight(char *name,float weight) { g_module *m, *prev = 0; for (m = g_head; m; m = m->m_next) if (strcmp(m->m_name,name) == 0) break; else prev = m; if (m == 0) return (0); if (prev) { prev->m_next = m->m_next; m->m_next = g_head; g_head = m; } g_head->m_weight = weight; return (g_head); } g_module *g_mod_lookup(int how,char *name) { g_module *m; if (g_head == 0) { if (how == GM_LOOKUP) return (0); g_head = (g_module *)alloc(sizeof(g_module)); m = g_head; } else { for (m = g_head; m->m_next; m = m->m_next) if (strcmp(m->m_name,name) == 0) return (m); if (how == GM_LOOKUP) return (0); m->m_next = (g_module *)alloc(sizeof(g_module)); m = m->m_next; } if ((m->m_name = strdup(name)) == 0) pr(FATAL,"out of memory in strdup"); m->m_weight = 1.0; g_count++; return (m); } /* * preloaded modules */ void g_mod_addinternals() { g_module *m; #define GMODINS(mod) \ do { \ m = g_mod_lookup(GM_INSERT,#mod); \ if (m) { \ m->m_init=mod##_init; \ m->m_term=mod##_term; \ m->m_gfun=mod##_gfun; \ } \ } while (0); /* * If no weights are given on the command line, the order * is somehow important. */ #define G_MODULE(mod) GMODINS(mod) G_MODULES #undef G_MODULE } gpart-0.3/src/gmodules.h000066400000000000000000000041351262504202100152450ustar00rootroot00000000000000/* * gmodules.h -- gpart module header file * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 29.01.2001 * New modules: qnx & beos. * */ #ifndef _GMODULES_H #define _GMODULES_H #define GM_NO (0.0) /* predefined probabilities */ #define GM_PERHAPS (0.5) #define GM_YES (0.8) #define GM_UNDOUBTEDLY (1.0) typedef struct g_mod { char *m_name; /* name of module */ char *m_desc; /* readable description */ int (*m_init)(disk_desc *,struct g_mod *); int (*m_term)(disk_desc *); int (*m_gfun)(disk_desc *,struct g_mod *); float m_guess; float m_weight; /* probability weight */ dos_part_entry m_part; /* a guessed partition entry */ long m_align; /* alignment of partition */ struct g_mod *m_next; unsigned int m_hasptbl : 1; /* has a ptbl like entry in sec 0 */ unsigned int m_notinext : 1; /* cannot exist in an ext part. */ unsigned int m_skip : 1; /* skip this module this time */ } g_module; #define GM_LOOKUP 0 #define GM_INSERT 1 void g_mod_list(), g_mod_delete(g_module *), g_mod_deleteall(); g_module *g_mod_head(), *g_mod_lookup(int,char *); void g_mod_addinternals(); int g_mod_count(); g_module *g_mod_setweight(char *,float); /* * preloaded guessing modules, order is important as it is also the order of registering and guessing */ #define G_MODULES \ G_MODULE(bsddl) \ G_MODULE(lswap) \ G_MODULE(qnx4) \ G_MODULE(reiserfs) \ G_MODULE(ntfs) \ G_MODULE(hpfs) \ G_MODULE(minix) \ G_MODULE(beos) \ G_MODULE(ext2) \ G_MODULE(btrfs) \ G_MODULE(fat) \ G_MODULE(s86dl) \ G_MODULE(hmlvm) \ G_MODULE(lvm2) \ G_MODULE(xfs) #define G_MODULE(mod) int mod##_init(disk_desc *,g_module *), \ mod##_term(disk_desc *), \ mod##_gfun(disk_desc *,g_module *); G_MODULES #undef G_MODULE #endif /* _GMODULES_H */ gpart-0.3/src/gpart.c000066400000000000000000001135701262504202100145420ustar00rootroot00000000000000/* * gpart.c -- gpart main * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: 11.06.1999 * Handle disk read errors. * Minor fixes. * * 29.06.1999 * Made every disk read/write buffer aligned to pagesize. * * 29.08.1999 * Default scan increment now 's'. * Extended ptbl boundary condition now depends on scan * increment. * * 26.02.2000 * Default scan increment 'h' again. * Fixed faulty head boundary condition. * Introduced ptbl entry editing after guess loop. * First scanned sector is no of sects/head, if no start * sector was given. * m_notinext now honoured. * Make a MBR backup. * Interactive mode now somehow works. * * 14.05.2000 * Made writing of guessed table also aligned. * Fixed stupid copy&paste bug in the check routine * (found by Bruno Bozza . * * 29.01.2001 * Extended partition type on an LBA disk now 0x0f instead * of 0x05. Changed some partition types (get_part_type). * When comparing partition types in extptbl links, try * to compare similarity, not equality (is_same_partition_type). * */ #include #include #include #include #include #include #include #include #include #include #include "gpart.h" static const char *gpart_version = PACKAGE_NAME " v" VERSION; int f_check = 0, f_verbose = 0, f_dontguess = 0, f_fast = 1; int f_getgeom = 1, f_interactive = 0, f_quiet = 0, f_testext = 1; int f_skiperrors = 1, berrno = 0; int (*boundary_fun)(disk_desc *,s64_t); unsigned long increment = 's', gc = 0, gh = 0, gs = 0; s64_t skipsec = 0, maxsec = 0; FILE *logfile = 0; void usage() { FILE *fp = stderr; fprintf(fp,"Usage: %s [options] device\n",PACKAGE_NAME); fprintf(fp,"Options: [-b ][-C c,h,s][-c][-d][-E][-e][-f][-g][-h][-i]\n"); fprintf(fp," [-K ][-k <# of sectors>][-L][-l ]\n"); fprintf(fp," [-n ][-q][-s ]\n"); fprintf(fp," [-V][-v][-W ][-w ]\n"); fprintf(fp,"%s (c) 1999-2001 Michail Brzitwa .\n",gpart_version); fprintf(fp,"Guess PC-type hard disk partitions.\n\n"); fprintf(fp,"Options:\n"); fprintf(fp," -b Save a backup of the original MBR to specified file.\n"); fprintf(fp," -C Set c/h/s to be used in the scan.\n"); fprintf(fp," -c Check/compare mode.\n"); fprintf(fp," -d Do not start the guessing loop.\n"); fprintf(fp," -E Do not try to identify extended partition tables.\n"); fprintf(fp," -e Do not skip disk read errors.\n"); fprintf(fp," -f Full scan.\n"); fprintf(fp," -g Do not try to get the disk geometry.\n"); fprintf(fp," -h Show this help.\n"); fprintf(fp," -i Run interactively (ask for confirmation).\n"); fprintf(fp," -K Scan only up to given sector.\n"); fprintf(fp," -k Skip sectors before scan.\n"); fprintf(fp," -L List available modules and their weights, then exit.\n"); fprintf(fp," -l Logfile name.\n"); fprintf(fp," -n Scan increment: number or 's' sector, 'h' head, 'c' cylinder.\n"); fprintf(fp," -q Run quiet (however log file is written if specified).\n"); fprintf(fp," -s Sector size to use (disable sector size probing).\n"); fprintf(fp," -V Show version.\n"); fprintf(fp," -v Verbose mode. Can be given more than once.\n"); fprintf(fp," -W Write guessed primary partition table to given device or file.\n"); fprintf(fp," -w Weight factor of module.\n"); fprintf(fp,"\n"); } void pr(int type,char *fmt,...) { va_list vl; static char msg[512]; va_start(vl,fmt); vsnprintf(msg,511,fmt,vl); va_end(vl); msg[511] = 0; switch (type) { case FATAL : g_mod_deleteall(); if (! f_quiet) fprintf(stderr,EM_FATALERROR,msg); if (logfile) { fprintf(logfile,EM_FATALERROR,msg); fclose(logfile); } exit(1); case ERROR : if (! f_quiet) fprintf(stderr,EM_SIMPLEERROR,msg); if (logfile) fprintf(logfile,EM_SIMPLEERROR,msg); break; case WARN : if (! f_quiet) fprintf(stderr,EM_WARNING,msg); if (logfile) fprintf(logfile,EM_WARNING,msg); break; case MSG : if (! f_quiet) fputs(msg,stdout); fflush(stdout); if (logfile) fputs(msg,logfile); break; } if (logfile) fflush(logfile); } byte_t *alloc(ssize_t s) { byte_t *p = (byte_t *)malloc(s); if (p == 0) pr(FATAL,EM_MALLOCFAILED,s); memset(p,0,s); return (p); } /* * read nsecs blocks of ssize bytes from fd */ ssize_t bread(int fd,byte_t *buf,size_t ssize,size_t nsecs) { ssize_t cs = 0, nr = 0; for ( ; nsecs > 0; nsecs--) { if ((nr = read(fd,buf,ssize)) == -1) { berrno = errno; return ((cs == 0) ? -1 : cs); } cs += nr; buf += nr; if (nr < ssize) break; } return (cs); } static int yesno(char *q) { int ch = 0; char buf[3]; pr(MSG,q); pr(MSG," %s : ",DM_YESNO); if (fgets(buf,3,stdin)) ch = *buf; pr(MSG,"\n"); return (strchr(DM_YES,ch) == 0 ? 0 : 1); } static long number_or_quit(char *m,long lo,long up) { char buf[32]; long num = -1; pr(MSG,m); pr(MSG,DM_NUMORQUIT,lo,up); if (fgets(buf,32,stdin)) { if (strchr(DM_QUIT,*buf)) return (-1); num = strtoul(buf,0,0); if (errno == ERANGE) return (-1); } return (num); } /* * get three comma separated strings. */ static int get_csep_arg(char *arg,char **p1,char **p2,char **p3) { char *p; if (p1) *p1 = arg; else return (0); if ((p = strchr(arg,',')) == 0) return (0); *p = 0; arg = p + 1; if (p2) *p2 = arg; else return (1); if (p3) { if ((p = strchr(arg,',')) == 0) return (0); *p = 0; *p3 = p + 1; } return (1); } /* * partition type list, taken from *BSD i386 fdisk, cfdisk etc. */ static char *get_part_type(int type) { int i; struct { int t; char *n; } ptypes[] = { { 0x00, "unused" }, { 0x01, "Primary DOS with 12 bit FAT" }, { 0x02, "XENIX / filesystem" }, { 0x03, "XENIX /usr filesystem" }, { 0x04, "Primary DOS with 16 bit FAT (<= 32MB)" }, { 0x05, "Extended DOS" }, { 0x06, "Primary 'big' DOS (> 32MB)" }, { 0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX" }, { 0x08, "AIX filesystem" }, { 0x09, "AIX boot partition or Coherent" }, { 0x0A, "OS/2 Boot Manager or OPUS" }, { 0x0B, "DOS or Windows 95 with 32 bit FAT" }, { 0x0C, "DOS or Windows 95 with 32 bit FAT, LBA" }, { 0x0E, "Primary 'big' DOS (> 32MB, LBA)" }, { 0x0F, "Extended DOS, LBA" }, { 0x10, "OPUS" }, { 0x11, "Hidden DOS with 12 bit FAT" }, { 0x12, "Compaq Diagnostics" }, { 0x14, "Hidden DOS with 16 bit FAT (<= 32MB)" }, { 0x16, "Hidden 'big' DOS (> 32MB)" }, { 0x17, "OS/2 Boot Manager HPFS" }, { 0x18, "AST special Windows swap file" }, { 0x24, "NEC MS-DOS 3.x" }, { 0x3C, "PowerQuest PartitionMagic recovery partition" }, { 0x40, "VENIX 286" }, { 0x4D, "QNX4.x" }, { 0x4E, "QNX4.x 2nd part" }, { 0x4F, "QNX4.x 3rd part" }, { 0x50, "DM" }, { 0x51, "DM" }, { 0x51, "DM" }, { 0x52, "CP/M or Microport SysV/AT" }, { 0x55, "EZ Drive" }, { 0x56, "GB" }, { 0x61, "SpeedStor" }, { 0x63, "ISC UNIX, other System V/386, GNU HURD or Mach" }, { 0x64, "Novell Netware 2.xx" }, { 0x65, "Novell Netware 3.xx" }, { 0x70, "DiskSecure Multi-Boot" }, { 0x75, "PCIX" }, { 0x80, "Minix V1" }, { 0x81, "Minix V2/Linux" }, { 0x82, "Linux swap or Solaris/x86" }, { 0x83, "Linux ext2 filesystem" }, { 0x85, "Extended Linux" }, { 0x86, "FAT16 volume/stripe set" }, { 0x8E, "Linux LVM physical volume" }, { 0x93, "Amoeba filesystem" }, { 0x94, "Amoeba bad block table" }, { 0xA5, "FreeBSD/NetBSD/386BSD" }, { 0xA6, "OpenBSD" }, { 0xA7, "NEXTSTEP" }, { 0xB7, "BSDI BSD/386 filesystem" }, { 0xB8, "BSDI BSD/386 swap" }, { 0xC7, "Syrinx" }, { 0xDB, "Concurrent CPM or C.DOS or CTOS" }, { 0xE1, "SpeedStor 12-bit FAT extended" }, { 0xE3, "Speed" }, { 0xE4, "SpeedStor 16-bit FAT" }, { 0xEB, "BeOS fs" }, { 0xF1, "SpeedStor" }, { 0xF2, "DOS 3.3+ Secondary" }, { 0xF4, "SpeedStor" }, { 0xFD, "Linux raid autodetect" }, { 0xFE, "LANstep" }, { 0xFF, "BBT (Bad Blocks Table)" } }; for (i = 0; i < sizeof(ptypes)/sizeof(ptypes[0]); i++) if (type == ptypes[i].t) return (ptypes[i].n); return (0); } static int is_ext_parttype(dos_part_entry *p) { return (p->p_size && ((p->p_typ == 0x05) || (p->p_typ == 0x0F) || (p->p_typ == 0x85))); } static int is_sane_partentry(disk_desc *d,dos_part_entry *p,int c) { if (p->p_start >= d->d_nsecs) { if (c) pr(WARN,EM_PSTART2BIG,get_part_type(p->p_typ)); return (0); } if (p->p_size > d->d_nsecs) { if (c) pr(WARN,EM_PSIZE2BIG,get_part_type(p->p_typ)); return (0); } if (p->p_start + p->p_size > d->d_nsecs) { if (c) pr(WARN,EM_PEND2BIG,get_part_type(p->p_typ)); return (0); } if (p->p_flag && (p->p_flag != DOSPARTACTIVE)) { if (c) pr(WARN,EM_STRANGEPTYPE,get_part_type(p->p_typ)); return (0); } return (1); } static int is_real_parttype(dos_part_entry *p) { return (!is_ext_parttype(p) && p->p_typ && get_part_type(p->p_typ)); } static int no_of_ext_partitions(dos_part_entry *p) { dos_part_entry *t; int ne = 0; for (t = &p[0]; t <= &p[NDOSPARTS - 1]; t++) if (is_ext_parttype(t)) ne++; return (ne); } static int no_of_real_partitions(dos_part_entry *p) { dos_part_entry *t; int nr = 0; for (t = &p[0]; t <= &p[NDOSPARTS - 1]; t++) if (is_real_parttype(t)) nr++; return (nr); } /* * Test similarity of partition types */ static int is_same_partition_type(dos_part_entry *p1,dos_part_entry *p2) { int ret = 0; switch (p1->p_typ) { case 0x01: case 0x11: ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E); break; case 0x06: case 0x0E: case 0x16: ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E) || (p2->p_typ == 0x16); break; case 0x05: case 0x0F: ret = (p2->p_typ == 0x05) || (p2->p_typ == 0x0F); break; case 0x0B: case 0x0C: ret = (p2->p_typ == 0x0B) || (p2->p_typ == 0x0C); break; case 0x8E: case 0xFE: ret = (p2->p_typ == 0x8E) || (p2->p_typ == 0xFE); break; default : ret = p1->p_typ == p2->p_typ; break; } return (ret); } /* * detecting an extended ptbl isn't unambiguous, the boot code * preceding the ptbl should be zeroed but isn't always. The * ptbl should in theory contain one 'normal' entry, zero or * one link to the next extended ptbl and two or three zeroed * entries. */ static int is_ext_parttable(disk_desc *d,byte_t *buf) { int r, e; byte_t *magic; dos_part_entry *p, *t; p = (dos_part_entry *)(buf + DOSPARTOFF); magic = (byte_t *)&p[NDOSPARTS]; if (*(unsigned short *)magic != le16(DOSPTMAGIC)) return (0); /* * ptbl sanity checks. */ for (t = p; t <= &p[NDOSPARTS - 1]; t++) if (! is_sane_partentry(d,t,0)) return (0); /* * one real, zero or one extended and two or three unused * partition entries. */ r = no_of_real_partitions(p); e = no_of_ext_partitions(p); return ((r == 1) && ((e == 0) || (e == 1))); } static void fillin_dos_chs(disk_desc *d,dos_part_entry *p,s64_t offset) { unsigned long n; n = p->p_start; if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s) { p->p_ssect = d->d_dg.d_s | ((1023 >> 2) & 0xc0); p->p_shd = d->d_dg.d_h - 1; p->p_scyl = 1023 & 0xff; } else { p->p_ssect = (n % d->d_dg.d_s) + 1; n /= d->d_dg.d_s; p->p_shd = n % d->d_dg.d_h; n /= d->d_dg.d_h; p->p_scyl = n & 0xff; p->p_ssect |= (n >> 2) & 0xc0; } n = p->p_size + p->p_start - 1; if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s) { p->p_esect = d->d_dg.d_s | ((1023 >> 2) & 0xc0); p->p_ehd = d->d_dg.d_h - 1; p->p_ecyl = 1023 & 0xff; } else { p->p_esect = (n % d->d_dg.d_s) + 1; n /= d->d_dg.d_s; p->p_ehd = n % d->d_dg.d_h; n /= d->d_dg.d_h; p->p_ecyl = n & 0xff; p->p_esect |= (n >> 2) & 0xc0; } } static void u_to_chs(disk_desc *d,unsigned long u,long *c,long *h,long *s) { struct disk_geom *g = &d->d_dg; *c = *h = *s = 0; if (g->d_h && g->d_s && u) { *c = u / (g->d_h * g->d_s); *h = (u / g->d_s) % g->d_h; *s = u % g->d_s + 1; } } static int on_cyl_boundary(disk_desc *d,s64_t sec) { struct disk_geom *g = &d->d_dg; if (g->d_h && g->d_s) return ((sec % (g->d_h * g->d_s)) == 0); return (1); } static int on_head_boundary(disk_desc *d,s64_t sec) { struct disk_geom *g = &d->d_dg; if (g->d_s) return ((sec % g->d_s) == 0); return (1); } static void print_partition(disk_desc *d,dos_part_entry *p,int inset,s64_t offset) { long i, c = 0, h = 0, s = 0; s64_t size; char *ptyp = get_part_type(p->p_typ); #define indent(s) for (i = 0; i < s; i++) pr(MSG," ") size = p->p_size; s2mb(d,size); indent(inset); pr(MSG,PM_PT_TYPE,p->p_typ,p->p_typ,ptyp ? ptyp : "UNKNOWN"); if (p->p_flag == DOSPARTACTIVE) pr(MSG," (BOOT)"); pr(MSG,"\n"); indent(inset); pr(MSG,PM_PT_SIZE,size,(s64_t)p->p_size); size = p->p_start; size += offset; size += p->p_size; if (size) size -= 1; pr(MSG," s(%qd-%qd)\n",(s64_t)p->p_start + offset,size); indent(inset); pr(MSG,PM_PT_CHS, DOSCYL(p->p_scyl,p->p_ssect),p->p_shd,DOSSEC(p->p_ssect), DOSCYL(p->p_ecyl,p->p_esect),p->p_ehd,DOSSEC(p->p_esect)); if (size) u_to_chs(d,p->p_start + offset,&c,&h,&s); pr(MSG," (%ld/%ld/%ld)-",c,h,s); if (size) u_to_chs(d,p->p_start + offset + p->p_size - 1,&c,&h,&s); pr(MSG,"(%ld/%ld/%ld)r\n",c,h,s); if (f_verbose > 0) { indent(inset); pr(MSG,PM_PT_HEX); for (i = 0; i < sizeof(dos_part_entry); i++) pr(MSG," %02X",((byte_t *)p)[i]); pr(MSG,"\n"); } pr(MSG,"\n"); } static void print_ext_partitions(disk_desc *d,s64_t offset) { dos_part_table *pt = d->d_pt.t_ext; dos_part_entry *p; s64_t extst = 0; for ( ; pt; pt = pt->t_ext) { pr(MSG,PM_EXTPART); for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) if (is_real_parttype(p)) print_partition(d,p,1,offset + extst); for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) if (is_ext_parttype(p)) extst = p->p_start; } } static void print_ptable(disk_desc *d,dos_part_table *pt,int pr_ext) { int n; for (n = 0; n < NDOSPARTS; n++) { pr(MSG,PM_PRIMPART,n + 1); print_partition(d,&pt->t_parts[n],0,0); if (pr_ext && is_ext_parttype(&pt->t_parts[n])) print_ext_partitions(d,pt->t_parts[n].p_start); } } static void print_disk_desc(disk_desc *d) { s64_t s; pr(MSG,PM_DEVDESC1,d->d_dev,d->d_ssize); if (f_getgeom) { s = d->d_nsecs; s2mb(d,s); pr(MSG,PM_DEVDESC2, d->d_dg.d_c,d->d_dg.d_h,d->d_dg.d_s, d->d_lba ? "(LBA) " : " ", d->d_nsecs,s); } pr(MSG,"\n"); if (d->d_pt.t_magic != le16(DOSPTMAGIC)) pr(WARN,EM_STRANGEPTBLMAGIC,d->d_pt.t_magic); print_ptable(d,&d->d_pt,1); } static void print_mboot_block(disk_desc *d) { int n, m, cols = 16; byte_t *boot = d->d_pt.t_boot; pr(MSG,PM_MBRPRINT,d->d_dev); for (n = 0; n < DOSPARTOFF - cols; n += cols) { pr(MSG," %04X: ",n); for (m = n; m < n + cols; m++) pr(MSG," %02x",boot[m]); pr(MSG,"\n "); for (m = n; m < n + cols; m++) pr(MSG," %c ",isprint(boot[m]) ? boot[m] : '.'); pr(MSG,"\n"); } } static void read_part_table(disk_desc *d,s64_t sec,byte_t *where) { ssize_t rd; size_t psize; byte_t *ubuf, *buf; psize = getpagesize(); ubuf = alloc(MAXSSIZE + psize); buf = align(ubuf,psize); sec *= d->d_ssize; if (l64seek(d->d_fd,sec,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); if (d->d_ssize < 512) rd = bread(d->d_fd,buf,d->d_ssize,512 / d->d_ssize); else rd = bread(d->d_fd,buf,d->d_ssize,1); if (rd == -1) pr(FATAL,EM_PTBLREAD); memcpy(where,buf,512); free((void *)ubuf); } static void read_ext_part_table(disk_desc *d,dos_part_table *pt) { dos_part_entry *p, *ep; s64_t epsize, epstart, epoffset; int epcount; epsize = epstart = epoffset = epcount = 0; while (1) { ep = 0; for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) if (is_ext_parttype(p)) { if (ep == 0) { ep = p; break; } pr(ERROR,EM_TOOMANYEXTP); } if (ep == 0) return; if (++epcount > 128) /* arbitrary maximum */ { pr(ERROR,EM_TOOMANYLOGP,128); return; } if (epstart == 0) { epstart = ep->p_start; epsize = ep->p_size; epoffset = 0; } else epoffset = ep->p_start; if (epoffset > epsize) { pr(ERROR,EM_EPILLEGALOFS); return; } /* * link in new extended ptbl. */ pt->t_ext = (dos_part_table *)alloc(sizeof(dos_part_table)); read_part_table(d,epstart + epoffset,(pt = pt->t_ext)->t_boot); if (! is_ext_parttable(d,pt->t_boot)) { pr(ERROR,EM_INVXPTBL,epstart + epoffset); return; } } } static void free_disk_desc(disk_desc *d) { dos_part_table *pt; dos_guessed_pt *pg; void *t; for (pt = d->d_pt.t_ext; pt; ) { t = pt->t_ext; free((void *)pt); pt = t; } for (pt = d->d_gpt.t_ext; pt; ) { t = pt->t_ext; free((void *)pt); pt = t; } for (pg = d->d_gl; pg; ) { t = pg->g_next; free((void *)pg); pg = t; } free((void *)d); } static disk_desc *get_disk_desc(char *dev,int sectsize) { byte_t *ubuf, *buf; disk_desc *d; int psize, ssize; struct disk_geom *dg; psize = getpagesize(); ubuf = alloc(MAXSSIZE + psize); buf = align(ubuf,psize); d = (disk_desc *)alloc(sizeof(disk_desc)); /* * I don't care if the given name denotes a block or character * special file or just a regular file. */ if ((d->d_fd = open(dev,O_RDONLY)) == -1) pr(FATAL,EM_OPENFAIL,dev,strerror(errno)); /* * try to test for sector sizes (doesn't work under many systems). */ if (sectsize > MAXSSIZE) pr(FATAL,EM_WRONGSECTSIZE,MAXSSIZE); if (sectsize) { ssize = bread(d->d_fd,buf,sectsize,1); if (ssize != sectsize) pr(FATAL,EM_FAILSSIZEATTEMPT,sectsize); d->d_ssize = sectsize; } else { for (d->d_ssize = MINSSIZE; d->d_ssize <= MAXSSIZE; d->d_ssize *= 2) { if (l64seek(d->d_fd,0,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,dev); ssize = bread(d->d_fd,buf,d->d_ssize,1); if (ssize == d->d_ssize) break; } if (ssize == -1) pr(FATAL,EM_CANTGETSSIZE,dev); } d->d_dev = dev; read_part_table(d,0,d->d_pt.t_boot); if (f_getgeom) { if ((dg = disk_geometry(d)) == 0) pr(FATAL,EM_CANTGETGEOM); memcpy(&d->d_dg,dg,sizeof(struct disk_geom)); d->d_nsecs = dg->d_nsecs; /* * command line geometry overrides */ if (gc) d->d_dg.d_c = gc; if (gh) d->d_dg.d_h = gh; if (gs) d->d_dg.d_s = gs; } else { d->d_dg.d_c = gc; d->d_dg.d_h = gh; d->d_dg.d_s = gs; } if (d->d_dg.d_c < 1024) d->d_dosc = 1; if ((d->d_dg.d_h > 16) || (d->d_dg.d_s > 63)) d->d_lba = 1; if (gh && gc && gs) { /* Override number of sectors with command line parameters */ d->d_nsecs = d->d_dg.d_c; d->d_nsecs *= d->d_dg.d_h; d->d_nsecs *= d->d_dg.d_s; } read_ext_part_table(d,&d->d_pt); close(d->d_fd); free((void *)ubuf); return (d); } static void add_guessed_p(disk_desc *d,dos_part_entry *p,int cnt) { dos_guessed_pt *gpt; if (d->d_gl == 0) gpt = d->d_gl = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt)); else { for (gpt = d->d_gl; gpt->g_next; gpt = gpt->g_next) ; gpt->g_next = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt)); gpt = gpt->g_next; } gpt->g_ext = (cnt > 1); for ( ; cnt > 0; cnt--) memcpy(&gpt->g_p[cnt-1],&p[cnt-1],sizeof(dos_part_entry)); gpt->g_sec = d->d_nsb; } static g_module *get_best_guess(g_module **g,int count) { int mx, i; float bestg = 0.0; /* * up to now the best guess is simple that one which * reported the largest probability (if there are more * than one, the last one of them). */ for (mx = i = 0; i < count; i++) if (g[i]->m_guess * g[i]->m_weight > bestg) bestg = g[mx = i]->m_guess * g[i]->m_weight; return ((bestg > 0.0) ? g[mx] : 0); } static int mod_is_aligned(disk_desc *d,g_module *m) { s64_t al; switch (m->m_align) { case 'h' : return (on_head_boundary(d,d->d_nsb)); case 'c' : return (on_cyl_boundary(d,d->d_nsb)); case 1 : case 's' : return (1); default : if (m->m_align > 0) { al = d->d_nsb; al %= m->m_align; return (al == 0); } break; } return (1); } /* * the main guessing loop. */ static void do_guess_loop(disk_desc *d) { g_module *m, **guesses; unsigned long incr = 0; int nsecs, in_ext = 0, end_of_ext = 0, psize; ssize_t rd, bsize = d->d_ssize; s64_t bincr, noffset, start; byte_t *ubuf; if ((d->d_fd = open(d->d_dev,O_RDONLY)) == -1) pr(FATAL,EM_OPENFAIL,d->d_dev,strerror(errno)); /* * initialize modules. Each should return the minimum * size in bytes it wants to receive for a test. */ for (m = g_mod_head(); m; m = m->m_next) if (m->m_init) { int sz; if ((sz = (*m->m_init)(d,m)) <= 0) pr(ERROR,EM_MINITFAILURE,m->m_name); bsize = max(sz,bsize); } if (bsize % d->d_ssize) bsize += d->d_ssize - bsize % d->d_ssize; nsecs = bsize / d->d_ssize; switch (increment) { case 's' : incr = 1; break; case 'h' : incr = d->d_dg.d_s; break; case 'c' : incr = d->d_dg.d_s * d->d_dg.d_h; break; default : incr = increment; break; } if (incr == 0) incr = 1; boundary_fun = (incr == 1) ? on_head_boundary : on_cyl_boundary; psize = getpagesize(); ubuf = alloc(bsize + psize); d->d_sbuf = align(ubuf,psize); d->d_nsb = 0; bincr = incr * d->d_ssize; start = skipsec ? skipsec : d->d_dg.d_s; d->d_nsb = start - incr; start *= d->d_ssize; if (l64seek(d->d_fd,start,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); /* * do the work: read blocks, distribute to modules, check * for probable hits. */ guesses = (g_module **)alloc(g_mod_count() * sizeof(g_module *)); pr(MSG,DM_STARTSCAN); scanloop: while ((rd = bread(d->d_fd,d->d_sbuf,d->d_ssize,nsecs)) == bsize) { int mod, have_ext = 0; g_module *bg; s64_t sz, ofs; d->d_nsb += incr; noffset = 0; ofs = d->d_nsb; s2mb(d,ofs); if (maxsec && (d->d_nsb > maxsec)) break; /* * reset modules */ for (m = g_mod_head(); m; m = m->m_next) m->m_skip = 0; guessit: bg = 0; mod = 0; for (m = g_mod_head(); m; m = m->m_next) { if (m->m_skip || (in_ext && m->m_notinext) || !mod_is_aligned(d,m)) continue; /* * because a gmodule is allowed to seek on * d->d_fd the current file position must be * saved. */ memset(&m->m_part,0,sizeof(dos_part_entry)); m->m_guess = GM_NO; l64opush(d->d_fd); if ((*m->m_gfun)(d,m) && (m->m_guess * m->m_weight >= GM_PERHAPS)) guesses[mod++] = m; if ((sz = l64opop(d->d_fd)) != l64tell(d->d_fd)) l64seek(d->d_fd,sz,SEEK_SET); } /* * now fetch the best guess. */ if (mod && (bg = get_best_guess(guesses,mod))) { noffset = bg->m_part.p_size; fillin_dos_chs(d,&bg->m_part,0); } /* * extended partition begin? */ if (f_testext && boundary_fun(d,d->d_nsb) && (!bg || !bg->m_hasptbl) && is_ext_parttable(d,d->d_sbuf)) { dos_part_entry *p; int no_ext; p = (dos_part_entry *)(d->d_sbuf + DOSPARTOFF); no_ext = no_of_ext_partitions(p); if (! in_ext) { pr(MSG,PM_POSSIBLEEXTPART,ofs); in_ext = 1; end_of_ext = 0; noffset = 0; } else if (no_ext == 0) end_of_ext = 1; if (in_ext) { if (f_interactive) { if (yesno(DM_ACCEPTGUESS)) add_guessed_p(d,p,have_ext = NDOSPARTS); else if (mod && bg) { bg->m_skip = 1; goto guessit; } } else add_guessed_p(d,p,have_ext = NDOSPARTS); } } if (! have_ext && noffset) { sz = noffset; s2mb(d,sz); if (in_ext) pr(MSG," "); pr(MSG,PM_POSSIBLEPART,bg->m_desc ? bg->m_desc : bg->m_name,sz,ofs); if (f_verbose) print_partition(d,&bg->m_part,in_ext ? 1 : 0,0); if (f_interactive) if (! yesno(DM_ACCEPTGUESS)) { noffset = 0; if (mod && bg) { bg->m_skip = 1; goto guessit; } } if (noffset) { add_guessed_p(d,&bg->m_part,1); if (end_of_ext) in_ext = 0; } } /* * seek to next sectors to investigate (may seek * backwards). */ if (noffset && f_fast) { if (noffset % incr) noffset += incr - noffset % incr; d->d_nsb += noffset - incr; noffset -= nsecs; noffset *= d->d_ssize; if (l64seek(d->d_fd,noffset,SEEK_CUR) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); } else if (bincr) if (l64seek(d->d_fd,bincr - bsize,SEEK_CUR) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); } /* * short read? */ if ((rd > 0) && (rd < bsize)) if (d->d_nsb + nsecs + 1 < d->d_nsecs) { /* * short read not at end of disk */ pr(f_skiperrors ? WARN : FATAL,EM_SHORTBREAD,d->d_nsb,rd,bsize); noffset = l64tell(d->d_fd); noffset /= d->d_ssize; noffset *= d->d_ssize; if (l64seek(d->d_fd,noffset,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr; goto scanloop; } if (rd == -1) { /* * EIO is ignored (skipping current sector(s)) */ if (f_skiperrors && (berrno == EIO)) { pr(WARN,EM_BADREADIO,d->d_nsb); noffset = l64tell(d->d_fd); noffset /= d->d_ssize; noffset += incr; noffset *= d->d_ssize; if (l64seek(d->d_fd,noffset,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,d->d_dev); d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr; goto scanloop; } pr(FATAL,EM_READERROR,d->d_dev,d->d_nsb,strerror(berrno)); } pr(MSG,DM_ENDSCAN); if (guesses) free((void *)guesses); for (m = g_mod_head(); m; m = m->m_next) if (m->m_term) (*m->m_term)(d); free((void *)ubuf); close(d->d_fd); } static void edit_partition(disk_desc *d,dos_part_entry *p) { char ans[32]; int n; unsigned long val; while (1) { pr(MSG,DM_NOCHECKWARNING); pr(MSG,PM_EDITITEM1,p->p_start); pr(MSG,PM_EDITITEM2,p->p_size); pr(MSG,PM_EDITITEM3,p->p_typ,get_part_type(p->p_typ)); if ((n = number_or_quit(DM_EDITWHICHITEM,1,3)) < 0) break; if ((n < 1) || (n > 3)) continue; pr(MSG,"Enter value for %d : ",n); if (fgets(ans,32,stdin)) { val = strtoul(ans,0,0); switch (n) { case 1: p->p_start = val; fillin_dos_chs(d,p,0); break; case 2: p->p_size = val; fillin_dos_chs(d,p,0); break; case 3: p->p_typ = val & 0xFF; break; } } } } static int make_mbr_backup(disk_desc *d,char *bfile) { int fd, ret = 0; if ((fd = open(bfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) return (ret); if (write(fd,d->d_pt.t_boot,512) == 512) ret = 1; close(fd); return (ret); } static void write_primary_ptbl(disk_desc *d,char *dev) { struct stat sbuf; byte_t *ptbl, *uptbl; int fd, doesntexist = 0, n; uptbl = alloc(d->d_ssize + getpagesize()); ptbl = align(uptbl,getpagesize()); if (stat(dev,&sbuf) == -1) { if (errno != ENOENT) pr(FATAL,EM_STATFAILURE,dev,strerror(errno)); else doesntexist = 1; } fd = open(dev,O_WRONLY | (doesntexist ? O_CREAT | O_EXCL : 0),0660); if (fd == -1) pr(FATAL,EM_OPENFAIL,dev,strerror(errno)); if (l64seek(fd,0,SEEK_SET) == -1) pr(FATAL,EM_SEEKFAILURE,dev); /* * is there a guessed partition table? */ if (d->d_gpt.t_magic == le16(DOSPTMAGIC)) { /* * ask if table should be hand-edited */ if (yesno(DM_EDITPTBL)) while (1) { if ((n = number_or_quit(DM_EDITWHICHPART,1,NDOSPARTS)) < 0) break; if ((n >= 1) && (n <= NDOSPARTS)) edit_partition(d,&d->d_gpt.t_parts[n - 1]); else break; print_ptable(d,&d->d_gpt,0); } /* * ask for the active partition. */ while (1) { if ((n = number_or_quit(DM_ACTWHICHPART,1,NDOSPARTS)) < 0) break; if ((n >= 1) && (n <= NDOSPARTS) && get_part_type(d->d_gpt.t_parts[n].p_typ)) { d->d_gpt.t_parts[n - 1].p_flag = DOSPARTACTIVE; break; } } if (yesno(DM_WRITEIT)) { memcpy(ptbl,d->d_pt.t_boot,DOSPARTOFF); memcpy(ptbl + DOSPARTOFF,d->d_gpt.t_parts,NDOSPARTS * sizeof(dos_part_entry) + 2); if (write(fd,ptbl,d->d_ssize) != d->d_ssize) pr(FATAL,EM_PTBLWRITE); if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) { sync(); sleep(1); sync(); reread_partition_table(fd); pr(WARN,DM_ASKTOREBOOT); } } else pr(MSG,DM_NOTWRITTEN); } close(fd); free((void *)uptbl); } static void warn_invalid(disk_desc *d,dos_part_entry *p,char *w) { if (f_verbose > 1) { pr(MSG,EM_PINVALID,w); print_partition(d,p,0,0); } } /* * after having gathered a list of possible partitions they * have to be checked for consistency. This routine must be * improved, it's too weird and is mistaken too often. */ static int check_partition_list(disk_desc *d) { dos_guessed_pt *gp, *prev; dos_part_entry *p, *rp, *ep, *lep; int n, npp, epp, maxp, in_ext; s64_t size, ofs; p = rp = ep = lep = 0; pr(MSG,DM_STARTCHECK); /* * 1. pass: discard overlapping entries. This means * that the first entry is assumed to be ok. */ ofs = 0; prev = 0; npp = 0; for (gp = d->d_gl; gp; gp = gp->g_next) { if (gp->g_ext || gp->g_inv) continue; p = &gp->g_p[0]; if (gp == d->d_gl) ofs = p->p_start + p->p_size; else { if (p->p_start < ofs) { /* * overlap. unlink and discard. */ prev->g_next = gp->g_next; free((void *)gp); gp = prev; npp++; } else ofs += p->p_size; } prev = gp; } if (npp) pr(WARN,EM_DISCARDOVLP,npp); /* * 2. pass: decide type of every partition, * marking inconsistent ones as invalid. */ size = 0; in_ext = npp = epp = 0; maxp = NDOSPARTS; for (n = 1, gp = d->d_gl; gp; gp = gp->g_next, n++) { if (gp->g_inv) continue; if (gp->g_ext) { if (gp->g_next == 0) { /* * ext ptbl without logical p. */ gp->g_inv = 1; warn_invalid(d,p,EM_P_EATEND); break; } if (! in_ext) { /* * new extended p. chain. */ if (no_of_ext_partitions(gp->g_p) == 0) { gp->g_inv = 1; warn_invalid(d,p,EM_P_EWLP); continue; } in_ext = 1; epp++; if (maxp >= NDOSPARTS) maxp--; /* * already had one? */ if (epp > 1) { gp->g_inv = 1; warn_invalid(d,p,EM_P_MTOE); continue; } } if (no_of_ext_partitions(gp->g_p) == 0) in_ext = 0; rp = 0; for (p = &gp->g_p[0]; p <= &gp->g_p[NDOSPARTS - 1]; p++) { if (is_real_parttype(p)) rp = p; else if (is_ext_parttype(p) && (n == 1)) size = p->p_start; } gp = gp->g_next; if (gp->g_ext) { /* * should not happen: a supposedly logical * partition which is an extended p itself. */ gp->g_inv = 1; warn_invalid(d,p,EM_P_LISAE); continue; } else gp->g_log = 1; /* * the p. type in the extended ptbl and the following * logical p. type must be identical. Also check size. */ p = &gp->g_p[0]; if (is_real_parttype(p) && is_same_partition_type(rp,p) && (rp->p_size >= p->p_size)) { if (! is_sane_partentry(d,p,1)) gp->g_inv = 1; else size += gp->g_p[0].p_size + 1; } else { gp->g_inv = 1; warn_invalid(d,p,EM_P_UTS); } } else if (! in_ext) { /* * primary entry. */ gp->g_prim = 1; p = &gp->g_p[0]; if (n == 1) size = p->p_start; if (npp++ >= maxp) { gp->g_inv = 1; warn_invalid(d,p,EM_P_2MANYPP); } else { if (! is_sane_partentry(d,p,1)) { gp->g_inv = 1; warn_invalid(d,p,EM_P_NOTSANE); } else size += p->p_size; } } else { /* * in_ext && !gp->g_ext. This means the end * of the logical partition chain hasn't been * found. Reset it. */ in_ext = 0; gp->g_inv = 1; warn_invalid(d,p,EM_P_ENDNOTF); } } if (epp > 1) pr(WARN,EM_TOOMANYXPTS,epp); if (npp > maxp) pr(WARN,EM_TOOMANYPPTS,maxp,npp); /* * 3. pass: check logical partition chain. Logical * partitions which seem ok but are not found in the * link chain are marked orphaned. */ in_ext = size = ofs = 0; lep = 0; for (gp = d->d_gl; gp; gp = gp->g_next) { if (gp->g_inv) continue; if (gp->g_ext) { if (! in_ext) { in_ext = 1; ofs = gp->g_sec; } rp = ep = 0; for (p = &gp->g_p[0]; p <= &gp->g_p[NDOSPARTS - 1]; p++) { if (is_real_parttype(p)) rp = p; else if (is_ext_parttype(p)) ep = p; } if (lep && rp) if (gp->g_sec != ofs + lep->p_start) gp->g_next->g_orph = 1; if (ep) lep = ep; gp = gp->g_next; } } /* * if the list was consistent the size of the whole * extended ptbl is equal to the end of the last eptbl * link. */ if (rp && lep) size = lep->p_start + lep->p_size; else size = ofs = 0; for (gp = d->d_gl; gp; gp = gp->g_next) { if (gp->g_ext) continue; p = &gp->g_p[0]; if (gp->g_log) pr(MSG," "); pr(MSG,"Partition(%s): ",get_part_type(p->p_typ)); if (gp->g_inv) pr(MSG,PM_G_INVALID); if (gp->g_orph) pr(MSG,PM_G_ORPHANED); if (gp->g_prim) pr(MSG,PM_G_PRIMARY); if (gp->g_log) pr(MSG,PM_G_LOGICAL); pr(MSG,"\n"); if (f_verbose > 1) print_partition(d,p,gp->g_log ? 1 : 0,0); } /* * now fill in the guessed primary partition table. */ in_ext = n = 0; memset(&d->d_gpt,0,sizeof(dos_part_table)); for (gp = d->d_gl; gp; gp = gp->g_next) { if (n >= NDOSPARTS) break; if (gp->g_inv) continue; if (gp->g_ext) { if (! in_ext) { in_ext = 1; if (size && ofs) { p = &d->d_gpt.t_parts[n++]; p->p_start = ofs; p->p_typ = 0x05; p->p_typ = d->d_lba ? 0x0F : 0x05; p->p_size = size; fillin_dos_chs(d,p,0); } } gp = gp->g_next; continue; } if (gp->g_prim) memcpy(&d->d_gpt.t_parts[n++],&gp->g_p[0],sizeof(dos_part_entry)); } /* * final step: re-check this table. If ok, set the * ptbl magic number which is the indicator for * write_primary_ptbl that it seems to be ok. */ ep = 0; npp = 0; for (n = 0; n < NDOSPARTS; n++) { p = &d->d_gpt.t_parts[n]; if (ep && p->p_typ) { if ((ep->p_start + ep->p_size > p->p_start) || ! is_sane_partentry(d,p,1)) { /* * zis is not funny. Perhaps the p. list * can be re-checked but for now only * inconsistencies are counted. */ npp++; if (f_verbose > 2) { pr(WARN,EM_PINCONS); print_partition(d,p,0,0); } } } ep = p; } if (npp == 0) { d->d_gpt.t_magic = le16(DOSPTMAGIC); pr(MSG,"Ok.\n"); } else pr(MSG,DM_NOOFINCONS,npp); return (npp); } /* * compare both existing and guessed partition tables. * The order of the ptbl entries is not important (the * physically first partition on disk can be in the last * ptbl slot). */ static int compare_parttables(disk_desc *d) { int ret, i, j, diff; byte_t *pr, *pg; ret = 0; for (i = 0; i < NDOSPARTS; i++) { pr = (byte_t *)&d->d_pt.t_parts[i]; for (j = 0; j < NDOSPARTS; j++) { pg = (byte_t *)&d->d_gpt.t_parts[j]; /* * the p_flag entry cannot be included * in the comparison. */ diff = memcmp(pr + 1,pg + 1,sizeof(dos_part_entry) - 1); if (diff == 0) break; } if (diff) ret++; } return (ret); } /* * main */ int main(int ac,char **av) { char *optstr = "b:C:cdEefghiK:k:Ll:n:qs:t:VvW:w:"; char *p1, *p2, *p3, *odev = 0, *backup = 0; int opt, sectsize = 0, no_of_incons = 0; disk_desc *d; g_mod_addinternals(); while ((opt = getopt(ac,av,optstr)) != -1) switch (opt) { case 'b' : backup = optarg; break; case 'C' : if (! get_csep_arg(optarg,&p1,&p2,&p3)) { usage(); return (EXIT_FAILURE); } gc = strtoul(p1,0,0); if (errno == ERANGE) pr(FATAL,EM_INVVALUE); gh = strtoul(p2,0,0); if (errno == ERANGE) pr(FATAL,EM_INVVALUE); gs = strtoul(p3,0,0); if (errno == ERANGE) pr(FATAL,EM_INVVALUE); break; case 'c' : f_check = 1; break; case 'd' : f_dontguess = 1; break; case 'E' : f_testext = 0; break; case 'e' : f_skiperrors = 0; break; case 'f' : f_fast = 0; break; case 'g' : f_getgeom = 0; break; case 'i' : f_interactive = 1; break; case 'K' : maxsec = strtoul(optarg,0,0); if ((maxsec <= 0) || (errno == ERANGE)) pr(FATAL,EM_INVVALUE); break; case 'k' : /* strtos64? */ skipsec = strtoul(optarg,0,0); if (errno == ERANGE) pr(FATAL,EM_INVVALUE); break; case 'n' : if ((*optarg == 's') || (*optarg == 'h') || (*optarg == 'c')) increment = *optarg; else { increment = strtoul(optarg,0,0); if (errno == ERANGE) pr(FATAL,EM_INVVALUE); } break; case 'l' : if (logfile) fclose(logfile); if ((logfile = fopen(optarg,"w")) == 0) pr(FATAL,EM_OPENLOG,optarg); break; case 'L' : g_mod_list(); return (EXIT_SUCCESS); case 'q' : f_quiet = 1; break; case 's' : if ((sectsize = atoi(optarg)) <= 0) pr(FATAL,"sector size must be >= 0"); break; case 'v' : f_verbose++; break; case 'V' : fprintf(stderr,"%s\n",gpart_version); return (EXIT_SUCCESS); case 'w' : if (! get_csep_arg(optarg,&p1,&p2,0)) { usage(); return (EXIT_FAILURE); } if (! g_mod_setweight(p1,atof(p2))) pr(FATAL,EM_NOSUCHMOD,p1); break; case 'W' : odev = optarg; break; case '?' : case 'h' : default : usage(); return (EXIT_FAILURE); } if ((optind + 1) != ac) { usage(); return (EXIT_FAILURE); } if (f_dontguess) f_check = 0; if (f_check) { f_quiet = 1; f_dontguess = 0; odev = 0; } if (f_quiet) f_interactive = 0; sync(); d = get_disk_desc(av[optind],sectsize); if (f_verbose > 0) print_disk_desc(d); if (f_verbose > 2) print_mboot_block(d); if (! f_dontguess) { sleep(1); sync(); do_guess_loop(d); no_of_incons = check_partition_list(d); pr(MSG,DM_GUESSEDPTBL); print_ptable(d,&d->d_gpt,0); if ((no_of_incons == 0) && f_check) no_of_incons = compare_parttables(d); if ((no_of_incons == 0) && odev) { if (backup) make_mbr_backup(d,backup); write_primary_ptbl(d,odev); } } free_disk_desc(d); if (logfile) fclose(logfile); return (f_check ? no_of_incons : 0); } gpart-0.3/src/gpart.h000066400000000000000000000067351262504202100145530ustar00rootroot00000000000000/* * gpart.h -- gpart main header file * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _GPART_H #define _GPART_H #include "config.h" #include "errmsgs.h" #include "l64seek.h" #include typedef uint8_t byte_t; #define le16(x) htole16(x) #define be16(x) htobe16(x) #define le32(x) htole32(x) #define be32(x) htobe32(x) #define le64(x) htole64(x) #define be64(x) htobe64(x) #ifndef max # define max(a,b) ((a)>(b)?(a):(b)) # define min(a,b) ((a)<(b)?(a):(b)) #endif #define MINSSIZE (512) /* min. sector size */ #define MAXSSIZE (16384) #define FATAL 1 /* fatal error, exit */ #define ERROR 2 /* non-fatal error */ #define WARN 3 #define MSG 4 /* normal message */ void pr(int,char *,...); ssize_t bread(int,byte_t *,size_t,size_t); byte_t *alloc(ssize_t); /* * dos partition table stuff */ #define DOSMBSECTOR 0 /* absolute sector # of mbr */ #define NDOSPARTS 4 /* # of primary partitions */ #define DOSPARTOFF 446 /* offset of part-table in mbr */ #define DOSPARTACTIVE 0x80 /* active (boot) flag */ #define DOSPTMAGIC 0xaa55 /* signature */ #define DOSCYL(cyl,s) ((cyl)+(((s)&0xc0)<<2)) #define DOSSEC(s) ((s)&0x3f) typedef struct { byte_t p_flag; /* bootstrap flags */ byte_t p_shd; /* starting head */ byte_t p_ssect; /* starting sector */ byte_t p_scyl; /* starting cylinder */ byte_t p_typ; /* partition type */ byte_t p_ehd; /* end head */ byte_t p_esect; /* end sector */ byte_t p_ecyl; /* end cylinder */ uint32_t p_start; /* start sector (absolute) */ uint32_t p_size; /* # of sectors */ } dos_part_entry; typedef struct dos_pt { struct dos_pt *t_ext; /* -> extended parttable */ byte_t _align[2]; byte_t t_boot[DOSPARTOFF]; dos_part_entry t_parts[NDOSPARTS]; uint16_t t_magic; /* DOSPTMAGIC */ } dos_part_table; typedef struct dos_gp { dos_part_entry g_p[NDOSPARTS]; struct dos_gp *g_next; s64_t g_sec; /* found there */ unsigned int g_ext : 1; /* extended ptbl */ unsigned int g_prim : 1; /* primary partition */ unsigned int g_log : 1; /* logical partition */ unsigned int g_inv : 1; /* invalid entry */ unsigned int g_orph : 1; /* orphaned partition */ } dos_guessed_pt; /* * disk description used */ typedef struct { char *d_dev; /* device name */ int d_fd; /* file descriptor when open */ ssize_t d_ssize; /* sector size */ byte_t *d_sbuf; /* sector buffer */ s64_t d_nsecs; /* total no of sectors */ s64_t d_nsb; /* # of first sector in sbuf on disk */ struct disk_geom /* disk geometry */ { long d_c; /* cylinder count */ long d_h; /* heads/cyl */ long d_s; /* sectors/head */ uint64_t d_nsecs; /* Number of sectors total */ } d_dg; unsigned int d_lba : 1; unsigned int d_dosc : 1; /* dos compatible? (g_c < 1024) */ dos_part_table d_pt; /* table of primary partitions */ dos_part_table d_gpt; /* guessed ptbl */ dos_guessed_pt *d_gl; /* list of gathered guesses */ } disk_desc; struct disk_geom *disk_geometry(disk_desc *); int reread_partition_table(int); #define s2mb(d,s) { (s)*=(d)->d_ssize; (s)/=1024; (s)/=1024; } #define align(b,s) (byte_t *)(((size_t)(b)+(s)-1)&~((s)-1)) #include "gmodules.h" #endif /* _GPART_H */ gpart-0.3/src/l64seek.c000066400000000000000000000020701262504202100146720ustar00rootroot00000000000000/* * l64seek.c -- gpart signed 64bit seek * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #include "config.h" /* for large file support */ #include "l64seek.h" #define OSTACKLEN 16 static struct { s64_t fpos; int fd; } ostck[OSTACKLEN]; static int osptr = -1; off64_t l64seek(int fd,off64_t offset,int whence) { off64_t ret = (off64_t)-1; ret = lseek(fd,offset,whence); return (ret); } int l64opush(int fd) { s64_t fpos; if (osptr < OSTACKLEN - 1) { if ((fpos = l64tell(fd)) >= 0) { ostck[++osptr].fd = fd; ostck[osptr].fpos = fpos; return (1); } } return (0); } s64_t l64opop(int fd) { if ((osptr >= 0) && (ostck[osptr].fd == fd)) return (ostck[osptr--].fpos); return (-1); } gpart-0.3/src/l64seek.h000066400000000000000000000015711262504202100147040ustar00rootroot00000000000000/* * l64seek.h -- gpart signed 64bit seek header file * * gpart (c) 1999-2001 Michail Brzitwa * Guess PC-type hard disk partitions. * * gpart 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, or (at your * option) any later version. * * Created: 04.01.1999 * Modified: * */ #ifndef _L64SEEK_H #define _L64SEEK_H #include #include #include /* * define a type 'off64_t' which is at least 64bit, and a * lseek function capable of seeking with at least 64bit * offsets. */ typedef loff_t off64_t; typedef off64_t s64_t; off64_t l64seek(int fd, off64_t offset, int whence); #define l64tell(fd) l64seek(fd,0,SEEK_CUR) int l64opush(int); s64_t l64opop(int); #endif