├── .gitignore ├── .travis.yml ├── COPYING ├── Changes ├── INSTALL ├── LSM ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── man ├── Makefile.am └── gpart.8.in └── src ├── Makefile.am ├── disku.c ├── errmsgs.h ├── gm_beos.c ├── gm_beos.h ├── gm_bsddl.c ├── gm_bsddl.h ├── gm_btrfs.c ├── gm_btrfs.h ├── gm_ext2.c ├── gm_ext2.h ├── gm_fat.c ├── gm_fat.h ├── gm_hmlvm.c ├── gm_hmlvm.h ├── gm_hpfs.c ├── gm_hpfs.h ├── gm_lswap.c ├── gm_lvm2.c ├── gm_lvm2.h ├── gm_minix.c ├── gm_minix.h ├── gm_ntfs.c ├── gm_ntfs.h ├── gm_qnx4.c ├── gm_qnx4.h ├── gm_reiserfs.c ├── gm_reiserfs.h ├── gm_s86dl.c ├── gm_s86dl.h ├── gm_xfs.c ├── gm_xfs.h ├── gmodules.c ├── gmodules.h ├── gpart.c ├── gpart.h ├── l64seek.c └── l64seek.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | src/gpart 3 | Makefile 4 | Makefile.in 5 | aclocal.m4 6 | autom4te.cache/ 7 | compile 8 | config.h 9 | config.h.in 10 | config.log 11 | config.status 12 | configure 13 | depcomp 14 | install-sh 15 | man/gpart.8 16 | missing 17 | .deps/ 18 | stamp-h1 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: false 3 | 4 | script: ./autogen.sh && make 5 | 6 | compiler: 7 | - gcc 8 | - clang 9 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | GNU GENERAL PUBLIC LICENSE 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | 11 | Preamble 12 | 13 | The licenses for most software are designed to take away your 14 | freedom to share and change it. By contrast, the GNU General Public 15 | License is intended to guarantee your freedom to share and change free 16 | software--to make sure the software is free for all its users. This 17 | General Public License applies to most of the Free Software 18 | Foundation's software and to any other program whose authors commit to 19 | using it. (Some other Free Software Foundation software is covered by 20 | the GNU Library General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not 24 | price. Our General Public Licenses are designed to make sure that you 25 | have the freedom to distribute copies of free software (and charge for 26 | this service if you wish), that you receive source code or can get it 27 | if you want it, that you can change the software or use pieces of it 28 | in new free programs; and that you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid 31 | anyone to deny you these rights or to ask you to surrender the rights. 32 | These restrictions translate to certain responsibilities for you if you 33 | distribute copies of the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether 36 | gratis or for a fee, you must give the recipients all the rights that 37 | you have. You must make sure that they, too, receive or can get the 38 | source code. And you must show them these terms so they know their 39 | rights. 40 | 41 | We protect your rights with two steps: (1) copyright the software, and 42 | (2) offer you this license which gives you legal permission to copy, 43 | distribute and/or modify the software. 44 | 45 | Also, for each author's protection and ours, we want to make certain 46 | that everyone understands that there is no warranty for this free 47 | software. If the software is modified by someone else and passed on, we 48 | want its recipients to know that what they have is not the original, so 49 | that any problems introduced by others will not reflect on the original 50 | authors' reputations. 51 | 52 | Finally, any free program is threatened constantly by software 53 | patents. We wish to avoid the danger that redistributors of a free 54 | program will individually obtain patent licenses, in effect making the 55 | program proprietary. To prevent this, we have made it clear that any 56 | patent must be licensed for everyone's free use or not licensed at all. 57 | 58 | The precise terms and conditions for copying, distribution and 59 | modification follow. 60 | 61 | 62 | GNU GENERAL PUBLIC LICENSE 63 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 64 | 65 | 0. This License applies to any program or other work which contains 66 | a notice placed by the copyright holder saying it may be distributed 67 | under the terms of this General Public License. The "Program", below, 68 | refers to any such program or work, and a "work based on the Program" 69 | means either the Program or any derivative work under copyright law: 70 | that is to say, a work containing the Program or a portion of it, 71 | either verbatim or with modifications and/or translated into another 72 | language. (Hereinafter, translation is included without limitation in 73 | the term "modification".) Each licensee is addressed as "you". 74 | 75 | Activities other than copying, distribution and modification are not 76 | covered by this License; they are outside its scope. The act of 77 | running the Program is not restricted, and the output from the Program 78 | is covered only if its contents constitute a work based on the 79 | Program (independent of having been made by running the Program). 80 | Whether that is true depends on what the Program does. 81 | 82 | 1. You may copy and distribute verbatim copies of the Program's 83 | source code as you receive it, in any medium, provided that you 84 | conspicuously and appropriately publish on each copy an appropriate 85 | copyright notice and disclaimer of warranty; keep intact all the 86 | notices that refer to this License and to the absence of any warranty; 87 | and give any other recipients of the Program a copy of this License 88 | along with the Program. 89 | 90 | You may charge a fee for the physical act of transferring a copy, and 91 | you may at your option offer warranty protection in exchange for a fee. 92 | 93 | 2. You may modify your copy or copies of the Program or any portion 94 | of it, thus forming a work based on the Program, and copy and 95 | distribute such modifications or work under the terms of Section 1 96 | above, provided that you also meet all of these conditions: 97 | 98 | a) You must cause the modified files to carry prominent notices 99 | stating that you changed the files and the date of any change. 100 | 101 | b) You must cause any work that you distribute or publish, that in 102 | whole or in part contains or is derived from the Program or any 103 | part thereof, to be licensed as a whole at no charge to all third 104 | parties under the terms of this License. 105 | 106 | c) If the modified program normally reads commands interactively 107 | when run, you must cause it, when started running for such 108 | interactive use in the most ordinary way, to print or display an 109 | announcement including an appropriate copyright notice and a 110 | notice that there is no warranty (or else, saying that you provide 111 | a warranty) and that users may redistribute the program under 112 | these conditions, and telling the user how to view a copy of this 113 | License. (Exception: if the Program itself is interactive but 114 | does not normally print such an announcement, your work based on 115 | the Program is not required to print an announcement.) 116 | 117 | 118 | These requirements apply to the modified work as a whole. If 119 | identifiable sections of that work are not derived from the Program, 120 | and can be reasonably considered independent and separate works in 121 | themselves, then this License, and its terms, do not apply to those 122 | sections when you distribute them as separate works. But when you 123 | distribute the same sections as part of a whole which is a work based 124 | on the Program, the distribution of the whole must be on the terms of 125 | this License, whose permissions for other licensees extend to the 126 | entire whole, and thus to each and every part regardless of who wrote it. 127 | 128 | Thus, it is not the intent of this section to claim rights or contest 129 | your rights to work written entirely by you; rather, the intent is to 130 | exercise the right to control the distribution of derivative or 131 | collective works based on the Program. 132 | 133 | In addition, mere aggregation of another work not based on the Program 134 | with the Program (or with a work based on the Program) on a volume of 135 | a storage or distribution medium does not bring the other work under 136 | the scope of this License. 137 | 138 | 3. You may copy and distribute the Program (or a work based on it, 139 | under Section 2) in object code or executable form under the terms of 140 | Sections 1 and 2 above provided that you also do one of the following: 141 | 142 | a) Accompany it with the complete corresponding machine-readable 143 | source code, which must be distributed under the terms of Sections 144 | 1 and 2 above on a medium customarily used for software interchange; or, 145 | 146 | b) Accompany it with a written offer, valid for at least three 147 | years, to give any third party, for a charge no more than your 148 | cost of physically performing source distribution, a complete 149 | machine-readable copy of the corresponding source code, to be 150 | distributed under the terms of Sections 1 and 2 above on a medium 151 | customarily used for software interchange; or, 152 | 153 | c) Accompany it with the information you received as to the offer 154 | to distribute corresponding source code. (This alternative is 155 | allowed only for noncommercial distribution and only if you 156 | received the program in object code or executable form with such 157 | an offer, in accord with Subsection b above.) 158 | 159 | The source code for a work means the preferred form of the work for 160 | making modifications to it. For an executable work, complete source 161 | code means all the source code for all modules it contains, plus any 162 | associated interface definition files, plus the scripts used to 163 | control compilation and installation of the executable. However, as a 164 | special exception, the source code distributed need not include 165 | anything that is normally distributed (in either source or binary 166 | form) with the major components (compiler, kernel, and so on) of the 167 | operating system on which the executable runs, unless that component 168 | itself accompanies the executable. 169 | 170 | If distribution of executable or object code is made by offering 171 | access to copy from a designated place, then offering equivalent 172 | access to copy the source code from the same place counts as 173 | distribution of the source code, even though third parties are not 174 | compelled to copy the source along with the object code. 175 | 176 | 177 | 4. You may not copy, modify, sublicense, or distribute the Program 178 | except as expressly provided under this License. Any attempt 179 | otherwise to copy, modify, sublicense or distribute the Program is 180 | void, and will automatically terminate your rights under this License. 181 | However, parties who have received copies, or rights, from you under 182 | this License will not have their licenses terminated so long as such 183 | parties remain in full compliance. 184 | 185 | 5. You are not required to accept this License, since you have not 186 | signed it. However, nothing else grants you permission to modify or 187 | distribute the Program or its derivative works. These actions are 188 | prohibited by law if you do not accept this License. Therefore, by 189 | modifying or distributing the Program (or any work based on the 190 | Program), you indicate your acceptance of this License to do so, and 191 | all its terms and conditions for copying, distributing or modifying 192 | the Program or works based on it. 193 | 194 | 6. Each time you redistribute the Program (or any work based on the 195 | Program), the recipient automatically receives a license from the 196 | original licensor to copy, distribute or modify the Program subject to 197 | these terms and conditions. You may not impose any further 198 | restrictions on the recipients' exercise of the rights granted herein. 199 | You are not responsible for enforcing compliance by third parties to 200 | this License. 201 | 202 | 7. If, as a consequence of a court judgment or allegation of patent 203 | infringement or for any other reason (not limited to patent issues), 204 | conditions are imposed on you (whether by court order, agreement or 205 | otherwise) that contradict the conditions of this License, they do not 206 | excuse you from the conditions of this License. If you cannot 207 | distribute so as to satisfy simultaneously your obligations under this 208 | License and any other pertinent obligations, then as a consequence you 209 | may not distribute the Program at all. For example, if a patent 210 | license would not permit royalty-free redistribution of the Program by 211 | all those who receive copies directly or indirectly through you, then 212 | the only way you could satisfy both it and this License would be to 213 | refrain entirely from distribution of the Program. 214 | 215 | If any portion of this section is held invalid or unenforceable under 216 | any particular circumstance, the balance of the section is intended to 217 | apply and the section as a whole is intended to apply in other 218 | circumstances. 219 | 220 | It is not the purpose of this section to induce you to infringe any 221 | patents or other property right claims or to contest validity of any 222 | such claims; this section has the sole purpose of protecting the 223 | integrity of the free software distribution system, which is 224 | implemented by public license practices. Many people have made 225 | generous contributions to the wide range of software distributed 226 | through that system in reliance on consistent application of that 227 | system; it is up to the author/donor to decide if he or she is willing 228 | to distribute software through any other system and a licensee cannot 229 | impose that choice. 230 | 231 | This section is intended to make thoroughly clear what is believed to 232 | be a consequence of the rest of this License. 233 | 234 | 235 | 8. If the distribution and/or use of the Program is restricted in 236 | certain countries either by patents or by copyrighted interfaces, the 237 | original copyright holder who places the Program under this License 238 | may add an explicit geographical distribution limitation excluding 239 | those countries, so that distribution is permitted only in or among 240 | countries not thus excluded. In such case, this License incorporates 241 | the limitation as if written in the body of this License. 242 | 243 | 9. The Free Software Foundation may publish revised and/or new versions 244 | of the General Public License from time to time. Such new versions will 245 | be similar in spirit to the present version, but may differ in detail to 246 | address new problems or concerns. 247 | 248 | Each version is given a distinguishing version number. If the Program 249 | specifies a version number of this License which applies to it and "any 250 | later version", you have the option of following the terms and conditions 251 | either of that version or of any later version published by the Free 252 | Software Foundation. If the Program does not specify a version number of 253 | this License, you may choose any version ever published by the Free Software 254 | Foundation. 255 | 256 | 10. If you wish to incorporate parts of the Program into other free 257 | programs whose distribution conditions are different, write to the author 258 | to ask for permission. For software which is copyrighted by the Free 259 | Software Foundation, write to the Free Software Foundation; we sometimes 260 | make exceptions for this. Our decision will be guided by the two goals 261 | of preserving the free status of all derivatives of our free software and 262 | of promoting the sharing and reuse of software generally. 263 | 264 | NO WARRANTY 265 | 266 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 267 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 268 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 269 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 270 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 271 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 272 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 273 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 274 | REPAIR OR CORRECTION. 275 | 276 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 277 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 278 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 279 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 280 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 281 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 282 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 283 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 284 | POSSIBILITY OF SUCH DAMAGES. 285 | 286 | END OF TERMS AND CONDITIONS 287 | 288 | 289 | Appendix: How to Apply These Terms to Your New Programs 290 | 291 | If you develop a new program, and you want it to be of the greatest 292 | possible use to the public, the best way to achieve this is to make it 293 | free software which everyone can redistribute and change under these terms. 294 | 295 | To do so, attach the following notices to the program. It is safest 296 | to attach them to the start of each source file to most effectively 297 | convey the exclusion of warranty; and each file should have at least 298 | the "copyright" line and a pointer to where the full notice is found. 299 | 300 | 301 | Copyright (C) 19yy 302 | 303 | This program is free software; you can redistribute it and/or modify 304 | it under the terms of the GNU General Public License as published by 305 | the Free Software Foundation; either version 2 of the License, or 306 | (at your option) any later version. 307 | 308 | This program is distributed in the hope that it will be useful, 309 | but WITHOUT ANY WARRANTY; without even the implied warranty of 310 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 311 | GNU General Public License for more details. 312 | 313 | You should have received a copy of the GNU General Public License 314 | along with this program; if not, write to the Free Software 315 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 316 | 317 | Also add information on how to contact you by electronic and paper mail. 318 | 319 | If the program is interactive, make it output a short notice like this 320 | when it starts in an interactive mode: 321 | 322 | Gnomovision version 69, Copyright (C) 19yy name of author 323 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 324 | This is free software, and you are welcome to redistribute it 325 | under certain conditions; type `show c' for details. 326 | 327 | The hypothetical commands `show w' and `show c' should show the appropriate 328 | parts of the General Public License. Of course, the commands you use may 329 | be called something other than `show w' and `show c'; they could even be 330 | mouse-clicks or menu items--whatever suits your program. 331 | 332 | You should also get your employer (if you work as a programmer) or your 333 | school, if any, to sign a "copyright disclaimer" for the program, if 334 | necessary. Here is a sample; alter the names: 335 | 336 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 337 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 338 | 339 | , 1 April 1989 340 | Ty Coon, President of Vice 341 | 342 | This General Public License does not permit incorporating your program into 343 | proprietary programs. If your program is a subroutine library, you may 344 | consider it more useful to permit linking proprietary applications with the 345 | library. If this is what you want to do, use the GNU Library General 346 | Public License instead of this License. 347 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | v0.2.1 2 | - Fix distribution issues that prevented builds of dist tarball 3 | 4 | v0.2 5 | - Import some FreeBSD patches 6 | - Default scan by sector size to handle new 4k alignment method 7 | - Properly consider the real size of the disk to not invalidate partitions 8 | 9 | v0.1i 10 | - Switch to autoconf/automake for cross-platform support 11 | - Integrate patches from distributions to fix build and overflow issues 12 | 13 | v0.1h 14 | - New support for the following filesystems: BeOS, QNX 4.x & SGI XFS. 15 | - Updated Reiser filesystem support (Francis Devereux ). 16 | - Updated LVM support. 17 | - Several small fixes from contributors. 18 | 19 | v0.1g 20 | - For access via raw devices: made writing of guessed table also aligned 21 | (reading has been aligned since 0.1f). 22 | - Fixed stupid copy&paste bug in the partition table check routine. 23 | 24 | v0.1f 25 | - Default scan increment 'h' again. 26 | - Fixed wrong head-boundary condition. 27 | - Introduced possibility to edit guessed partitions. 28 | - Scan now starts on (sectors/head) unless -k was given. 29 | - Length of guessed NTFS partitions now includes NTFS backup boot 30 | sector. 31 | 32 | v0.1e 33 | - Default scan increment now 's', extended ptbl boundary condition 34 | now depends on scan increment (head if 's', else cylinder boundary). 35 | - Added LVM physical volume module (LVM by Heinz Mauelshagen). 36 | 37 | v0.1d 38 | - Cope with short reads/read errors from disk (corrupted sectors etc.). 39 | - When flagging probable partitions 'invalid' give a reason why. 40 | - Fixed buggy ext2 spare superblock location calculation. 41 | 42 | v0.1c 43 | - Don't flag partitions 'invalid' which are smaller than their 44 | partition table entry. 45 | - Fixed buggy rejection of some valid ext2 superblocks. 46 | - Fixed linux swap partition size calculation. 47 | - Added ReiserFS module. 48 | 49 | v0.1b 50 | - First public version. 51 | - Made 'fast' scan the default behaviour (-f enables the complete scan). 52 | - Increased tolerance in recognizing extended partition tables. 53 | 54 | v0.1a 55 | - Initial version. 56 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | gpart Compilation and Installation 3 | 4 | 5 | Up to now a configure script for gpart does not seem necessary, 6 | it should compile under Linux and FreeBSD using GNU cc and GNU 7 | make. 8 | 9 | Steps to compile and install: 10 | 11 | - change the installation directory prefix "prefix" in the 12 | file "inst.defs". The default is "/usr/local". 13 | 14 | - type "make". 15 | - if no errors were encountered, type "make install". 16 | 17 | It is a good idea to read the man page before starting to 18 | play around. 19 | -------------------------------------------------------------------------------- /LSM: -------------------------------------------------------------------------------- 1 | Begin4 2 | Title: gpart 3 | Version: 0.1h 4 | Entered-date: 2000-02-09 5 | Description: A tool which tries to guess the primary partition 6 | table of a PC-type hard disk in case the primary 7 | partition table in sector 0 is damaged, incorrect 8 | or deleted. The guessed table can be written to a 9 | file or device. Supported (guessable) filesystem or 10 | partition types: DOS/Windows FAT, Linux ext2 and 11 | swap, OS/2 HPFS, Windows NTFS, FreeBSD and Solaris/x86 12 | disklabels, Minix FS, QNX 4 FS, Reiser FS, LVM physical 13 | volumes, BeOS FS, SGI XFS. 14 | Keywords: hard disk primary partition table reconstruction 15 | Author: michail@brzitwa.de (Michail Brzitwa) 16 | Maintained-by: michail@brzitwa.de (Michail Brzitwa) 17 | Primary-site: http://home.pages.de/~michab/gpart/ 18 | ~51k gpart-0.1h.tar.gz 19 | Alternate-site: metalab.unc.edu /pub/Linux/system/filesystems 20 | Copying-policy: GPL 21 | End 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | SUBDIRS = src man 3 | 4 | doc_DATA = Changes README.md 5 | EXTRA_DIST = Changes README.md 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gpart 2 | 3 | [![Build Status](https://travis-ci.org/baruch/gpart.svg)](https://travis-ci.org/baruch/gpart) 4 | 5 | Gpart is a small tool which tries to guess what partitions 6 | are on a PC type, MBR-partitioned hard disk in case the 7 | primary partition table was damaged. 8 | 9 | Gpart works by scanning through the device (or file) given on 10 | the command line on a sector basis. Each guessing module is 11 | asked if it thinks a filesystem it knows about could start at 12 | a given sector. Several filesystem guessing modules are built 13 | in. 14 | 15 | Consult the manual page for command line options and usage. 16 | 17 | 18 | ## Installation 19 | 20 | See file *INSTALL*. 21 | 22 | ## Currently recognized partitions/filesystems types 23 | 24 | Modname | Typ | Description 25 | :----------|:----:|:------------ 26 | | fat | 0x01 | Primary DOS with 12 bit FAT 27 | | | 0x04 | Primary DOS with 16 bit FAT (<= 32MB) 28 | | | 0x06 | Primary 'big' DOS (> 32MB) 29 | | | 0x0B | DOS or Windows 95 with 32 bit FAT 30 | | | 0x0C | DOS or Windows 95 with 32 bit FAT, LBA 31 | | ntfs | 0x07 | OS/2 HPFS, NTFS, QNX or Advanced UNIX 32 | | hpfs | 0x07 | OS/2 HPFS, NTFS, QNX or Advanced UNIX 33 | | ext2 | 0x83 | Linux ext2 filesystem 34 | | lswap | 0x82 | Linux swap 35 | | bsddl | 0xA5 | FreeBSD/NetBSD/386BSD 36 | | s86dl | 0x82 | Solaris/x86 disklabel 37 | | minix | 0x80 | Minix V1 38 | | | 0x81 | Minix V2 39 | | reiserfs | 0x83 | ReiserFS filesystem 40 | | hmlvm | 0xFE | Linux LVM physical volumes 41 | | qnx4 | 0x4F | QNX 4.x 42 | | beos | 0xEB | BeOS fs 43 | | xfs | 0x83 | SGI XFS filesystem 44 | | btrfs | 0x83 | BtrFS 45 | | LVM2 | 0x8E | LVM2 46 | 47 | 48 | ## Guessing modules 49 | 50 | Each guessing module must provide three functions callable from 51 | gpart: 52 | 53 | int xxx_init(disk_desc *d,g_module *m) 54 | 55 | > Initialisation function. Will be called before a scan. 56 | > It should return the minimum number of bytes it wants 57 | > to receive for a test. The module should set the 58 | > description of the filesystem/partition type it handles 59 | > in `g_module.m_desc`. If the filesystem/partition type 60 | > included a partition table like first sector (like the 61 | > \*BSD disklabels do), the flag `m_hasptbl` should be set. 62 | > Another flag is `m_notinext` which means the tested type 63 | > cannot reside in a logical partition. 64 | 65 | int xxx_term(disk_desc *d) 66 | 67 | > Termination/cleanup function, called after the scanning 68 | > of the device has been done. 69 | 70 | int xxx_gfun(disk_desc *d,g_module *m) 71 | 72 | > The actual guessing function, called from within the 73 | > scan loop. It should test the plausibility of the 74 | > given sectors, and return its guess in `m->m_guess` (a 75 | > probability between 0 and 1). See existing modules 76 | > for examples. 77 | > 78 | > The given file descriptor `d->d_fd` can be used for seeking 79 | > and reading (see e.g. *gm_ext2.c* which tries to read 80 | > the first spare superblock). If a module is convinced 81 | > that it has found a filesystem/partition start it should 82 | > fill in the assumed begin and size of the partition. 83 | > 84 | > The test performed should not be too pedantic, for 85 | > instance it should not be relied upon that the file- 86 | > system is clean/was properly unmounted. On the other 87 | > hand too much tolerance leads to misguided guesses, 88 | > so a golden middle way must be found. 89 | 90 | 91 | ## Output explanation 92 | 93 | Here is a sample `gpart -v` run on my first IDE hard disk 94 | (comments in block-quotes): 95 | 96 | dev(/dev/hda) mss(512) chs(1232/255/63)(LBA) #s(19792080) size(9664mb) 97 | 98 | > `mss` is the medium sector size, `chs` the geometry retrieved 99 | > from the OS (or from the command line), `#s` is the total 100 | > sector count. 101 | 102 | Primary partition(1) 103 | type: 006(0x06)(Primary 'big' DOS (> 32MB)) (BOOT) 104 | size: 502mb #s(1028097) s(63-1028159) 105 | chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r 106 | hex: 80 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 107 | 108 | > `size`: the size of the partition in megabytes, number of 109 | > sectors and the sector range. 110 | > `chs`: the partition table chs range (`d`) and the real one 111 | > (`r`). If the number of cylinders is less than 1024, both 112 | > are identical. 113 | > `hex`: the hexadecimal representation of the partition entry 114 | > as found in the partition table. 115 | 116 | ... 117 | 118 | Begin scan... 119 | Possible partition(DOS FAT), size(502mb), offset(0mb) 120 | type: 006(0x06)(Primary 'big' DOS (> 32MB)) 121 | size: 502mb #s(1028097) s(63-1028159) 122 | chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r 123 | hex: 00 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 124 | 125 | Possible extended partition at offset(502mb) 126 | Possible partition(Linux ext2), size(31mb), offset(502mb) 127 | type: 131(0x83)(Linux ext2 filesystem) 128 | size: 31mb #s(64196) s(1028223-1092418) 129 | chs: (64/1/1)-(67/254/62)d (64/1/1)-(67/254/62)r 130 | hex: 00 01 01 40 83 FE 3E 43 7F B0 0F 00 C4 FA 00 00 131 | 132 | Possible partition(Linux swap), size(125mb), offset(533mb) 133 | type: 130(0x82)(Linux swap or Solaris/x86) 134 | size: 125mb #s(256976) s(1092483-1349458) 135 | chs: (68/1/1)-(83/254/62)d (68/1/1)-(83/254/62)r 136 | hex: 00 01 01 44 82 FE 3E 53 83 AB 10 00 D0 EB 03 00 137 | 138 | > During the scan phase all found partitions are listed by 139 | > their real type names. The Linux swap partition above is 140 | > recognized as Linux swap but will get the 0x82 partition 141 | > identifier which can be both a Solaris disklabel or a 142 | > Linux swap partition. 143 | > 144 | > When examining the hex values of the first primary partition 145 | > it can be seen that they are identical to the values of the 146 | > actual partition table (good guess) except for the first 147 | > value (0x80 vs. 0x00). This entry denotes the partition 148 | > 'boot' flag which cannot be guessed. 149 | 150 | ... 151 | 152 | End scan. 153 | 154 | Checking partitions... 155 | Partition(Primary 'big' DOS (> 32MB)): primary 156 | Partition(Linux ext2 filesystem): logical 157 | Partition(Linux swap or Solaris/x86): logical 158 | Partition(Linux LVM physical volume): logical 159 | Partition(Linux ext2 filesystem): logical 160 | Partition(DOS or Windows 95 with 32 bit FAT, LBA): logical 161 | Partition(FreeBSD/NetBSD/386BSD): primary 162 | Partition(Linux LVM physical volume): primary 163 | Ok. 164 | 165 | > During the scan phase gpart gathers a simple list of possible 166 | > partitions, the check phase now tries to decide if found 167 | > extended partitions seem consistent, if partitions do not 168 | > overlap etc. Overlapping partitions are silently discarded, 169 | > all remaining ones are given an attribute 'primary', 'logical', 170 | > 'orphaned' or 'invalid'. If gpart is called like `gpart -vv ...`, 171 | > it also tells why it thinks a partition guess is invalid. 172 | > 173 | > If any inconsistencies are found, gpart prints the number 174 | > of remaining inconsistencies, otherwise it says 'Ok.' 175 | 176 | Guessed primary partition table: 177 | Primary partition(1) 178 | type: 006(0x06)(Primary 'big' DOS (> 32MB)) 179 | size: 502mb #s(1028097) s(63-1028159) 180 | chs: (0/1/1)-(63/254/63)d (0/1/1)-(63/254/63)r 181 | hex: 00 01 01 00 06 FE 3F 3F 3F 00 00 00 01 B0 0F 00 182 | 183 | Primary partition(2) 184 | type: 005(0x05)(Extended DOS) 185 | size: 6157mb #s(12611025) s(1028160-13639184) 186 | chs: (64/0/1)-(848/254/63)d (64/0/1)-(848/254/63)r 187 | hex: 00 00 01 40 05 FE FF 50 40 B0 0F 00 D1 6D C0 00 188 | 189 | Primary partition(3) 190 | type: 165(0xA5)(FreeBSD/NetBSD/386BSD) 191 | size: 1396mb #s(2859570) s(13639185-16498754) 192 | chs: (849/0/1)-(1023/254/63)d (849/0/1)-(1026/254/63)r 193 | hex: 00 00 C1 51 A5 FE FF FF 11 1E D0 00 32 A2 2B 00 194 | 195 | Primary partition(4) 196 | type: 254(0xFE)(Linux LVM physical volume) 197 | size: 1608mb #s(3293325) s(16498755-19792079) 198 | chs: (1023/254/63)-(1023/254/63)d (1027/0/1)-(1231/254/63)r 199 | hex: 00 FE FF FF FE FE FF FF 43 C0 FB 00 8D 40 32 00 200 | 201 | > This is a resulting primary partition table. Note that 202 | > the logical partition guesses were only used to create 203 | > the extended partition entry. Up to now gpart cannot 204 | > reconstruct a damaged logical partition chain itself. 205 | > 206 | > If a guessed primary partition table should be written to 207 | > some file or device the user must specify (via the `-W` 208 | > option) which partition gets the active (bootable) one. 209 | 210 | ## Author 211 | 212 | gpart README, Aug 1999, Michail Brzitwa 213 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | aclocal 4 | autoconf 5 | autoheader 6 | automake --add-missing 7 | ./configure 8 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.64]) 5 | AC_INIT(gpart, 0.2.3-dev, https://github.com/baruch/gpart/issues) 6 | AM_INIT_AUTOMAKE([1.11]) 7 | AC_CONFIG_SRCDIR([src/gpart.c]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | AC_PROG_INSTALL 13 | 14 | # Checks for header files. 15 | AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h unistd.h]) 16 | 17 | # Checks for typedefs, structures, and compiler characteristics. 18 | AC_TYPE_INT16_T 19 | AC_TYPE_INT8_T 20 | AC_TYPE_SIZE_T 21 | AC_TYPE_SSIZE_T 22 | AC_TYPE_UINT16_T 23 | AC_TYPE_UINT32_T 24 | AC_TYPE_UINT64_T 25 | AC_TYPE_UINT8_T 26 | 27 | # Checks for library functions. 28 | AC_FUNC_MALLOC 29 | AC_CHECK_FUNCS([getpagesize memset strchr strdup strerror strtoul posix_fadvise]) 30 | 31 | # Configure system services. 32 | AC_SYS_LARGEFILE 33 | 34 | AC_CONFIG_FILES([Makefile 35 | man/Makefile 36 | src/Makefile 37 | man/gpart.8]) 38 | AC_OUTPUT 39 | -------------------------------------------------------------------------------- /man/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = gpart.8 2 | -------------------------------------------------------------------------------- /man/gpart.8.in: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" gpart v@VERSION@ man page (c) Jan 1999 Michail Brzitwa 3 | .\" 4 | .TH GPART 8 "January 2001" "Administration Tools" 5 | .SH NAME 6 | gpart \- guess PC-type hard disk partitions 7 | .SH SYNOPSIS 8 | .B gpart 9 | [options] 10 | .I device 11 | 12 | Options: [\-b ][\-C c,h,s][\-c][\-d][\-E][\-e][\-f] 13 | [\-g][\-h][\-i][\-K ][\-k <# of sectors>] [\-L] 14 | [\-l ][\-n ] [\-q][\-s ] 15 | [\-t ][\-V][\-v] [\-W ][\-w ] 17 | .SH DESCRIPTION 18 | .B gpart 19 | tries to guess which partitions are on a hard disk. 20 | If the primary partition table has been lost, overwritten 21 | or destroyed the partitions still exist on the disk but 22 | the operating system cannot access them. 23 | 24 | .B gpart 25 | ignores the primary partition table and scans the disk 26 | (or disk image, file) sector after sector for several 27 | filesystem/partition types. It does so by "asking" filesystem 28 | recognition modules if they think a given sequence of 29 | sectors resembles the beginning of a filesystem or partition 30 | type. Currently the following filesystem types are known to 31 | .B gpart 32 | (listed by module names) : 33 | 34 | .TP 35 | .I beos 36 | BeOS filesystem type. 37 | .TP 38 | .I bsddl 39 | FreeBSD/NetBSD/386BSD disklabel sub-partitioning 40 | scheme used on Intel platforms. 41 | .TP 42 | .I ext2 43 | Linux second extended filesystem. 44 | .TP 45 | .I fat 46 | MS-DOS FAT12/16/32 "filesystems". 47 | .TP 48 | .I hpfs 49 | IBM OS/2 High Performance filesystem. 50 | .TP 51 | .I hmlvm 52 | Linux LVM physical volumes (LVM by Heinz Mauelshagen). 53 | .TP 54 | .I lswap 55 | Linux swap partitions (versions 0 and 1). 56 | .TP 57 | .I minix 58 | The Minix operating system filesystem type. 59 | .TP 60 | .I ntfs 61 | MS Windows NT/2000 filesystem. 62 | .TP 63 | .I qnx4 64 | QNX 4.x filesystem. 65 | .TP 66 | .I reiserfs 67 | The Reiser filesystem (version 3.5.X, X > 11, 3.6.X). 68 | .TP 69 | .I s86dl 70 | Sun Solaris on Intel platforms uses a sub-partitioning 71 | scheme on PC hard disks similar to the BSD disklabels. 72 | .TP 73 | .I xfs 74 | Silicon Graphic's journalling filesystem for Linux. 75 | .PP 76 | More filesystem guessing modules can be added at 77 | runtime (see the 78 | .I -t 79 | option). Please consult the 80 | .B gpart 81 | README file for detailed explanations on how to create 82 | guessing modules. All modules are accompanied by a guessing 83 | weight factor which denotes how "educated" their guesses 84 | are compared to other modules. This weight can be 85 | changed if a certain module keeps on mis-identifying 86 | a partition. 87 | 88 | Naturally only partitions which have been formatted in 89 | some way can be recognized. If the type of a partition 90 | entry in the primary partition table is changed from 91 | x to y while the filesystem is still of type x, 92 | .B gpart 93 | will also still guess a type x. 94 | 95 | No checks are performed whether a found filesystem 96 | is clean or even consistent/mountable, so it is quite 97 | possible that 98 | .B gpart 99 | may identify partitions which existed prior to the current 100 | partitioning scheme of the disk. Especially on large 101 | disks old file system headers/superblocks may be present 102 | a long time until they are finally overwritten with 103 | user data. 104 | 105 | It should be stressed that 106 | .B gpart 107 | does a very heuristic job, never believe its output 108 | without any plausability checks. It can be easily right 109 | in its guesswork but it can also be terribly wrong. You 110 | have been warned. 111 | 112 | After having found a list of possible partition types, 113 | the list is checked for consistency. For example, a 114 | partition which overlaps with the previous one will be 115 | discarded. All remaining partitions are labelled with 116 | one of the following attributes: "primary", "logical", 117 | "orphaned" or "invalid". 118 | 119 | A partition labelled "orphaned" is a logical partition 120 | which seems ok but is missed in the chain of logical 121 | partitions. This may occur if a logical partition is 122 | deleted from the extended partition table without 123 | overwriting the actual disk space. 124 | 125 | An "invalid" partition is one that cannot be accepted 126 | because of various reasons. If a consistent primary partition 127 | table was created in this process it is printed and 128 | can be written to a file or device. 129 | 130 | .SH EXTENDED PARTITIONS 131 | If the disk/file to be examined consists of primary 132 | partitions only, 133 | .B gpart 134 | has quite a good chance to identify them. Extended 135 | partitions on the other hand can result in a lot of 136 | problems. 137 | 138 | Extended partitions are realized as a linked list of 139 | extended partition tables, each of which include an 140 | entry pointing to a logical partition. The size of an 141 | extended partition depends on where the last logical 142 | partition ends. This means that extended partitions 143 | may include "holes", unallocated disk space which 144 | should only be assigned to logical, not primary partitions. 145 | 146 | .B gpart 147 | tries to do its best to check a found chain of logical 148 | partitions but there are very many possible points of 149 | failure. If "good" fdisk programs are used to create 150 | extended partitions, the resulting tables consist of 151 | a zeroed boot record and the four partition entries 152 | of which at least two should be marked unused. Unfortunately 153 | e.g. the fdisk program shipped with Windows NT does 154 | not seem to zero out the boot record area so 155 | .B gpart 156 | has to be overly tolerant in recognizing extended partition 157 | tables. This tolerance may result in quite stupid 158 | guesses. 159 | 160 | .SH DISK TRANSFERS 161 | If you want to investigate hard disks from other systems 162 | you should note down the geometry (number of cylinders, 163 | heads per cylinder and sectors per head) used for that 164 | disk, and tell 165 | .B gpart 166 | about this geometry. 167 | 168 | Investigating disks from machines with a different 169 | endianness than the scanning one has not been tested 170 | at all, and is currently not recommended. 171 | 172 | .SH LARGE DISKS 173 | .B gpart 174 | relies on the OS reporting the correct disk geometry. 175 | Unfortunately sometimes the OS may report a geometry 176 | smaller the the actual one (e.g. disks with more than 177 | 1024 or 16384 cylinder). 178 | 179 | .B gpart 180 | checks if guessed partitions extend beyond the disk 181 | size and marks those "invalid", but may be mistaken 182 | in case the disk size is calculated from an incorrect 183 | geometry. For instance if a disk with the geometry 184 | 1028/255/63 should be scanned, and the OS reports 185 | 1024/255/63 186 | .B gpart 187 | should be called like 188 | 189 | .RS 190 | gpart \-C 1028,255,63 191 | .RE 192 | 193 | .SH PRECAUTIONS 194 | .B gpart 195 | may be of some help when the primary partition table was 196 | lost or destroyed but it can under 197 | .B no 198 | circumstances replace proper disk/partition table backups. 199 | To save the master boot record (MBR) including the primary 200 | partition table to a file type 201 | 202 | .RS 203 | dd if=/dev/hda of=mbr bs=512 count=1 204 | .RE 205 | 206 | exchanging /dev/hda with the block device name of the 207 | disk in question. This should be done for all disks 208 | in the system. To restore the primary partition table 209 | without overwriting the MBR type 210 | 211 | .RS 212 | dd if=mbr of=/dev/hda bs=1 count=64 skip=446 seek=446 213 | .RE 214 | 215 | .B Warning: 216 | make sure that all parameters are typed as shown and 217 | that the disk device is correct. Failing to do so may 218 | result in severe filesystem corruption. The saved file 219 | should be stored in a safe place like a floppy disk. 220 | 221 | .SH OPTIONS 222 | .IP "-b backupfile" 223 | If the guessed primary partition table seems consistent 224 | and should be written (see the 225 | .I 226 | \-W 227 | option) backup the current MBR into the specified file. 228 | .IP "-C c,h,s" 229 | Set the disk geometry (cylinders, heads, sectors) for 230 | the scan. This is useful if a disk should be scanned 231 | which was partitioned using a different geometry, if the 232 | .I device 233 | is a disk-image or if the disk geometry cannot be retrieved 234 | through the PCs BIOS. No spaces are allowed between the 235 | numbers, unless all three are enclosed in quotes. 236 | .IP -c 237 | Check/compare mode (implies the 238 | .I -q 239 | quiet option). After the scan is done, the resulting 240 | primary partition table is compared to the existing 241 | one. The return code of 242 | .B gpart 243 | then contains the number of differences (0 if they 244 | are identical except for the boot/active flag which 245 | cannot be guessed). This option has no effect if 246 | .I -d 247 | is given on the command line. 248 | .IP -d 249 | Do not start the guessing loop. Useful if the partition 250 | table should be printed (in combination with the 251 | .I -v 252 | option) without actually scanning for partitions. 253 | .IP -E 254 | Do not try to identify extended partition tables. If 255 | there are extended partitions on the given device 256 | .B gpart 257 | will most certainly complain about too many primary 258 | partitions because there can be only four primary 259 | partitions. Existing logical partitions will be listed 260 | as primary ones. 261 | .IP -e 262 | Do not skip disk read errors. If this option is given, 263 | and short disk reads or general disk read errors (EIO) 264 | are encountered, 265 | .B gpart 266 | will exit. If not given, the program tries to continue. 267 | .IP -f 268 | Full scan. When a possible partition is found, 269 | .B gpart 270 | normally skips all sectors this entry seems to occupy 271 | and continues the scan from the end of the last possible 272 | partition. The disk scan can take quite a while if 273 | this option is given, be patient. 274 | .IP -g 275 | Do not try to get the disk geometry from the OS. If the 276 | .I device 277 | is no block or character device but a plain file this 278 | option should be supplied. If the file to be scanned is 279 | an image of a disk, the geometry can be given by the 280 | .I -C 281 | option. 282 | .IP -h 283 | Show some help. 284 | .IP -i 285 | Run interactively. Each time a possible partition is 286 | identified the user is asked for confirmation. 287 | .IP "-K last sector" 288 | Scan only up to the given sector or the end of the file 289 | or device whichever comes first. 290 | .IP "-k sectors" 291 | Skip given number of sectors before the scan. Potentially 292 | useful if a partition is looked for at the end of a 293 | large disk. 294 | .IP -L 295 | List available filesystem/partition type modules and 296 | their weights, then exit. 297 | .IP "-l logfile" 298 | Log output to the given file (even if 299 | .I -q 300 | was supplied). 301 | .IP "-n increment" 302 | Scan increment: number of sectors or "s" for single 303 | sector increment, "h" for an increment of sectors 304 | per head (depends on geometry) or "c" for cylinder 305 | increment. 306 | 307 | The increment also influences the condition where extended 308 | partition tables are searched: if the scan increment 309 | is "s" (i.e. 1) extended partition tables are required 310 | to be on a head boundary, otherwise they must be on a 311 | cylinder boundary. 312 | 313 | If the disk geometry could not be retrieved and no 314 | geometry was given on the command line, the default 315 | increment is one sector. 316 | .IP -q 317 | Quiet/no output mode. However if a logfile was 318 | specified (see 319 | .I -l 320 | option) all output is written to that file. This 321 | option overrides the 322 | .I -i 323 | interactive mode. 324 | .IP "-s sector size" 325 | Preset medium sector size. 326 | .B gpart 327 | tries to find out the sector size but may fail in 328 | doing so. Probed sector sizes are 2^i, i=9..14 329 | (512 to 16384 bytes). The default medium sector 330 | size is 512 bytes. 331 | .IP -V 332 | Show version number. 333 | .IP -v 334 | Be verbose. This option can be given more than 335 | once resulting in quite a lot of information. 336 | .IP "-W device" 337 | Write partition table. If a consistent primary 338 | partition table has been guessed it can be written 339 | to the specified file or device. The supplied device 340 | can be the same as the scanned one. 341 | 342 | Additionally the guessed partition entries can 343 | be edited. No checks are performed on the entered 344 | values, thus the resulting table is allowed to 345 | be highly inconsistent. Please beware. 346 | 347 | .B Warning: 348 | The guessed partition table should be checked 349 | very carefully before writing it back. You can 350 | always write the guessed partition table into a 351 | plain file and write this into sector 0 using 352 | .BR dd (1) 353 | (see section PRECAUTIONS above). 354 | 355 | .IP "-w module name,weight" 356 | Put the given module at the head of the module chain 357 | and assign a new weight to that module. All modules 358 | are given an initial weight of 1.0. A weight of 0 359 | deactivates the filesystem recognition module. Again 360 | no spaces are allowed. 361 | 362 | 363 | .PP 364 | Default settings are "\-n h". 365 | 366 | .SH EXAMPLES 367 | \-\ To scan the first IDE hard disk under Linux using default 368 | settings type 369 | 370 | .RS 371 | gpart /dev/hda 372 | .RE 373 | 374 | \-\ To print the primary partition table of the third IDE 375 | drive without starting the scan loop in FreeBSD type 376 | 377 | .RS 378 | gpart \-vvd /dev/wd2 379 | .RE 380 | .RE 381 | 382 | \-\ If 383 | .BR lilo(8) 384 | was installed in the master boot record (MBR) of a 385 | hard disk it saves the contents of the first sector 386 | in a file called /boot/boot.. To list 387 | the partitions contained in such a file type e.g. 388 | 389 | .RS 390 | gpart \-vdg /boot/boot.0300 391 | .RE 392 | 393 | If the partition table contains an extended partition, 394 | .B gpart 395 | will complain about invalid extended partition tables 396 | because the extended entry points to sectors not within 397 | that file. 398 | 399 | \-\ Usually the first primary partition starts on the 400 | second head. If 401 | .B gpart 402 | cannot identify the first partition properly this may 403 | not be the case. 404 | .B gpart 405 | can be told to start the scan directly from sector one 406 | of the disk, using the sector-wise scan mode: 407 | 408 | .RS 409 | gpart \-k 1 \-n s /dev/hdb 410 | .RE 411 | 412 | \-\ Suppose 413 | .B gpart 414 | identifies an NTFS partition as FAT on a certain 415 | disk. In this situation the "ntfs" module should be 416 | made the first module to be probed and given a 417 | weight higher than the usual weight of 1.0: 418 | 419 | .RS 420 | gpart \-w ntfs,1.5 /dev/hdb 421 | .RE 422 | 423 | To list the available modules and their weights use 424 | the 425 | .I -L 426 | option. 427 | 428 | \-\ Suppose the hard disk contains a lot of virtual machines 429 | and the filesystems inside the VMs isn't used outside. Thereby 430 | deactivating the guessing of those filesystems reduces the 431 | noise and false positives during the scan process. 432 | 433 | Set the module weight to 0 to deactivate guessing it. 434 | 435 | For example: The hard disk is formatted with XFS and EXT3 436 | filesystems only and there are a lot of Windows VMs on these 437 | filesystems. Thereby deactivating of FAT and NTFS guesses 438 | reduce the noise during the scan process and produces a more 439 | accurate guess. 440 | 441 | .RS 442 | gpart \-w fat,0 \-w ntfs,0 /dev/hdb 443 | .RE 444 | 445 | \-\ After having checked the output of 446 | .B gpart 447 | at least thrice, the primary partition table can 448 | be written back to the device this way: 449 | 450 | .RS 451 | gpart \-W /dev/sdc /dev/sdc 452 | .RE 453 | 454 | This of course may be extremely dangerous to your health 455 | and social security, so beware. 456 | 457 | \-\ A hard disk with 63 sectors per head is scanned in 458 | steps of 63 sectors. To perform the scan on every second 459 | head while skipping the first 1008 sectors type 460 | 461 | .RS 462 | gpart \-k 1008 \-n 126 /dev/sda 463 | .RE 464 | 465 | \-\ If you want to see how easily 466 | .B gpart 467 | can be mislead, and how many probable partition starts 468 | are on a disk, search the whole disk really sector by 469 | sector, writing all output to a logfile: 470 | 471 | .RS 472 | gpart \-vvfn s \-ql /tmp/gpart.log /dev/sd2 & 473 | .RE 474 | 475 | Usually 476 | .B gpart 477 | will not be able to produce an educated guess of the 478 | primary partition table in this mode. The logfile 479 | however may contain enough hints to manually reconstruct 480 | the partition table. 481 | 482 | .SH FILES 483 | .I /dev/* 484 | .RS 485 | Hard disk block devices. The naming scheme of hard disk 486 | block devices is OS dependent, consult your system manuals 487 | for more information. 488 | .RE 489 | 490 | .SH DIAGNOSTICS 491 | There are many error message types, all of them should 492 | be self-explanatory. Complain if they are not. 493 | 494 | .SH BUGS 495 | .B gpart 496 | is beta software, so expect buggy behaviour. 497 | 498 | \-\ 499 | .B gpart 500 | only accepts extended partition links with one logical 501 | partition. There may be 502 | .B fdisk 503 | variants out there creating links with up to three 504 | logical partition entries but these are not accepted. 505 | 506 | .SH TO DO 507 | .br 508 | \-\ Support big-endian architectures. 509 | .br 510 | \-\ Test on 64-bit architectures. 511 | .br 512 | \-\ Look for boot manager partitions (e.g. OS/2 BM). 513 | .br 514 | \-\ Think about reconstructing logical partition chains. 515 | 516 | .SH AUTHOR 517 | Please send bug reports, suggestions, comments etc. to 518 | 519 | .RS 520 | Michail Brzitwa 521 | .RE 522 | 523 | .SH "SEE ALSO" 524 | .BR fdisk (8). 525 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -Wall -O2 2 | AM_LDFLAGS = 3 | 4 | sbin_PROGRAMS = gpart 5 | 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 6 | 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 7 | -------------------------------------------------------------------------------- /src/disku.c: -------------------------------------------------------------------------------- 1 | /* 2 | * disku.c -- gpart disk util routines 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 13.12.2000 14 | * Calculation of disk cylinder count changed for Linux. 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "gpart.h" 24 | 25 | #if defined(__linux__) 26 | #include 27 | #include 28 | #endif 29 | 30 | #if defined(__FreeBSD__) 31 | #include 32 | #include 33 | #include 34 | #endif 35 | 36 | #include 37 | 38 | static void geometry_from_num_sectors(struct disk_geom *g, uint64_t nsects) 39 | { 40 | const uint64_t lba = nsects - 1; 41 | 42 | g->d_h = (lba / 63) % 255; 43 | g->d_s = lba % 63 + 1; 44 | g->d_c = lba / (255 * 63); 45 | g->d_nsecs = nsects; 46 | } 47 | 48 | #if defined(__linux__) 49 | static void os_disk_geometry(disk_desc *d, struct disk_geom *g) 50 | { 51 | struct hd_geometry hg; 52 | uint64_t nsects; 53 | 54 | if (ioctl(d->d_fd, HDIO_GETGEO, &hg) == -1) 55 | pr(FATAL, EM_IOCTLFAILED, "HDIO_GETGEO", strerror(errno)); 56 | else { 57 | g->d_h = hg.heads; 58 | g->d_s = hg.sectors; 59 | g->d_c = hg.cylinders; 60 | } 61 | #ifdef BLKGETSIZE 62 | if (ioctl(d->d_fd, BLKGETSIZE, &nsects) == -1) 63 | pr(FATAL, EM_IOCTLFAILED, "BLKGETSIZE", strerror(errno)); 64 | else { 65 | if (hg.heads && hg.sectors) 66 | g->d_c = nsects / (hg.heads * hg.sectors); 67 | else 68 | geometry_from_num_sectors(g, nsects); 69 | } 70 | #endif 71 | } 72 | #elif defined(__FreeBSD__) 73 | static void os_disk_geometry(disk_desc *d, struct disk_geom *g) 74 | { 75 | struct disklabel dl; 76 | struct disklabel loclab; 77 | u_int u; 78 | off_t o; /* total disk size */ 79 | 80 | if (ioctl(d->d_fd, DIOCGFWSECTORS, &u) == 0) 81 | g.d_s = u; 82 | else 83 | pr(FATAL, EM_IOCTLFAILED, "DIOCGFWSECTORS", strerror(errno)); 84 | // loclab.d_nsectors = 63; 85 | if (ioctl(d->d_fd, DIOCGFWHEADS, &u) == 0) 86 | g.d_h = u; 87 | else 88 | pr(FATAL, EM_IOCTLFAILED, "DIOCGFWHEADS", strerror(errno)); 89 | if (ioctl(d->d_fd, DIOCGSECTORSIZE, &u) == 0) 90 | if (u != 512) 91 | pr(FATAL, "sector size not a multiple of 512"); 92 | if (ioctl(d->d_fd, DIOCGMEDIASIZE, &o)) 93 | pr(FATAL, EM_IOCTLFAILED, "DIOCGMEDIASIZE", strerror(errno)); 94 | 95 | g.d_nsecs = o / u; 96 | g.d_c = g.d_nsecs / g.d_h / g.d_s; 97 | } 98 | #else 99 | #error Only Linux and FreeBSD supported 100 | #endif 101 | 102 | /* 103 | * get disk geometry. The medium is opened for reading, 104 | * descriptor in d_fd. 105 | */ 106 | 107 | struct disk_geom *disk_geometry(disk_desc *d) 108 | { 109 | static struct disk_geom g; 110 | uint64_t nsects; 111 | struct stat st; 112 | int ret; 113 | 114 | memset(&g, 0, sizeof(g)); 115 | 116 | ret = stat(d->d_dev, &st); 117 | if (ret == 0 && S_ISREG(st.st_mode)) { 118 | // We have something, we'll use it for a first fill of the data 119 | nsects = st.st_size / 512; 120 | if (nsects == 0) 121 | pr(FATAL, EM_FATALERROR, "Not a block device image file"); 122 | geometry_from_num_sectors(&g, nsects); 123 | return (&g); 124 | } 125 | 126 | os_disk_geometry(d, &g); 127 | return (&g); 128 | } 129 | 130 | /* 131 | * tell the OS to reread a changed partition table. Do 132 | * nothing if there is no such possibility. 133 | */ 134 | 135 | int reread_partition_table(int fd) 136 | { 137 | #if defined(__linux__) && defined(BLKRRPART) 138 | if (ioctl(fd, BLKRRPART) == -1) { 139 | pr(ERROR, "rereading partition table: %s", strerror(errno)); 140 | return (0); 141 | } 142 | #endif 143 | 144 | return (1); 145 | } 146 | -------------------------------------------------------------------------------- /src/errmsgs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * errmsgs.h -- gpart error/warning messages header file 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _ERRMSGS_H 18 | #define _ERRMSGS_H 19 | 20 | 21 | /* dialog messages */ 22 | #define DM_YESNO "(y,n)" 23 | #define DM_YES "yY" 24 | #define DM_NUMORQUIT " (%d..%d, q to quit) : " 25 | #define DM_QUIT "qQ" 26 | #define DM_STARTSCAN "\nBegin scan...\n" 27 | #define DM_ENDSCAN "End scan.\n" 28 | #define DM_EDITPTBL "Edit this table" 29 | #define DM_ACCEPTGUESS "\nAccept this guess" 30 | #define DM_ACTWHICHPART "Activate which partition" 31 | #define DM_EDITWHICHPART "Edit which partition" 32 | #define DM_WRITEIT "Write this partition table" 33 | #define DM_ASKTOREBOOT "partition table written, you should reboot now" 34 | #define DM_NOTWRITTEN "Partition table not written\n" 35 | #define DM_STARTCHECK "\nChecking partitions...\n" 36 | #define DM_NOOFINCONS "Number of inconsistencies found: %d.\n" 37 | #define DM_GUESSEDPTBL "\nGuessed primary partition table:\n" 38 | #define DM_NOCHECKWARNING "\nWarning: entered values will not be checked; enter at your own risk!\n" 39 | #define DM_EDITWHICHITEM "\nEdit which value" 40 | 41 | /* partition list messages */ 42 | #define PM_DEVDESC1 "\ndev(%s) mss(%d)" 43 | #define PM_DEVDESC2 " chs(%d/%d/%d)%s#s(%qd) size(%qdmb)" 44 | #define PM_MBRPRINT "\ndev(%s) master boot record (w/o partition table):\n" 45 | #define PM_PRIMPART "Primary partition(%d)\n" 46 | #define PM_EXTPART " Logical partition\n" 47 | #define PM_POSSIBLEPART "Possible partition(%s), size(%qdmb), offset(%qdmb)\n" 48 | #define PM_POSSIBLEEXTPART "Possible extended partition at offset(%qdmb)\n" 49 | #define PM_PT_TYPE " type: %03d(0x%02X)(%s)" 50 | #define PM_PT_SIZE " size: %qdmb #s(%qd)" 51 | #define PM_PT_CHS " chs: (%d/%d/%d)-(%d/%d/%d)d" 52 | #define PM_PT_HEX " hex: " 53 | #define PM_G_PRIMARY "primary " 54 | #define PM_G_LOGICAL "logical " 55 | #define PM_G_INVALID "invalid " 56 | #define PM_G_ORPHANED "orphaned " 57 | #define PM_EDITITEM1 "1 - Absolute start sector (%12lu)\n" 58 | #define PM_EDITITEM2 "2 - Absolute sector count (%12lu)\n" 59 | #define PM_EDITITEM3 "3 - Partition type (%12d)(%s)\n" 60 | 61 | /* error/warning messages */ 62 | #define EM_FATALERROR "\n*** Fatal error: %s.\n" 63 | #define EM_SIMPLEERROR "\n** Error: %s.\n" 64 | #define EM_WARNING "\n* Warning: %s.\n" 65 | #define EM_PINVALID "\n* Partition invalid(%s):\n" 66 | #define EM_MALLOCFAILED "malloc(%d) failed" 67 | #define EM_IOCTLFAILED "ioctl(%s) failed: %s" 68 | #define EM_OPENFAIL "open(%s): %s" 69 | #define EM_STRANGEPTBLMAGIC "strange partition table magic 0x%04X" 70 | #define EM_WRONGSECTSIZE "sector size must be > 0 and <= %d" 71 | #define EM_FAILSSIZEATTEMPT "failed trying to use sector size %d" 72 | #define EM_SEEKFAILURE "dev(%s): seek failure" 73 | #define EM_STATFAILURE "stat(%s): %s" 74 | #define EM_READERROR "dev(%s): read error near sector(%qd): %s" 75 | #define EM_CANTGETSSIZE "cannot get sector size on dev(%s)" 76 | #define EM_CANTGETGEOM "cannot get disk geometry" 77 | #define EM_MINITFAILURE "module(%s) failed to init" 78 | #define EM_INVVALUE "invalid number value" 79 | #define EM_PSTART2BIG "partition(%s) starts beyond disk end" 80 | #define EM_PSIZE2BIG "partition(%s) is bigger than the disk" 81 | #define EM_PEND2BIG "partition(%s) ends beyond disk end" 82 | #define EM_STRANGEPTYPE "partition(%s) contains strange flag" 83 | #define EM_PTBLREAD "failed to read partition table" 84 | #define EM_PTBLWRITE "could not write partition table" 85 | #define EM_MBRWRITE "could not write master boot record" 86 | #define EM_TOOMANYEXTP "found more than one extended partition, skipping" 87 | #define EM_TOOMANYLOGP "more than %d logical partitions encountered" 88 | #define EM_EPILLEGALOFS "extended ptbl illegal sector offset" 89 | #define EM_INVXPTBL "invalid extended ptbl found at sector(%qd)" 90 | #define EM_DISCARDOVLP "Discarded %d overlapping partition guesses" 91 | #define EM_TOOMANYXPTS "more than one extended partition: %d" 92 | #define EM_TOOMANYPPTS "more than %d primary partitions: %d" 93 | #define EM_OPENLOG "cannot open logfile %s" 94 | #define EM_NOSUCHMOD "no such module: %s" 95 | #define EM_SHORTBREAD "short read near sector(%qd), %d bytes instead of %d. Skipping.." 96 | #define EM_BADREADIO "read error (EIO) near sector(%qd), skipping.." 97 | #define EM_PINCONS "partition still overlaps with previous one or seems invalid:" 98 | #define EM_P_EATEND "extended ptbl without any following partitions" 99 | #define EM_P_EWLP "extended ptbl without logical partition" 100 | #define EM_P_MTOE "encountered a second extended ptbl" 101 | #define EM_P_LISAE "logical partition is an extended partition" 102 | #define EM_P_UTS "wrong size, no valid type or (ptbl,link) type mismatch" 103 | #define EM_P_2MANYPP "too many primary partitions" 104 | #define EM_P_NOTSANE "invalid partition entry (see comments above)" 105 | #define EM_P_ENDNOTF "primary partition within extended ptbl link" 106 | 107 | 108 | #endif /* _ERRMSGS_H */ 109 | -------------------------------------------------------------------------------- /src/gm_beos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_beos.c -- gpart BeOS filesystem guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 29.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include "gpart.h" 21 | #include "gm_beos.h" 22 | 23 | #include 24 | 25 | int beos_init(disk_desc *d, g_module *m) 26 | { 27 | if ((d == 0) || (m == 0)) 28 | return (0); 29 | m->m_desc = "BeOS filesystem"; 30 | return (2 * 512); 31 | } 32 | 33 | int beos_term(disk_desc *d) { return (1); } 34 | 35 | int beos_gfun(disk_desc *d, g_module *m) 36 | { 37 | beos_super_block *sb; 38 | s64_t size; 39 | 40 | m->m_guess = GM_NO; 41 | 42 | /* 43 | * BeOS superblock without little/big endian conversions 44 | */ 45 | 46 | sb = (beos_super_block *)(d->d_sbuf + 512); 47 | if ((sb->magic1 != BEOS_SUPER_BLOCK_MAGIC1) || (sb->magic2 != BEOS_SUPER_BLOCK_MAGIC2) || 48 | (sb->magic3 != BEOS_SUPER_BLOCK_MAGIC3)) 49 | return (1); 50 | 51 | /* 52 | * some consistency checks 53 | */ 54 | 55 | if ((sb->block_size != 1024) && (sb->block_size != 2048) && (sb->block_size != 4096) && (sb->block_size != 8192)) 56 | return (1); 57 | 58 | if (sb->block_size != 1 << sb->block_shift) 59 | return (1); 60 | 61 | if (sb->num_blocks < sb->used_blocks) 62 | return (1); 63 | 64 | if ((sb->flags != BEOS_CLEAN) && (sb->flags != BEOS_DIRTY)) 65 | return (1); 66 | 67 | /* 68 | * I hope this is enough, if not I have to read the root dir 69 | * as well later. 70 | */ 71 | 72 | size = sb->num_blocks; 73 | size *= sb->block_size; 74 | size /= d->d_ssize; 75 | m->m_guess = GM_YES; 76 | m->m_part.p_typ = 0xEB; 77 | m->m_part.p_start = d->d_nsb; 78 | m->m_part.p_size = (unsigned long)size; 79 | 80 | return (1); 81 | } 82 | -------------------------------------------------------------------------------- /src/gm_beos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_beos.h -- gpart BeOS filesystem guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 29.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_BEOS_H 18 | #define _GM_BEOS_H 19 | 20 | /* imported from asm/types.h */ 21 | typedef __signed__ char __s8; 22 | typedef unsigned char __u8; 23 | 24 | typedef __signed__ short __s16; 25 | typedef unsigned short __u16; 26 | 27 | typedef __signed__ int __s32; 28 | typedef unsigned int __u32; 29 | 30 | /* 31 | * BeOS filesystem structures, taken from "BEOS filesystem for Linux 1999-05-28" 32 | * by Makoto Kato 33 | */ 34 | 35 | /* 36 | * Flags of superblock 37 | */ 38 | 39 | #define BEOS_CLEAN 0x434c454e 40 | #define BEOS_DIRTY 0x44495254 41 | 42 | /* 43 | * Magic headers of BEOS's superblock, inode and index 44 | */ 45 | 46 | #define BEOS_SUPER_BLOCK_MAGIC1 0x42465331 /* BEOS1 */ 47 | #define BEOS_SUPER_BLOCK_MAGIC2 0xdd121031 48 | #define BEOS_SUPER_BLOCK_MAGIC3 0x15b6830e 49 | #define BEOS_INODE_MAGIC1 0x3bbe0ad9 50 | #define BEOS_INDEX_MAGIC 0x69f6c2e8 51 | #define BEOS_SUPER_MAGIC BEOS_SUPER_BLOCK_MAGIC1 52 | #define BEOS_NUM_DIRECT_BLOCKS 12 53 | #define BEOS_NAME_LENGTH 32 54 | 55 | /* 56 | * BEOS filesystem type 57 | */ 58 | 59 | #define BEOS_PPC 1 60 | #define BEOS_X86 2 61 | 62 | /* 63 | * special type of BEOS 64 | */ 65 | 66 | typedef s64_t beos_off_t; 67 | typedef s64_t beos_bigtime_t; 68 | typedef void beos_binode_etc; 69 | 70 | typedef struct _beos_block_run { 71 | __u32 allocation_group; 72 | __u16 start; 73 | __u16 len; 74 | } beos_block_run; 75 | 76 | typedef beos_block_run beos_inode_addr; 77 | 78 | /* 79 | * The Superblock Structure 80 | */ 81 | 82 | typedef struct _beos_super_block { 83 | char name[BEOS_NAME_LENGTH]; 84 | __u32 magic1; 85 | __u32 fs_byte_order; 86 | 87 | __u32 block_size; 88 | __u32 block_shift; 89 | 90 | beos_off_t num_blocks; 91 | beos_off_t used_blocks; 92 | 93 | __u32 inode_size; 94 | 95 | __u32 magic2; 96 | __u32 blocks_per_ag; 97 | __u32 ag_shift; 98 | __u32 num_ags; 99 | 100 | __u32 flags; 101 | 102 | beos_block_run log_blocks; 103 | beos_off_t log_start; 104 | beos_off_t log_end; 105 | 106 | __u32 magic3; 107 | beos_inode_addr root_dir; 108 | beos_inode_addr indices; 109 | 110 | __u32 pad[8]; 111 | } __attribute__((packed)) beos_super_block; 112 | 113 | #endif /* _GM_BEOS_H */ 114 | -------------------------------------------------------------------------------- /src/gm_bsddl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_bsddl.c -- gpart BSD disk label guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include "gpart.h" 18 | #include "gm_bsddl.h" 19 | 20 | int bsddl_init(disk_desc *d, g_module *m) 21 | { 22 | if ((d == 0) || (m == 0)) 23 | return (0); 24 | m->m_desc = "*BSD disklabel"; 25 | m->m_hasptbl = 1; 26 | m->m_notinext = 1; 27 | return (BBSIZE); 28 | } 29 | 30 | int bsddl_term(disk_desc *d) { return (1); } 31 | 32 | int bsddl_gfun(disk_desc *d, g_module *m) 33 | { 34 | struct disklabel *dl; 35 | struct partition *bsdpt; 36 | unsigned short *cp, *ep, cs1, cs2; 37 | 38 | m->m_guess = GM_NO; 39 | dl = (struct disklabel *)(d->d_sbuf + LABELSECTOR * d->d_ssize); 40 | if ((dl->d_magic == le32(DISKMAGIC)) && (dl->d_magic2 == le32(DISKMAGIC))) { 41 | /* 42 | * partition RAW_PART(2) usually denotes the whole disk (slice) 43 | */ 44 | 45 | if (dl->d_npartitions <= RAW_PART) 46 | return (1); 47 | bsdpt = &dl->d_partitions[RAW_PART]; 48 | 49 | /* 50 | * some sanity checks: disklabel checksum and start 51 | * of partition. 52 | */ 53 | 54 | cs1 = 0; 55 | cs2 = le16(dl->d_checksum); 56 | dl->d_checksum = 0; 57 | cp = (unsigned short *)dl; 58 | ep = (unsigned short *)&dl->d_partitions[dl->d_npartitions]; 59 | for (; cp < ep; cp++) 60 | cs1 ^= le16(*cp); 61 | dl->d_checksum = le16(cs2); 62 | 63 | if ((le32(bsdpt->p_offset) == d->d_nsb) && (cs1 == cs2)) { 64 | m->m_part.p_typ = 0xA5; 65 | m->m_part.p_start = le32(bsdpt->p_offset); 66 | m->m_part.p_size = le32(bsdpt->p_size); 67 | m->m_guess = GM_YES; 68 | } 69 | } 70 | return (1); 71 | } 72 | -------------------------------------------------------------------------------- /src/gm_bsddl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_bsddl.h -- gpart BSD disk label guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_BSDDL_H 18 | #define _GM_BSDDL_H 19 | 20 | /* 21 | * BSD 4.4 disklabel support. Copied from the sources of the 22 | * FreeBSD (2.2.7) disklabel(8) program sources. These sources 23 | * are under the BSD licence, not the GPL. Please see http:// 24 | * www.freebsd.org/ for copyright/licence notes. 25 | */ 26 | 27 | #define STANDALONE 28 | 29 | #define BBSIZE 8192 /* size of boot area, with label */ 30 | 31 | #ifdef __i386__ 32 | #define LABELSECTOR 1 /* sector containing label */ 33 | #define LABELOFFSET 0 /* offset of label in sector */ 34 | #endif 35 | 36 | #ifndef LABELSECTOR 37 | #define LABELSECTOR 0 /* sector containing label */ 38 | #endif 39 | 40 | #ifndef LABELOFFSET 41 | #define LABELOFFSET 64 /* offset of label in sector */ 42 | #endif 43 | 44 | #define DISKMAGIC ((u_int32_t)0x82564557) /* The disk magic number */ 45 | #ifndef MAXPARTITIONS 46 | #define MAXPARTITIONS 8 47 | #endif 48 | 49 | #define LABEL_PART 2 /* partition containing label */ 50 | #define RAW_PART 2 /* partition containing whole disk */ 51 | #define SWAP_PART 1 /* partition normally containing swap */ 52 | 53 | struct disklabel { 54 | u_int32_t d_magic; /* the magic number */ 55 | u_int16_t d_type; /* drive type */ 56 | u_int16_t d_subtype; /* controller/d_type specific */ 57 | char d_typename[16]; /* type name, e.g. "eagle" */ 58 | 59 | /* 60 | * d_packname contains the pack identifier and is returned when 61 | * the disklabel is read off the disk or in-core copy. 62 | * d_boot0 and d_boot1 are the (optional) names of the 63 | * primary (block 0) and secondary (block 1-15) bootstraps 64 | * as found in /usr/mdec. These are returned when using 65 | * getdiskbyname(3) to retrieve the values from /etc/disktab. 66 | */ 67 | #if defined(KERNEL) || defined(STANDALONE) 68 | char d_packname[16]; /* pack identifier */ 69 | #else 70 | union { 71 | char un_d_packname[16]; /* pack identifier */ 72 | struct { 73 | char *un_d_boot0; /* primary bootstrap name */ 74 | char *un_d_boot1; /* secondary bootstrap name */ 75 | } un_b; 76 | } d_un; 77 | #define d_packname d_un.un_d_packname 78 | #define d_boot0 d_un.un_b.un_d_boot0 79 | #define d_boot1 d_un.un_b.un_d_boot1 80 | #endif /* ! KERNEL or STANDALONE */ 81 | 82 | /* disk geometry: */ 83 | u_int32_t d_secsize; /* # of bytes per sector */ 84 | u_int32_t d_nsectors; /* # of data sectors per track */ 85 | u_int32_t d_ntracks; /* # of tracks per cylinder */ 86 | u_int32_t d_ncylinders; /* # of data cylinders per unit */ 87 | u_int32_t d_secpercyl; /* # of data sectors per cylinder */ 88 | u_int32_t d_secperunit; /* # of data sectors per unit */ 89 | 90 | /* 91 | * Spares (bad sector replacements) below are not counted in 92 | * d_nsectors or d_secpercyl. Spare sectors are assumed to 93 | * be physical sectors which occupy space at the end of each 94 | * track and/or cylinder. 95 | */ 96 | u_int16_t d_sparespertrack; /* # of spare sectors per track */ 97 | u_int16_t d_sparespercyl; /* # of spare sectors per cylinder */ 98 | /* 99 | * Alternate cylinders include maintenance, replacement, configuration 100 | * description areas, etc. 101 | */ 102 | u_int32_t d_acylinders; /* # of alt. cylinders per unit */ 103 | 104 | /* hardware characteristics: */ 105 | /* 106 | * d_interleave, d_trackskew and d_cylskew describe perturbations 107 | * in the media format used to compensate for a slow controller. 108 | * Interleave is physical sector interleave, set up by the 109 | * formatter or controller when formatting. When interleaving is 110 | * in use, logically adjacent sectors are not physically 111 | * contiguous, but instead are separated by some number of 112 | * sectors. It is specified as the ratio of physical sectors 113 | * traversed per logical sector. Thus an interleave of 1:1 114 | * implies contiguous layout, while 2:1 implies that logical 115 | * sector 0 is separated by one sector from logical sector 1. 116 | * d_trackskew is the offset of sector 0 on track N relative to 117 | * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew 118 | * is the offset of sector 0 on cylinder N relative to sector 0 119 | * on cylinder N-1. 120 | */ 121 | u_int16_t d_rpm; /* rotational speed */ 122 | u_int16_t d_interleave; /* hardware sector interleave */ 123 | u_int16_t d_trackskew; /* sector 0 skew, per track */ 124 | u_int16_t d_cylskew; /* sector 0 skew, per cylinder */ 125 | u_int32_t d_headswitch; /* head switch time, usec */ 126 | u_int32_t d_trkseek; /* track-to-track seek, usec */ 127 | u_int32_t d_flags; /* generic flags */ 128 | #define NDDATA 5 129 | u_int32_t d_drivedata[NDDATA]; /* drive-type specific information */ 130 | #define NSPARE 5 131 | u_int32_t d_spare[NSPARE]; /* reserved for future use */ 132 | u_int32_t d_magic2; /* the magic number (again) */ 133 | u_int16_t d_checksum; /* xor of data incl. partitions */ 134 | 135 | /* filesystem and partition information: */ 136 | u_int16_t d_npartitions; /* number of partitions in following */ 137 | u_int32_t d_bbsize; /* size of boot area at sn0, bytes */ 138 | u_int32_t d_sbsize; /* max size of fs superblock, bytes */ 139 | struct partition { /* the partition table */ 140 | u_int32_t p_size; /* number of sectors in partition */ 141 | u_int32_t p_offset; /* starting sector */ 142 | u_int32_t p_fsize; /* filesystem basic fragment size */ 143 | u_int8_t p_fstype; /* filesystem type, see below */ 144 | u_int8_t p_frag; /* filesystem fragments per block */ 145 | union { 146 | u_int16_t cpg; /* UFS: FS cylinders per group */ 147 | u_int16_t sgs; /* LFS: FS segment shift */ 148 | } __partition_u1; 149 | #define p_cpg __partition_u1.cpg 150 | #define p_sgs __partition_u1.sgs 151 | } d_partitions[MAXPARTITIONS]; /* actually may be more */ 152 | }; 153 | 154 | #endif /* _GM_BSDDL_H */ 155 | -------------------------------------------------------------------------------- /src/gm_btrfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_btrfs.c -- gpart Linux Btrfs volume guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 20.11.2015 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include "gpart.h" 20 | #include "gm_btrfs.h" 21 | 22 | int btrfs_init(disk_desc *d, g_module *m) 23 | { 24 | if ((d == 0) || (m == 0)) 25 | return (0); 26 | 27 | m->m_desc = "Btrfs volume"; 28 | return BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE; 29 | } 30 | 31 | int btrfs_term(disk_desc *d) { return (1); } 32 | 33 | int btrfs_gfun(disk_desc *d, g_module *m) 34 | { 35 | struct btrfs_super_block *sb; 36 | dos_part_entry *pt = &m->m_part; 37 | s64_t psize; 38 | 39 | m->m_guess = GM_NO; 40 | sb = (struct btrfs_super_block *)(d->d_sbuf + BTRFS_SUPER_INFO_OFFSET); 41 | 42 | if (le64toh(sb->magic) != BTRFS_MAGIC) 43 | return 1; 44 | 45 | if (memcmp(sb->fsid, sb->dev_item.fsid, BTRFS_FSID_SIZE)) 46 | return 1; 47 | 48 | psize = le64toh(sb->dev_item.total_bytes); 49 | if (psize > btrfs_sb_offset(1)) { 50 | struct btrfs_super_block sb_copy; 51 | if (l64seek(d->d_fd, d->d_nsb * d->d_ssize + btrfs_sb_offset(1), SEEK_SET) == -1) 52 | pr(FATAL, "btrfs: cannot seek: %s", strerror(errno)); 53 | read(d->d_fd, &sb_copy, sizeof(sb_copy)); 54 | if (le64toh(sb_copy.magic) != BTRFS_MAGIC || memcmp(sb->fsid, sb_copy.fsid, BTRFS_FSID_SIZE)) { 55 | pr(MSG, "btrfs: superblock copy mismatch\n"); 56 | return 1; 57 | } 58 | } 59 | 60 | m->m_guess = GM_YES; 61 | pt->p_start = d->d_nsb; 62 | pt->p_size = psize / d->d_ssize; 63 | pt->p_typ = 0x83; 64 | 65 | return 1; 66 | } 67 | -------------------------------------------------------------------------------- /src/gm_btrfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_btrfs.h -- gpart Btrfs volume guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 20.11.2015 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_BTRFS_H 18 | #define _GM_BTRFS_H 19 | 20 | /* 21 | * structs & defines gathered from btrfs-progs 22 | */ 23 | 24 | #if !defined(__FreeBSD__) 25 | typedef unsigned char uint8_t; 26 | typedef unsigned short uint16_t; 27 | typedef unsigned int uint32_t; 28 | #endif 29 | 30 | typedef uint64_t __le64; 31 | typedef uint32_t __le32; 32 | typedef uint16_t __le16; 33 | typedef uint8_t u8; 34 | 35 | #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) 36 | #define BTRFS_SUPER_INFO_SIZE 4096 37 | #define btrfs_sb_offset(i) ((i) ? ((16 * 1024) << (BTRFS_SUPER_MIRROR_SHIFT * (i))) : BTRFS_SUPER_INFO_SIZE) 38 | #define BTRFS_SUPER_MIRROR_SHIFT 12 39 | #define BTRFS_CSUM_SIZE 32 40 | #define BTRFS_FSID_SIZE 16 41 | #define BTRFS_UUID_SIZE 16 42 | #define BTRFS_MAGIC 0x4D5F53665248425FULL 43 | #define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 44 | #define BTRFS_LABEL_SIZE 256 45 | 46 | #define BTRFS_NUM_BACKUP_ROOTS 4 47 | struct btrfs_root_backup { 48 | __le64 tree_root; 49 | __le64 tree_root_gen; 50 | 51 | __le64 chunk_root; 52 | __le64 chunk_root_gen; 53 | 54 | __le64 extent_root; 55 | __le64 extent_root_gen; 56 | 57 | __le64 fs_root; 58 | __le64 fs_root_gen; 59 | 60 | __le64 dev_root; 61 | __le64 dev_root_gen; 62 | 63 | __le64 csum_root; 64 | __le64 csum_root_gen; 65 | 66 | __le64 total_bytes; 67 | __le64 bytes_used; 68 | __le64 num_devices; 69 | /* future */ 70 | __le64 unsed_64[4]; 71 | 72 | u8 tree_root_level; 73 | u8 chunk_root_level; 74 | u8 extent_root_level; 75 | u8 fs_root_level; 76 | u8 dev_root_level; 77 | u8 csum_root_level; 78 | /* future and to align */ 79 | u8 unused_8[10]; 80 | } __attribute__((__packed__)); 81 | 82 | #define BTRFS_UUID_SIZE 16 83 | struct btrfs_dev_item { 84 | /* the internal btrfs device id */ 85 | __le64 devid; 86 | 87 | /* size of the device */ 88 | __le64 total_bytes; 89 | 90 | /* bytes used */ 91 | __le64 bytes_used; 92 | 93 | /* optimal io alignment for this device */ 94 | __le32 io_align; 95 | 96 | /* optimal io width for this device */ 97 | __le32 io_width; 98 | 99 | /* minimal io size for this device */ 100 | __le32 sector_size; 101 | 102 | /* type and info about this device */ 103 | __le64 type; 104 | 105 | /* expected generation for this device */ 106 | __le64 generation; 107 | 108 | /* 109 | * starting byte of this partition on the device, 110 | * to allowr for stripe alignment in the future 111 | */ 112 | __le64 start_offset; 113 | 114 | /* grouping information for allocation decisions */ 115 | __le32 dev_group; 116 | 117 | /* seek speed 0-100 where 100 is fastest */ 118 | u8 seek_speed; 119 | 120 | /* bandwidth 0-100 where 100 is fastest */ 121 | u8 bandwidth; 122 | 123 | /* btrfs generated uuid for this device */ 124 | u8 uuid[BTRFS_UUID_SIZE]; 125 | 126 | /* uuid of FS who owns this device */ 127 | u8 fsid[BTRFS_UUID_SIZE]; 128 | } __attribute__((__packed__)); 129 | 130 | struct btrfs_super_block { 131 | u8 csum[BTRFS_CSUM_SIZE]; 132 | /* the first 3 fields must match struct btrfs_header */ 133 | u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ 134 | __le64 bytenr; /* this block number */ 135 | __le64 flags; 136 | /* allowed to be different from the btrfs_header from here own down */ 137 | __le64 magic; 138 | __le64 generation; 139 | __le64 root; 140 | __le64 chunk_root; 141 | __le64 log_root; 142 | 143 | /* this will help find the new super based on the log root */ 144 | __le64 log_root_transid; 145 | __le64 total_bytes; 146 | __le64 bytes_used; 147 | __le64 root_dir_objectid; 148 | __le64 num_devices; 149 | __le32 sectorsize; 150 | __le32 nodesize; 151 | __le32 leafsize; 152 | __le32 stripesize; 153 | __le32 sys_chunk_array_size; 154 | __le64 chunk_root_generation; 155 | __le64 compat_flags; 156 | __le64 compat_ro_flags; 157 | __le64 incompat_flags; 158 | __le16 csum_type; 159 | u8 root_level; 160 | u8 chunk_root_level; 161 | u8 log_root_level; 162 | struct btrfs_dev_item dev_item; 163 | 164 | char label[BTRFS_LABEL_SIZE]; 165 | 166 | __le64 cache_generation; 167 | __le64 uuid_tree_generation; 168 | 169 | /* future expansion */ 170 | __le64 reserved[30]; 171 | u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; 172 | struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; 173 | } __attribute__((__packed__)); 174 | 175 | #endif /* _GM_BTRFS_H */ 176 | -------------------------------------------------------------------------------- /src/gm_ext2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_ext2.c -- gpart ext2 guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 30.04.1999 14 | * Added suggestions from Andries.Brouwer@cwi.nl 15 | * 16 | * 18.06.1999 17 | * Fixed buggy ext2 spare superblock location calculation. 18 | * 19 | * 29.06.1999 20 | * Made every disk read/write buffer aligned to pagesize. 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include "gpart.h" 28 | #include "gm_ext2.h" 29 | 30 | int ext2_init(disk_desc *d, g_module *m) 31 | { 32 | int bsize = SUPERBLOCK_SIZE; 33 | 34 | if ((d == 0) || (m == 0)) 35 | return (0); 36 | 37 | /* 38 | * the medium sector size must either be a multiple 39 | * of the superblock size or vice versa. 40 | */ 41 | 42 | if (((d->d_ssize > bsize) && (d->d_ssize % bsize)) || ((d->d_ssize < bsize) && (bsize % d->d_ssize))) { 43 | pr(ERROR, "ext2_init: cannot work on that sector size"); 44 | return (0); 45 | } 46 | m->m_desc = "Linux ext2"; 47 | return (SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE); 48 | } 49 | 50 | int ext2_term(disk_desc *d) { return (1); } 51 | 52 | int ext2_gfun(disk_desc *d, g_module *m) 53 | { 54 | struct ext2fs_sb *sb, *sparesb; 55 | int psize, bsize = 1024; 56 | s64_t ls, ofs; 57 | dos_part_entry *pt = &m->m_part; 58 | byte_t *ubuf, *sbuf; 59 | 60 | m->m_guess = GM_NO; 61 | sb = (struct ext2fs_sb *)(d->d_sbuf + SUPERBLOCK_OFFSET); 62 | if (sb->s_magic != le16(EXT2_SUPER_MAGIC)) 63 | return (1); 64 | 65 | /* 66 | * first some plausability checks. 67 | */ 68 | 69 | if (sb->s_free_blocks_count >= sb->s_blocks_count) 70 | return (1); 71 | if (sb->s_free_inodes_count >= sb->s_inodes_count) 72 | return (1); 73 | if (sb->s_errors && (sb->s_errors != EXT2_ERRORS_CONTINUE) && (sb->s_errors != EXT2_ERRORS_RO) && 74 | (sb->s_errors != EXT2_ERRORS_PANIC)) 75 | return (1); 76 | if (sb->s_state & ~(EXT2_VALID_FS | EXT2_ERROR_FS)) 77 | return (1); 78 | 79 | /* 80 | * empty filesystems seem unlikely to me. 81 | */ 82 | 83 | if (sb->s_blocks_count == 0) 84 | return (1); 85 | 86 | /* 87 | * yet they also shouldn't be too large. 88 | */ 89 | 90 | if (d->d_nsecs) { 91 | ls = sb->s_blocks_count; 92 | ls *= bsize; 93 | ls /= d->d_ssize; 94 | ls += d->d_nsb; 95 | if (ls > d->d_nsecs) 96 | return (1); 97 | } 98 | 99 | /* 100 | * ext2fs supports 1024, 2048 and 4096b blocks. 101 | */ 102 | 103 | switch (sb->s_log_block_size) { 104 | case BSIZE_1024: 105 | bsize = 1024; 106 | break; 107 | case BSIZE_2048: 108 | bsize = 2048; 109 | break; 110 | case BSIZE_4096: 111 | bsize = 4096; 112 | break; 113 | default: 114 | return (1); 115 | } 116 | 117 | /* 118 | * current mount count shouldn't be greater than max+20 119 | * but ext3 usually has s_max_mnt_count==-1 120 | */ 121 | 122 | if ((sb->s_max_mnt_count != -1) && (sb->s_mnt_count > sb->s_max_mnt_count + 20)) 123 | return (1); 124 | 125 | /* 126 | * up to here this looks like a valid ext2 sb, now try to read 127 | * the first spare super block to be sure. 128 | */ 129 | 130 | if ((ls = l64tell(d->d_fd)) == -1) 131 | pr(FATAL, "ext2: cannot seek: %s", strerror(errno)); 132 | ls /= d->d_ssize; 133 | ls -= d->d_nsb; 134 | ls *= d->d_ssize; 135 | ofs = sb->s_blocks_per_group + sb->s_first_data_block; 136 | ofs *= bsize; 137 | if (l64seek(d->d_fd, ofs - ls, SEEK_CUR) == -1) 138 | pr(FATAL, "ext2: cannot seek: %s", strerror(errno)); 139 | 140 | psize = getpagesize(); 141 | ubuf = alloc(SUPERBLOCK_SIZE + psize); 142 | sbuf = align(ubuf, psize); 143 | if (read(d->d_fd, sbuf, SUPERBLOCK_SIZE) != SUPERBLOCK_SIZE) 144 | pr(FATAL, "ext2: cannot read spare super block"); 145 | sparesb = (struct ext2fs_sb *)sbuf; 146 | 147 | /* 148 | * test only some values of the spare sb. 149 | */ 150 | 151 | if (sparesb->s_magic != le16(EXT2_SUPER_MAGIC)) 152 | goto out; 153 | if (sparesb->s_log_block_size != sb->s_log_block_size) 154 | goto out; 155 | 156 | /* 157 | * seems ok. 158 | */ 159 | 160 | m->m_guess = GM_YES; 161 | pt->p_typ = 0x83; 162 | pt->p_start = d->d_nsb; 163 | pt->p_size = bsize / d->d_ssize; 164 | pt->p_size *= sb->s_blocks_count; 165 | 166 | out: 167 | free((void *)ubuf); 168 | return (1); 169 | } 170 | -------------------------------------------------------------------------------- /src/gm_ext2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_ext2.h -- gpart ext2 guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_EXT2_H 18 | #define _GM_EXT2_H 19 | 20 | /* 21 | * Ext2 filesystem structures, taken from the ext2 utilities v1.10. 22 | */ 23 | 24 | /* imported from asm/types.h */ 25 | typedef __signed__ char __s8; 26 | typedef unsigned char __u8; 27 | 28 | typedef __signed__ short __s16; 29 | typedef unsigned short __u16; 30 | 31 | typedef __signed__ int __s32; 32 | typedef unsigned int __u32; 33 | 34 | /* imported from ext2fs/ext2_fs.h */ 35 | 36 | #define SUPERBLOCK_OFFSET 1024 37 | #define SUPERBLOCK_SIZE 1024 38 | #define BSIZE_1024 0 39 | #define BSIZE_2048 1 40 | #define BSIZE_4096 2 41 | #define EXT2_LIB_CURRENT_REV 0 42 | #define EXT2_SUPER_MAGIC 0xEF53 43 | #define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ 44 | #define EXT2_ERROR_FS 0x0002 /* Errors detected */ 45 | #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ 46 | #define EXT2_DFL_CHECKINTERVAL 15552000 /* Don't use interval check */ 47 | #define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ 48 | #define EXT2_ERRORS_RO 2 /* Remount fs read-only */ 49 | #define EXT2_ERRORS_PANIC 3 /* Panic */ 50 | #define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE 51 | #define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ 52 | #define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ 53 | 54 | struct ext2fs_sb { 55 | __u32 s_inodes_count; /* Inodes count */ 56 | __u32 s_blocks_count; /* Blocks count */ 57 | __u32 s_r_blocks_count; /* Reserved blocks count */ 58 | __u32 s_free_blocks_count; /* Free blocks count */ 59 | __u32 s_free_inodes_count; /* Free inodes count */ 60 | __u32 s_first_data_block; /* First Data Block */ 61 | __u32 s_log_block_size; /* Block size */ 62 | __s32 s_log_frag_size; /* Fragment size */ 63 | __u32 s_blocks_per_group; /* # Blocks per group */ 64 | __u32 s_frags_per_group; /* # Fragments per group */ 65 | __u32 s_inodes_per_group; /* # Inodes per group */ 66 | __u32 s_mtime; /* Mount time */ 67 | __u32 s_wtime; /* Write time */ 68 | __u16 s_mnt_count; /* Mount count */ 69 | __s16 s_max_mnt_count; /* Maximal mount count */ 70 | __u16 s_magic; /* Magic signature */ 71 | __u16 s_state; /* File system state */ 72 | __u16 s_errors; /* Behaviour when detecting errors */ 73 | __u16 s_minor_rev_level; /* minor revision level */ 74 | __u32 s_lastcheck; /* time of last check */ 75 | __u32 s_checkinterval; /* max. time between checks */ 76 | __u32 s_creator_os; /* OS */ 77 | __u32 s_rev_level; /* Revision level */ 78 | __u16 s_def_resuid; /* Default uid for reserved blocks */ 79 | __u16 s_def_resgid; /* Default gid for reserved blocks */ 80 | /* 81 | * These fields are for EXT2_DYNAMIC_REV superblocks only. 82 | * 83 | * Note: the difference between the compatible feature set and 84 | * the incompatible feature set is that if there is a bit set 85 | * in the incompatible feature set that the kernel doesn't 86 | * know about, it should refuse to mount the filesystem. 87 | * 88 | * e2fsck's requirements are more strict; if it doesn't know 89 | * about a feature in either the compatible or incompatible 90 | * feature set, it must abort and not try to meddle with 91 | * things it doesn't understand... 92 | */ 93 | __u32 s_first_ino; /* First non-reserved inode */ 94 | __u16 s_inode_size; /* size of inode structure */ 95 | __u16 s_block_group_nr; /* block group # of this superblock */ 96 | __u32 s_feature_compat; /* compatible feature set */ 97 | __u32 s_feature_incompat; /* incompatible feature set */ 98 | __u32 s_feature_ro_compat; /* readonly-compatible feature set */ 99 | __u8 s_uuid[16]; /* 128-bit uuid for volume */ 100 | char s_volume_name[16]; /* volume name */ 101 | char s_last_mounted[64]; /* directory where last mounted */ 102 | __u32 s_reserved[206]; /* Padding to the end of the block */ 103 | }; 104 | 105 | #endif /* _GM_EXT2_H */ 106 | -------------------------------------------------------------------------------- /src/gm_fat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_fat.c -- gpart fat guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include "gpart.h" 18 | #include "gm_fat.h" 19 | 20 | int fat_init(disk_desc *d, g_module *m) 21 | { 22 | if ((d == 0) || (m == 0)) 23 | return (0); 24 | m->m_desc = "DOS FAT"; 25 | m->m_align = 'h'; 26 | return (sizeof(struct fat_boot_sector)); 27 | } 28 | 29 | int fat_term(disk_desc *d) { return (1); } 30 | 31 | int fat_gfun(disk_desc *d, g_module *m) 32 | { 33 | struct fat_boot_sector *sb = (struct fat_boot_sector *)d->d_sbuf; 34 | dos_part_entry *pt = &m->m_part; 35 | unsigned long nsecs = 0; 36 | unsigned char ig1, ig2, media; 37 | int sectsize, fat32 = 0, fat12 = 0; 38 | s64_t size = 0; 39 | 40 | m->m_guess = GM_NO; 41 | ig1 = sb->ignored[0]; 42 | ig2 = sb->ignored[2]; 43 | media = sb->media; 44 | if ((ig1 == 0xeb) && (ig2 == 0x90) && ((media == 0xf8) || (media == 0xfc))) { 45 | if (*((unsigned short *)d->d_sbuf + 255) != le16(DOSPTMAGIC)) 46 | return (1); 47 | 48 | /* 49 | * looks like a standard FAT boot sector. Now find out, 50 | * which one of the numerous versions this could be. 51 | */ 52 | 53 | pt->p_start = d->d_nsb; 54 | nsecs = le16(sb->sectors); 55 | if (nsecs == 0) 56 | nsecs = le32(sb->total_sect); 57 | if (nsecs == 0) 58 | return (1); 59 | sectsize = le16(sb->sector_size); 60 | if ((d->d_sbuf[0x39] == '1') && (d->d_sbuf[0x3a] == '2')) 61 | fat12 = 1; 62 | if (sb->fat_length == 0) 63 | fat32 = 1; 64 | if (fat32 && (*(d->d_sbuf + 0x26) == 0x29)) 65 | return (1); 66 | if (!fat32 && (*(d->d_sbuf + 0x26) != 0x29)) 67 | return (1); 68 | if (fat12 && fat32) 69 | return (1); 70 | m->m_guess = GM_YES; 71 | 72 | /* 73 | * what happens when the fat sectsize != medium sectsize? 74 | * I don't know. I just say no now. 75 | */ 76 | 77 | if (sectsize != d->d_ssize) 78 | m->m_guess = GM_NO; 79 | size = nsecs; 80 | size *= sectsize; 81 | size /= 1024; 82 | if (size >= 32768) { 83 | pt->p_typ = 0x06; 84 | if (fat32) 85 | pt->p_typ = d->d_lba ? 0x0C : 0x0B; 86 | } else 87 | pt->p_typ = fat12 ? 0x01 : 0x04; 88 | pt->p_size = nsecs; 89 | } 90 | return (1); 91 | } 92 | -------------------------------------------------------------------------------- /src/gm_fat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_fat.h -- gpart fat guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_FAT_H 18 | #define _GM_FAT_H 19 | 20 | /* 21 | * FAT partition boot sector information, taken from the Linux 22 | * kernel sources. 23 | */ 24 | 25 | /* imported from asm/types.h */ 26 | typedef __signed__ char __s8; 27 | typedef unsigned char __u8; 28 | 29 | typedef __signed__ short __s16; 30 | typedef unsigned short __u16; 31 | 32 | typedef __signed__ int __s32; 33 | typedef unsigned int __u32; 34 | 35 | 36 | struct fat_boot_sector { 37 | __s8 ignored[3]; /* Boot strap short or near jump */ 38 | __s8 system_id[8]; /* Name - can be used to special case 39 | partition manager volumes */ 40 | __u16 sector_size; /* bytes per logical sector */ 41 | __u8 cluster_size; /* sectors/cluster */ 42 | __u16 reserved; /* reserved sectors */ 43 | __u8 fats; /* number of FATs */ 44 | __u8 dir_entries[2]; /* root directory entries */ 45 | __u16 sectors; /* number of sectors */ 46 | __u8 media; /* media code (unused) */ 47 | __u16 fat_length; /* sectors/FAT */ 48 | __u16 secs_track; /* sectors per track */ 49 | __u16 heads; /* number of heads */ 50 | __u32 hidden; /* hidden sectors (unused) */ 51 | __u32 total_sect; /* number of sectors (if sectors == 0) */ 52 | 53 | /* The following fields are only used by FAT32 */ 54 | __u32 fat32_length; /* sectors/FAT */ 55 | __u16 flags; /* bit 8: fat mirroring, low 4: active fat */ 56 | __u8 version[2]; /* major, minor filesystem version */ 57 | __u32 root_cluster; /* first cluster in root directory */ 58 | __u16 info_sector; /* filesystem info sector */ 59 | __u16 backup_boot; /* backup boot sector */ 60 | __u16 reserved2[6]; /* Unused */ 61 | } __attribute__ ((packed)); 62 | /* "__attribute__ ((packed))" 63 | added by davidc@debian.org, 64 | as suggested by falk@zxmjz18.extern.uni-tuebingen.de 65 | Fri Jul 07 18:04:15 2000 66 | in debian bug report #66893 "FAT detection broken on Alpha" */ 67 | #endif /* _GM_FAT_H */ 68 | -------------------------------------------------------------------------------- /src/gm_hmlvm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_hmlvm.c -- gpart Linux LVM physical volume guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 29.08.1999 13 | * Modified: 29.01.2001 14 | * Minor update to LVM 0.9. 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include "gpart.h" 21 | #include "gm_hmlvm.h" 22 | 23 | int hmlvm_init(disk_desc *d, g_module *m) 24 | { 25 | if ((d == 0) || (m == 0)) 26 | return (0); 27 | 28 | m->m_desc = "Linux LVM physical volume"; 29 | return (LVM_PV_DISK_BASE + LVM_PV_DISK_SIZE); 30 | } 31 | 32 | int hmlvm_term(disk_desc *d) { return (1); } 33 | 34 | int hmlvm_gfun(disk_desc *d, g_module *m) 35 | { 36 | pv_disk_t *pv; 37 | dos_part_entry *pt = &m->m_part; 38 | unsigned int size; 39 | s64_t s; 40 | 41 | m->m_guess = GM_NO; 42 | pv = (pv_disk_t *)&d->d_sbuf[LVM_PV_DISK_BASE]; 43 | if ((strncmp((char *)pv->id, LVM_ID, sizeof(pv->id)) == 0) && ((pv->version == 1) || (pv->version == 2))) { 44 | /* 45 | * looks like a physical volume header. Do the usual 46 | * consistency checks. 47 | */ 48 | 49 | if (pv->pv_size > LVM_MAX_SIZE) 50 | return (1); 51 | if ((pv->pv_status != 0) && (pv->pv_status != PV_ACTIVE)) 52 | return (1); 53 | if ((pv->pv_allocatable != 0) && (pv->pv_allocatable != PV_ALLOCATABLE)) 54 | return (1); 55 | if (pv->lv_cur > MAX_LV) 56 | return (1); 57 | if (strlen((char *)pv->vg_name) > NAME_LEN / 2) 58 | return (1); 59 | 60 | size = pv->pe_size / LVM_MIN_PE_SIZE * LVM_MIN_PE_SIZE; 61 | if ((pv->pe_size != size) || (pv->pe_size < LVM_MIN_PE_SIZE) || (pv->pe_size > LVM_MAX_PE_SIZE)) 62 | return (1); 63 | 64 | if (pv->pe_total > (pv->pe_on_disk.size / sizeof(disk_pe_t))) 65 | return (1); 66 | if (pv->pe_allocated > pv->pe_total) 67 | return (1); 68 | 69 | /* 70 | * Ok. 71 | */ 72 | 73 | m->m_guess = GM_YES; 74 | pt->p_start = d->d_nsb; 75 | s = pv->pv_size; 76 | s *= 512; 77 | s /= d->d_ssize; 78 | pt->p_size = s; 79 | pt->p_typ = 0x8E; 80 | } 81 | 82 | return (1); 83 | } 84 | -------------------------------------------------------------------------------- /src/gm_hmlvm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_hmlvm.h -- gpart Linux LVM physical volume guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 29.08.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_HMLVM_H 18 | #define _GM_HMLVM_H 19 | 20 | /* 21 | * structs & defines gathered from LVM 0.7/0.9 lvm.h and liblvm.h 22 | */ 23 | 24 | #if !defined(__FreeBSD__) 25 | typedef unsigned char uint8_t; 26 | typedef unsigned short uint16_t; 27 | typedef unsigned int uint32_t; 28 | #endif 29 | 30 | 31 | /* 32 | * Status flags 33 | */ 34 | 35 | /* physical volume */ 36 | #define PV_ACTIVE 0x01 /* pv_status */ 37 | #define PV_ALLOCATABLE 0x02 /* pv_allocatable */ 38 | 39 | 40 | #define LVM_PV_DISK_BASE 0L 41 | #define LVM_PV_DISK_SIZE 1024L 42 | #define NAME_LEN 128 /* don't change!!! */ 43 | #define UUID_LEN 16 /* don't change!!! */ 44 | #define LVM_MAX_SIZE ( 1024LU * 1024 * 1024 * 2) /* 1TB[sectors] */ 45 | #define LVM_ID "HM" 46 | #define LVM_DIR_PREFIX "/dev/" 47 | #define MAX_LV 256 48 | #define LVM_MIN_PE_SIZE ( 8L * 2) /* 8 KB in sectors */ 49 | #define LVM_MAX_PE_SIZE ( 16L * 1024L * 1024L * 2) /* 16GB in sectors */ 50 | 51 | /* disk stored pe information */ 52 | typedef struct { 53 | uint16_t lv_num; 54 | uint16_t le_num; 55 | } disk_pe_t; 56 | 57 | /* disk stored PV, VG, LV and PE size and offset information */ 58 | typedef struct { 59 | uint32_t base; 60 | uint32_t size; 61 | } lvm_disk_data_t; 62 | 63 | /* 64 | * Structure Physical Volume (PV) Version 2 65 | */ 66 | 67 | /* disk */ 68 | typedef struct { 69 | uint8_t id[2]; /* Identifier */ 70 | uint16_t version; /* HM lvm version */ 71 | lvm_disk_data_t pv_on_disk; 72 | lvm_disk_data_t vg_on_disk; 73 | lvm_disk_data_t pv_uuidlist_on_disk; 74 | lvm_disk_data_t lv_on_disk; 75 | lvm_disk_data_t pe_on_disk; 76 | uint8_t pv_uuid[NAME_LEN]; 77 | uint8_t vg_name[NAME_LEN]; 78 | uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ 79 | uint32_t pv_major; 80 | uint32_t pv_number; 81 | uint32_t pv_status; 82 | uint32_t pv_allocatable; 83 | uint32_t pv_size; /* HM */ 84 | uint32_t lv_cur; 85 | uint32_t pe_size; 86 | uint32_t pe_total; 87 | uint32_t pe_allocated; 88 | } pv_disk_v2_t; 89 | 90 | #define pv_disk_t pv_disk_v2_t 91 | 92 | #endif /* _GM_HMLVM_H */ 93 | -------------------------------------------------------------------------------- /src/gm_hpfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_hpfs.c -- gpart hpfs guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 29.06.1999 14 | * Made every disk read/write buffer aligned to pagesize. 15 | * 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include "gpart.h" 23 | #include "gm_hpfs.h" 24 | 25 | #define OS2SECTSIZE 512 26 | 27 | int hpfs_init(disk_desc *d, g_module *m) 28 | { 29 | if ((d == 0) || (m == 0)) 30 | return (0); 31 | 32 | m->m_desc = "OS/2 HPFS"; 33 | return (OS2SECTSIZE); 34 | } 35 | 36 | int hpfs_term(disk_desc *d) { return (1); } 37 | 38 | int hpfs_gfun(disk_desc *d, g_module *m) 39 | { 40 | struct hpfs_boot_block *bb = (struct hpfs_boot_block *)d->d_sbuf; 41 | struct hpfs_super_block *sb; 42 | s64_t s; 43 | size_t psize; 44 | byte_t *ubuf, *sbuf; 45 | 46 | m->m_guess = GM_NO; 47 | if ((bb->sig_28h == 0x28) && (strncmp((char *)bb->sig_hpfs, "HPFS ", 8) == 0) && (bb->magic == le16(0xaa55)) && 48 | (bb->bytes_per_sector == le16(OS2SECTSIZE))) { 49 | /* 50 | * looks like a hpfs boot sector. Test hpfs superblock 51 | * at sector offset 16 (from start of partition). 52 | */ 53 | 54 | if ((s = l64tell(d->d_fd)) == -1) 55 | pr(FATAL, "hpfs: cannot seek: %s", strerror(errno)); 56 | s /= d->d_ssize; 57 | s -= d->d_nsb; 58 | s *= d->d_ssize; 59 | if (l64seek(d->d_fd, 16 * OS2SECTSIZE - s, SEEK_CUR) == -1) 60 | pr(FATAL, "hpfs: cannot seek: %s", strerror(errno)); 61 | 62 | psize = getpagesize(); 63 | ubuf = alloc(OS2SECTSIZE + psize); 64 | sbuf = align(ubuf, psize); 65 | if (read(d->d_fd, sbuf, OS2SECTSIZE) != OS2SECTSIZE) 66 | pr(FATAL, "hpfs: cannot read super block"); 67 | sb = (struct hpfs_super_block *)sbuf; 68 | if (sb->magic != le32(SB_MAGIC)) 69 | goto out; 70 | 71 | /* 72 | * ok, fill in sizes. 73 | */ 74 | 75 | s = sb->n_sectors; 76 | s *= OS2SECTSIZE; 77 | s /= d->d_ssize; 78 | m->m_part.p_start = d->d_nsb; 79 | m->m_part.p_size = s; 80 | m->m_guess = GM_YES; 81 | out: 82 | free((void *)ubuf); 83 | } 84 | return (1); 85 | } 86 | -------------------------------------------------------------------------------- /src/gm_hpfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_hpfs.h -- gpart hpfs guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_HPFS_H 18 | #define _GM_HPFS_H 19 | 20 | 21 | /* 22 | * hpfs information/macros, taken from the Linux kernel sources. 23 | */ 24 | 25 | 26 | /* Notation */ 27 | 28 | typedef unsigned secno; /* sector number, partition relative */ 29 | 30 | typedef secno dnode_secno; /* sector number of a dnode */ 31 | typedef secno fnode_secno; /* sector number of an fnode */ 32 | typedef secno anode_secno; /* sector number of an anode */ 33 | 34 | 35 | 36 | /* sector 0 */ 37 | 38 | /* The boot block is very like a FAT boot block, except that the 39 | 29h signature byte is 28h instead, and the ID string is "HPFS". */ 40 | 41 | struct hpfs_boot_block 42 | { 43 | unsigned char jmp[3]; 44 | unsigned char oem_id[8]; 45 | unsigned short bytes_per_sector; /* 512 */ 46 | unsigned char sectors_per_cluster; 47 | unsigned char n_reserved_sectors[2]; 48 | unsigned char n_fats; 49 | unsigned char n_rootdir_entries[2]; 50 | unsigned char n_sectors_s[2]; 51 | unsigned char media_byte; 52 | unsigned short sectors_per_fat; 53 | unsigned short sectors_per_track; 54 | unsigned short heads_per_cyl; 55 | unsigned int n_hidden_sectors; 56 | unsigned int n_sectors_l; /* size of partition */ 57 | unsigned char drive_number; 58 | unsigned char mbz; 59 | unsigned char sig_28h; /* 28h */ 60 | unsigned char vol_serno[4]; 61 | unsigned char vol_label[11]; 62 | unsigned char sig_hpfs[8]; /* "HPFS " */ 63 | unsigned char pad[448]; 64 | unsigned short magic; /* aa55 */ 65 | }; 66 | 67 | 68 | /* sector 16 */ 69 | 70 | /* The super block has the pointer to the root directory. */ 71 | 72 | #define SB_MAGIC 0xf995e849 73 | 74 | struct hpfs_super_block 75 | { 76 | unsigned magic; /* f995 e849 */ 77 | unsigned magic1; /* fa53 e9c5, more magic? */ 78 | unsigned huh202; /* ?? 202 = N. of B. in 1.00390625 S.*/ 79 | fnode_secno root; /* fnode of root directory */ 80 | secno n_sectors; /* size of filesystem */ 81 | unsigned n_badblocks; /* number of bad blocks */ 82 | secno bitmaps; /* pointers to free space bit maps */ 83 | unsigned zero1; /* 0 */ 84 | secno badblocks; /* bad block list */ 85 | unsigned zero3; /* 0 */ 86 | time_t last_chkdsk; /* date last checked, 0 if never */ 87 | unsigned zero4; /* 0 */ 88 | secno n_dir_band; /* number of sectors in dir band */ 89 | secno dir_band_start; /* first sector in dir band */ 90 | secno dir_band_end; /* last sector in dir band */ 91 | secno dir_band_bitmap; /* free space map, 1 dnode per bit */ 92 | unsigned zero5[8]; /* 0 */ 93 | secno scratch_dnodes; /* ?? 8 preallocated sectors near dir 94 | band, 4-aligned. */ 95 | unsigned zero6[103]; /* 0 */ 96 | }; 97 | 98 | 99 | 100 | #endif /* _GM_HPFS_H */ 101 | -------------------------------------------------------------------------------- /src/gm_lswap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_lswap.c -- gpart linux swap guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 22.01.1999 14 | * Calculation of old swap-partition was wrong. 15 | * 16 | */ 17 | 18 | #include 19 | #include "gpart.h" 20 | 21 | static char *sigs[] = {"SWAP-SPACE", "SWAPSPACE2"}; 22 | static int pszs[] = {4096, 8192}; 23 | static int siglen = 10; 24 | 25 | int lswap_init(disk_desc *d, g_module *m) 26 | { 27 | if ((d == 0) || (m == 0)) 28 | return (0); 29 | 30 | m->m_desc = "Linux swap"; 31 | 32 | /* 33 | * return the max. pagesize of platforms running Linux. 34 | * Seems to be 8k (Alpha). 35 | */ 36 | 37 | return (8192); 38 | } 39 | 40 | int lswap_term(disk_desc *d) { return (1); } 41 | 42 | int lswap_gfun(disk_desc *d, g_module *m) 43 | { 44 | char *sig = 0; 45 | int i, j, pagesize, vers; 46 | byte_t *p, b; 47 | s64_t np = 0; 48 | dos_part_entry *pt = &m->m_part; 49 | 50 | m->m_guess = GM_NO; 51 | pagesize = vers = 0; 52 | for (i = 0; (pagesize == 0) && (i < sizeof(sigs) / sizeof(char *)); i++) 53 | for (j = 0; j < sizeof(pszs) / sizeof(int); j++) { 54 | sig = (char *)(d->d_sbuf + pszs[j] - siglen); 55 | if (strncmp(sig, sigs[i], siglen) == 0) { 56 | pagesize = pszs[j]; 57 | vers = i; 58 | break; 59 | } 60 | } 61 | 62 | if (pagesize == 0) 63 | return (1); 64 | 65 | if (vers == 0) /* old (<128mb) style swap */ 66 | { 67 | if (*d->d_sbuf != 0xFE) 68 | return (1); 69 | 70 | for (p = (byte_t *)(sig - 1); p >= d->d_sbuf; p--) 71 | if (*p) 72 | break; 73 | np = (p - d->d_sbuf) * 8; 74 | for (b = *p; (b & 0x01) == 1; b >>= 1) 75 | np++; 76 | } else if (vers == 1) /* Linux > 2.2.X swap partitions */ 77 | { 78 | struct swapinfo { 79 | char bootbits[1024]; 80 | unsigned int version; 81 | unsigned int last_page; 82 | unsigned int nr_badpages; 83 | unsigned int padding[125]; 84 | unsigned int badpages[1]; 85 | } *info = (struct swapinfo *)d->d_sbuf; 86 | 87 | if (info->version != 1) 88 | return (1); 89 | np = 1 + info->last_page; 90 | } else 91 | return (1); 92 | 93 | if (np >= 10) /* mkswap(8) says this */ 94 | { 95 | np *= pagesize; 96 | np /= d->d_ssize; 97 | m->m_guess = GM_YES; 98 | pt->p_typ = 0x82; 99 | pt->p_start = d->d_nsb; 100 | pt->p_size = np; 101 | } 102 | return (1); 103 | } 104 | -------------------------------------------------------------------------------- /src/gm_lvm2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_lvm2.c -- gpart Linux LVM2 physical volume guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 20.11.2015 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include "gpart.h" 19 | #include "gm_lvm2.h" 20 | 21 | int lvm2_init(disk_desc *d, g_module *m) 22 | { 23 | if ((d == 0) || (m == 0)) 24 | return (0); 25 | 26 | m->m_desc = "Linux LVM2 physical volume"; 27 | return SECTOR_SIZE + LABEL_SIZE; 28 | } 29 | 30 | int lvm2_term(disk_desc *d) { return (1); } 31 | 32 | int lvm2_gfun(disk_desc *d, g_module *m) 33 | { 34 | struct label_header *lh; 35 | struct pv_header *pvh; 36 | dos_part_entry *pt = &m->m_part; 37 | s64_t pv_size; 38 | byte_t *p = d->d_sbuf + SECTOR_SIZE; 39 | 40 | m->m_guess = GM_NO; 41 | lh = (struct label_header *)p; 42 | if (strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id)) || strncmp((char *)lh->type, LVM2_LABEL, sizeof(lh->type))) 43 | return 1; 44 | 45 | pvh = (struct pv_header *)((char *)lh + le32toh(lh->offset_xl)); 46 | pv_size = le64toh(pvh->device_size_xl); 47 | pv_size /= d->d_ssize; 48 | if (d->d_nsecs != 0 && pv_size > d->d_nsecs - d->d_nsb) 49 | return 1; 50 | 51 | m->m_guess = GM_YES; 52 | pt->p_start = d->d_nsb; 53 | pt->p_size = pv_size; 54 | pt->p_typ = 0x8E; 55 | 56 | return 1; 57 | } 58 | -------------------------------------------------------------------------------- /src/gm_lvm2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_lvm2.h -- gpart Linux LVM physical volume guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 19.11.2015 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_LVM2_H 18 | #define _GM_LVM2_H 19 | #include 20 | 21 | /* 22 | * structs & defines gathered from LVM2 23 | */ 24 | 25 | #if !defined(__FreeBSD__) 26 | typedef unsigned char uint8_t; 27 | typedef unsigned short uint16_t; 28 | typedef unsigned int uint32_t; 29 | #endif 30 | 31 | #define ID_LEN 32 32 | #define SECTOR_SHIFT 9 33 | #define SECTOR_SIZE (1 << SECTOR_SHIFT) 34 | #define LABEL_ID "LABELONE" 35 | #define LABEL_SIZE SECTOR_SIZE 36 | #define LABEL_SCAN_SECTORS 4L 37 | #define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT) 38 | #define LVM2_LABEL "LVM2 001" 39 | 40 | /* On disk - 32 bytes */ 41 | struct label_header { 42 | int8_t id[8]; /* LABELONE */ 43 | uint64_t sector_xl; /* Sector number of this label */ 44 | uint32_t crc_xl; /* From next field to end of sector */ 45 | uint32_t offset_xl; /* Offset from start of struct to contents */ 46 | int8_t type[8]; /* LVM2 001 */ 47 | } __attribute__((packed)); 48 | 49 | struct disk_locn { 50 | uint64_t offset; /* Offset in bytes to start sector */ 51 | uint64_t size; /* Bytes */ 52 | } __attribute__((packed)); 53 | 54 | struct pv_header { 55 | int8_t pv_uuid[ID_LEN]; 56 | 57 | /* This size can be overridden if PV belongs to a VG */ 58 | uint64_t device_size_xl; /* Bytes */ 59 | 60 | /* NULL-terminated list of data areas followed by */ 61 | /* NULL-terminated list of metadata area headers */ 62 | struct disk_locn disk_areas_xl[0]; /* Two lists */ 63 | } __attribute__((packed)); 64 | 65 | #endif /* _GM_LVM2_H */ 66 | -------------------------------------------------------------------------------- /src/gm_minix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_minix.c -- gpart minix guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include "gpart.h" 18 | #include "gm_minix.h" 19 | 20 | int minix_init(disk_desc *d, g_module *m) 21 | { 22 | if ((d == 0) || (m == 0)) 23 | return (0); 24 | m->m_desc = "Minix filesystem"; 25 | return (2 * BLOCK_SIZE); 26 | } 27 | 28 | int minix_term(disk_desc *d) { return (1); } 29 | 30 | int minix_gfun(disk_desc *d, g_module *m) 31 | { 32 | long version = 0; 33 | struct minix_super_block *ms; 34 | byte_t *p; 35 | unsigned long zones, size; 36 | 37 | ms = (struct minix_super_block *)(d->d_sbuf + BLOCK_SIZE); 38 | m->m_guess = GM_NO; 39 | 40 | if (ms->s_magic == le16(MINIX_SUPER_MAGIC)) 41 | version = MINIX_V1; 42 | if (ms->s_magic == le16(MINIX_SUPER_MAGIC2)) 43 | version = MINIX_V1; 44 | if (ms->s_magic == le16(MINIX2_SUPER_MAGIC)) 45 | version = MINIX_V2; 46 | if (ms->s_magic == le16(MINIX2_SUPER_MAGIC2)) 47 | version = MINIX_V2; 48 | 49 | if (version == 0) 50 | return (1); 51 | if ((ms->s_state != MINIX_VALID_FS) && (ms->s_state != MINIX_ERROR_FS)) 52 | return (1); 53 | 54 | /* 55 | * the rest of the disk block where the superblock 56 | * was found should be zeroed out. 57 | */ 58 | 59 | for (p = d->d_sbuf + BLOCK_SIZE + sizeof(struct minix_super_block); p < d->d_sbuf + 2 * BLOCK_SIZE; p++) 60 | if (*p) 61 | return (1); 62 | 63 | zones = (version == MINIX_V2) ? ms->s_zones : ms->s_nzones; 64 | size = zones << ms->s_log_zone_size; 65 | size *= BLOCK_SIZE; 66 | 67 | m->m_guess = GM_YES; 68 | m->m_part.p_typ = (version == MINIX_V2) ? 0x81 : 0x80; 69 | m->m_part.p_start = d->d_nsb; 70 | m->m_part.p_size = size / d->d_ssize; 71 | 72 | return (1); 73 | } 74 | -------------------------------------------------------------------------------- /src/gm_minix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_minix.h -- gpart minix guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_MINIX_H 18 | #define _GM_MINIX_H 19 | 20 | /* 21 | * Minix filesystem structures, taken from the Linux kernel. 22 | */ 23 | 24 | /* imported from asm/types.h */ 25 | typedef __signed__ char __s8; 26 | typedef unsigned char __u8; 27 | 28 | typedef __signed__ short __s16; 29 | typedef unsigned short __u16; 30 | 31 | typedef __signed__ int __s32; 32 | typedef unsigned int __u32; 33 | 34 | 35 | #define BLOCK_SIZE 1024 36 | #define MINIX_ROOT_INO 1 37 | 38 | /* Not the same as the bogus LINK_MAX in . Oh well. */ 39 | #define MINIX_LINK_MAX 250 40 | #define MINIX2_LINK_MAX 65530 41 | 42 | #define MINIX_I_MAP_SLOTS 8 43 | #define MINIX_Z_MAP_SLOTS 64 44 | #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ 45 | #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ 46 | #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ 47 | #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ 48 | #define MINIX_VALID_FS 0x0001 /* Clean fs. */ 49 | #define MINIX_ERROR_FS 0x0002 /* fs has errors. */ 50 | 51 | #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) 52 | #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) 53 | 54 | #define MINIX_V1 0x0001 /* original minix fs */ 55 | #define MINIX_V2 0x0002 /* minix V2 fs */ 56 | 57 | #define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version 58 | 59 | /* 60 | * This is the original minix inode layout on disk. 61 | * Note the 8-bit gid and atime and ctime. 62 | */ 63 | struct minix_inode { 64 | __u16 i_mode; 65 | __u16 i_uid; 66 | __u32 i_size; 67 | __u32 i_time; 68 | __u8 i_gid; 69 | __u8 i_nlinks; 70 | __u16 i_zone[9]; 71 | }; 72 | 73 | /* 74 | * The new minix inode has all the time entries, as well as 75 | * long block numbers and a third indirect block (7+1+1+1 76 | * instead of 7+1+1). Also, some previously 8-bit values are 77 | * now 16-bit. The inode is now 64 bytes instead of 32. 78 | */ 79 | struct minix2_inode { 80 | __u16 i_mode; 81 | __u16 i_nlinks; 82 | __u16 i_uid; 83 | __u16 i_gid; 84 | __u32 i_size; 85 | __u32 i_atime; 86 | __u32 i_mtime; 87 | __u32 i_ctime; 88 | __u32 i_zone[10]; 89 | }; 90 | 91 | /* 92 | * minix super-block data on disk 93 | */ 94 | struct minix_super_block { 95 | __u16 s_ninodes; 96 | __u16 s_nzones; 97 | __u16 s_imap_blocks; 98 | __u16 s_zmap_blocks; 99 | __u16 s_firstdatazone; 100 | __u16 s_log_zone_size; 101 | __u32 s_max_size; 102 | __u16 s_magic; 103 | __u16 s_state; 104 | __u32 s_zones; 105 | }; 106 | 107 | #endif /* _GM_MINIX_H */ 108 | -------------------------------------------------------------------------------- /src/gm_ntfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_ntfs.c -- gpart ntfs guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 26.02.2000 14 | * Length of guessed partition incremented to include NT4 backup 15 | * boot sector. 16 | * 17 | */ 18 | 19 | #include 20 | #include 21 | #include "gpart.h" 22 | #include "gm_ntfs.h" 23 | 24 | #define NTFS_SECTSIZE 512 25 | 26 | int ntfs_init(disk_desc *d, g_module *m) 27 | { 28 | if ((d == 0) || (m == 0)) 29 | return (0); 30 | 31 | m->m_desc = "Windows NT/W2K FS"; 32 | m->m_hasptbl = 1; 33 | return (NTFS_SECTSIZE); /* The ntfs driver in Linux just assumes so */ 34 | } 35 | 36 | int ntfs_term(disk_desc *d) { return (1); } 37 | 38 | int ntfs_gfun(disk_desc *d, g_module *m) 39 | { 40 | int mft_clusters_per_record; 41 | s64_t size, ls; 42 | byte_t *ubuf, *sbuf; 43 | 44 | m->m_guess = GM_NO; 45 | if (IS_NTFS_VOLUME(d->d_sbuf)) { 46 | /* 47 | * ntfs detection is quite weak, should come before 48 | * fat or hpfs. 49 | */ 50 | 51 | if (NTFS_GETU32(d->d_sbuf + 0x40) > 256UL) 52 | return (1); 53 | if (NTFS_GETU32(d->d_sbuf + 0x44) > 256UL) 54 | return (1); 55 | 56 | mft_clusters_per_record = NTFS_GETS8(d->d_sbuf + 0x40); 57 | if ((mft_clusters_per_record < 0) && (mft_clusters_per_record != -10)) 58 | return (1); 59 | size = NTFS_GETU64(d->d_sbuf + 0x28); 60 | 61 | /* 62 | * look for an additional backup boot sector at the end of 63 | * this FS (NT4 puts this backup sector after the FS, this 64 | * sector must be counted). 65 | */ 66 | 67 | ls = d->d_nsb + size; 68 | ls *= d->d_ssize; 69 | if (l64seek(d->d_fd, ls, SEEK_SET) >= 0) { 70 | ubuf = alloc(NTFS_SECTSIZE + getpagesize()); 71 | sbuf = align(ubuf, getpagesize()); 72 | if (read(d->d_fd, sbuf, NTFS_SECTSIZE) != NTFS_SECTSIZE) 73 | pr(FATAL, "ntfs: cannot read backup boot sector"); 74 | if (memcmp(d->d_sbuf, sbuf, NTFS_SECTSIZE) == 0) 75 | size += 1; 76 | free((void *)ubuf); 77 | } 78 | 79 | m->m_part.p_start = d->d_nsb; 80 | m->m_part.p_size = (unsigned long)size; 81 | m->m_part.p_typ = 0x07; 82 | m->m_guess = GM_YES; 83 | } 84 | return (1); 85 | } 86 | -------------------------------------------------------------------------------- /src/gm_ntfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_ntfs.h -- gpart ntfs guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #ifndef _GM_NTFS_H 21 | #define _GM_NTFS_H 22 | 23 | /* 24 | * ntfs information/macros, taken from the Linux kernel sources. 25 | */ 26 | 27 | #define IS_MAGIC(a,b) (*(int*)(a)==*(int*)(b)) 28 | #define IS_MFT_RECORD(a) IS_MAGIC((a),"FILE") 29 | #define IS_NTFS_VOLUME(a) IS_MAGIC((a)+3,"NTFS") 30 | #define IS_INDEX_RECORD(a) IS_MAGIC((a),"INDX") 31 | 32 | /* 'NTFS' in little endian */ 33 | #define NTFS_SUPER_MAGIC 0x5346544E 34 | 35 | /* unsigned integral types */ 36 | #ifndef NTFS_INTEGRAL_TYPES 37 | #define NTFS_INTEGRAL_TYPES 38 | typedef uint8_t ntfs_u8; 39 | typedef uint16_t ntfs_u16; 40 | typedef uint32_t ntfs_u32; 41 | typedef uint64_t ntfs_u64; 42 | typedef int8_t ntfs_s8; 43 | typedef int16_t ntfs_s16; 44 | #endif /* NTFS_INTEGRAL_TYPES */ 45 | 46 | 47 | /* Macros reading unsigned integers from a byte pointer */ 48 | #define NTFS_GETU8(p) (*(ntfs_u8*)(p)) 49 | #define NTFS_GETU16(p) ((ntfs_u16)htole16(*(ntfs_u16*)(p))) 50 | #define NTFS_GETU24(p) ((ntfs_u32)NTFS_GETU16(p) | \ 51 | ((ntfs_u32)NTFS_GETU8(((char*)p)+2))<<16) 52 | #define NTFS_GETU32(p) ((ntfs_u32)htole32(*(ntfs_u32*)(p))) 53 | #define NTFS_GETU64(p) ((ntfs_u64)htole64(*(ntfs_u64*)(p))) 54 | 55 | /* Macros reading signed integers, returning int */ 56 | #define NTFS_GETS8(p) (*(ntfs_s8*)(p)) 57 | #define NTFS_GETS16(p) ((ntfs_s16)htole16(*(ntfs_s16*)(p))) 58 | #define NTFS_GETS24(p) (NTFS_GETU24(p) < 0x800000 ? \ 59 | (int)NTFS_GETU24(p) : \ 60 | (int)(NTFS_GETU24(p) - 0x1000000)) 61 | 62 | #endif /* _GM_NTFS_H */ 63 | -------------------------------------------------------------------------------- /src/gm_qnx4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_qnx4.c -- gpart qnx4 guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include "gpart.h" 21 | #include "gm_qnx4.h" 22 | 23 | #include 24 | 25 | int qnx4_init(disk_desc *d, g_module *m) 26 | { 27 | if ((d == 0) || (m == 0)) 28 | return (0); 29 | m->m_desc = "QNX4 filesystem"; 30 | m->m_notinext = 1; 31 | return (2 * QNX4_BLOCK_SIZE); 32 | } 33 | 34 | int qnx4_term(disk_desc *d) { return (1); } 35 | 36 | int qnx4_gfun(disk_desc *d, g_module *m) 37 | { 38 | struct qnx4_super_block *sb; 39 | struct qnx4_inode_entry *rootdir, bitmap; 40 | int rd, rl, i, j, psize, found; 41 | s64_t ls, ofs, size; 42 | byte_t *ubuf, *sbuf; 43 | 44 | m->m_guess = GM_NO; 45 | 46 | /* 47 | * check QNX signature 48 | */ 49 | 50 | if (memcmp(d->d_sbuf + 4, QNX4_BOOTSECT_SIG, strlen(QNX4_BOOTSECT_SIG))) 51 | return (1); 52 | sb = (struct qnx4_super_block *)(d->d_sbuf + QNX4_BLOCK_SIZE); 53 | if (*sb->RootDir.di_fname != '/') 54 | return (1); 55 | 56 | /* 57 | * read root directory 58 | */ 59 | 60 | psize = getpagesize(); 61 | ubuf = alloc(QNX4_BLOCK_SIZE + psize); 62 | sbuf = align(ubuf, psize); 63 | 64 | found = 0; 65 | 66 | rd = le32(sb->RootDir.di_first_xtnt.xtnt_blk) - 1; 67 | rl = le32(sb->RootDir.di_first_xtnt.xtnt_size); 68 | 69 | for (j = 0; j < rl; j++) { 70 | if ((ls = l64tell(d->d_fd)) == -1) 71 | pr(FATAL, "qnx4: cannot seek: %s", strerror(errno)); 72 | ls /= d->d_ssize; 73 | ls -= d->d_nsb; 74 | ls *= d->d_ssize; 75 | ofs = rd + j; 76 | ofs *= QNX4_BLOCK_SIZE; 77 | if (l64seek(d->d_fd, ofs - ls, SEEK_CUR) == -1) 78 | pr(FATAL, "qnx4: cannot seek: %s", strerror(errno)); 79 | if (read(d->d_fd, sbuf, QNX4_BLOCK_SIZE) != QNX4_BLOCK_SIZE) 80 | pr(FATAL, "qnx4: cannot read root dir entry"); 81 | 82 | /* 83 | * find the ".bitmap" entry 84 | */ 85 | 86 | for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { 87 | rootdir = (struct qnx4_inode_entry *)(sbuf + i * QNX4_DIR_ENTRY_SIZE); 88 | if (rootdir->di_fname && !strncmp(rootdir->di_fname, QNX4_BITMAP_NAME, strlen(QNX4_BITMAP_NAME))) { 89 | memcpy(&bitmap, rootdir, sizeof(struct qnx4_inode_entry)); 90 | found = 1; 91 | } 92 | } 93 | } 94 | 95 | if (!found) 96 | return (1); 97 | 98 | size = le32(bitmap.di_size) * 8 - 6; 99 | size *= QNX4_BLOCK_SIZE; 100 | size /= d->d_ssize; 101 | 102 | m->m_guess = GM_YES; 103 | m->m_part.p_typ = 0x4F; 104 | m->m_part.p_start = d->d_nsb; 105 | m->m_part.p_size = size; 106 | 107 | free((void *)ubuf); 108 | return (1); 109 | } 110 | -------------------------------------------------------------------------------- /src/gm_qnx4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_qnx4.h -- gpart qnx4 guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_QNX4_H 18 | #define _GM_QNX4_H 19 | 20 | /* imported from asm/types.h */ 21 | typedef __signed__ char __s8; 22 | typedef unsigned char __u8; 23 | 24 | typedef __signed__ short __s16; 25 | typedef unsigned short __u16; 26 | 27 | typedef __signed__ int __s32; 28 | typedef unsigned int __u32; 29 | 30 | 31 | #define QNX4_BOOTSECT_SIG "QNX4FS" 32 | #define QNX4_BITMAP_NAME ".bitmap" 33 | 34 | /* 35 | * QNX4 filesystem structures, taken from the Linux kernel. 36 | */ 37 | 38 | #define QNX4_VALID_FS 0x0001 /* Clean fs. */ 39 | #define QNX4_ERROR_FS 0x0002 /* fs has errors. */ 40 | #define QNX4_BLOCK_SIZE 0x200 /* blocksize of 512 bytes */ 41 | #define QNX4_INODES_PER_BLOCK 0x08 /* 512 / 64 */ 42 | #define QNX4_DIR_ENTRY_SIZE 0x040 /* dir entry size of 64 bytes */ 43 | 44 | /* for filenames */ 45 | #define QNX4_SHORT_NAME_MAX 16 46 | #define QNX4_NAME_MAX 48 47 | 48 | typedef __u16 qnx4_nxtnt_t; 49 | typedef __u8 qnx4_ftype_t; 50 | 51 | typedef struct { 52 | __u32 xtnt_blk; 53 | __u32 xtnt_size; 54 | } qnx4_xtnt_t; 55 | 56 | typedef __u16 qnx4_mode_t; 57 | typedef __u16 qnx4_muid_t; 58 | typedef __u16 qnx4_mgid_t; 59 | typedef __u32 qnx4_off_t; 60 | typedef __u16 qnx4_nlink_t; 61 | 62 | /* 63 | * This is the original qnx4 inode layout on disk. 64 | */ 65 | struct qnx4_inode_entry { 66 | char di_fname[QNX4_SHORT_NAME_MAX]; 67 | qnx4_off_t di_size; 68 | qnx4_xtnt_t di_first_xtnt; 69 | __u32 di_xblk; 70 | __s32 di_ftime; 71 | __s32 di_mtime; 72 | __s32 di_atime; 73 | __s32 di_ctime; 74 | qnx4_nxtnt_t di_num_xtnts; 75 | qnx4_mode_t di_mode; 76 | qnx4_muid_t di_uid; 77 | qnx4_mgid_t di_gid; 78 | qnx4_nlink_t di_nlink; 79 | __u8 di_zero[4]; 80 | qnx4_ftype_t di_type; 81 | __u8 di_status; 82 | }; 83 | 84 | struct qnx4_super_block { 85 | struct qnx4_inode_entry RootDir; 86 | struct qnx4_inode_entry Inode; 87 | struct qnx4_inode_entry Boot; 88 | struct qnx4_inode_entry AltBoot; 89 | }; 90 | 91 | #endif /* _GM_QNX4_H */ 92 | -------------------------------------------------------------------------------- /src/gm_reiserfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_reiserfs.c -- gpart ReiserFS guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 21.01.1999 13 | * Modified: 26.12.2000 Francis Devereux 14 | * Added reiserfs 3.5.28 support. 15 | * Modified: 10.01.2003 Yury Umanets 16 | * Added reiserfs 3.6.x support. 17 | * 18 | */ 19 | 20 | #include 21 | #include 22 | #include "gpart.h" 23 | #include "gm_reiserfs.h" 24 | 25 | int reiserfs_init(disk_desc *d, g_module *m) 26 | { 27 | if ((d == 0) || (m == 0)) 28 | return (0); 29 | 30 | m->m_desc = "ReiserFS filesystem"; 31 | return (REISERFS_FIRST_BLOCK * 1024 + SB_V35_SIZE); 32 | } 33 | 34 | int reiserfs_term(disk_desc *d) { return (1); } 35 | 36 | int reiserfs_gfun(disk_desc *d, g_module *m) 37 | { 38 | struct reiserfs_super_block_v35 *sb; 39 | dos_part_entry *pt = &m->m_part; 40 | s64_t size; 41 | 42 | m->m_guess = GM_NO; 43 | sb = (struct reiserfs_super_block_v35 *)(d->d_sbuf + REISERFS_FIRST_BLOCK * 1024); 44 | if (strncmp(sb->s_magic, REISERFS_SUPER_V35_MAGIC, 12) == 0 || 45 | strncmp(sb->s_magic, REISERFS_SUPER_V36_MAGIC, 12) == 0) { 46 | /* 47 | * sanity checks. 48 | */ 49 | 50 | if (sb->s_block_count < sb->s_free_blocks) 51 | return (1); 52 | 53 | if (sb->s_block_count < REISERFS_MIN_BLOCK_AMOUNT) 54 | return (1); 55 | 56 | if ((sb->s_state != REISERFS_VALID_FS) && (sb->s_state != REISERFS_ERROR_FS)) 57 | return (1); 58 | 59 | if (sb->s_oid_maxsize % 2) /* must be even */ 60 | return (1); 61 | 62 | if (sb->s_oid_maxsize < sb->s_oid_cursize) 63 | return (1); 64 | 65 | if ((sb->s_blocksize != 4096) && (sb->s_blocksize != 8192)) 66 | return (1); 67 | 68 | /* 69 | * ok. 70 | */ 71 | 72 | m->m_guess = GM_YES; 73 | pt->p_start = d->d_nsb; 74 | size = sb->s_block_count; 75 | size *= sb->s_blocksize; 76 | size /= d->d_ssize; 77 | pt->p_size = (unsigned long)size; 78 | pt->p_typ = 0x83; 79 | } 80 | return (1); 81 | } 82 | -------------------------------------------------------------------------------- /src/gm_reiserfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_reiserfs.h -- gpart ReiserFS guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 21.01.1999 13 | * Modified: 26.12.2000 Francis Devereux 14 | * Update support reiserfs version 3.5.28 15 | * Modified: 10.01.2003 Yury Umanets 16 | * Added reiserfs 3.6.x support. 17 | * 18 | */ 19 | 20 | #ifndef _GM_reiserfs_H 21 | #define _GM_reiserfs_H 22 | 23 | /* imported from asm/types.h */ 24 | typedef __signed__ char __s8; 25 | typedef unsigned char __u8; 26 | 27 | typedef __signed__ short __s16; 28 | typedef unsigned short __u16; 29 | 30 | typedef __signed__ int __s32; 31 | typedef unsigned int __u32; 32 | 33 | /* 34 | * taken from ReiserFS v3.5.28, v3.6.x. Reiserfs Copyright 1996-2000 Hans Reiser 35 | */ 36 | 37 | #define REISERFS_SUPER_V35_MAGIC "ReIsErFs" 38 | #define REISERFS_SUPER_V36_MAGIC "ReIsEr2Fs" 39 | 40 | #define REISERFS_FIRST_BLOCK 64 41 | #define REISERFS_VALID_FS 1 42 | #define REISERFS_ERROR_FS 2 43 | #define REISERFS_MIN_BLOCK_AMOUNT 100 44 | 45 | struct reiserfs_super_block_v35 46 | { 47 | __u32 s_block_count; /* blocks count */ 48 | __u32 s_free_blocks; /* free blocks count */ 49 | __u32 s_root_block; /* root block number */ 50 | __u32 s_journal_block; /* journal block number */ 51 | __u32 s_journal_dev; /* journal device number */ 52 | __u32 s_orig_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ 53 | __u32 s_journal_trans_max; /* max number of blocks in a transaction. */ 54 | __u32 s_journal_block_count; /* total size of the journal. can change over time */ 55 | __u32 s_journal_max_batch; /* max number of blocks to batch into a trans */ 56 | __u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */ 57 | __u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */ 58 | __u16 s_blocksize; /* block size */ 59 | __u16 s_oid_maxsize; /* max size of object id array, see get_objectid() commentary */ 60 | __u16 s_oid_cursize; /* current size of object id array */ 61 | __u16 s_state; /* valid or error */ 62 | char s_magic[12]; /* reiserfs magic string indicates that file system is reiserfs */ 63 | __u32 s_hash_function_code; /* indicate, what hash fuction is being use to sort names in a directory*/ 64 | __u16 s_tree_height; /* height of disk tree */ 65 | __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ 66 | __u16 s_reserved; 67 | }; 68 | 69 | #define SB_V35_SIZE (sizeof(struct reiserfs_super_block_v35)) 70 | 71 | struct reiserfs_super_block_v36 { 72 | struct reiserfs_super_block_v35 s_v35; 73 | __u32 s_inode_generation; 74 | __u32 s_flags; 75 | char s_uuid[16]; 76 | char s_label[16]; 77 | char s_unused[88]; 78 | }; 79 | 80 | #define SB_V36_SIZE (sizeof(struct reiserfs_super_block_v36)) 81 | 82 | #endif /* _GM_REISERFS_H */ 83 | -------------------------------------------------------------------------------- /src/gm_s86dl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_s86dl.c -- gpart solaris/x86 disklabel guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include "gpart.h" 18 | #include "gm_s86dl.h" 19 | 20 | int s86dl_init(disk_desc *d, g_module *m) 21 | { 22 | if ((d == 0) || (m == 0)) 23 | return (0); 24 | m->m_desc = "Solaris/x86 disklabel"; 25 | m->m_notinext = 1; 26 | return (512 + sizeof(struct solaris_x86_vtoc)); 27 | } 28 | 29 | int s86dl_term(disk_desc *d) { return (1); } 30 | 31 | int s86dl_gfun(disk_desc *d, g_module *m) 32 | { 33 | struct solaris_x86_vtoc *svtoc; 34 | struct solaris_x86_slice *ws = 0, *rs = 0; 35 | int i; 36 | 37 | m->m_guess = GM_NO; 38 | svtoc = (struct solaris_x86_vtoc *)(d->d_sbuf + 512); 39 | if ((svtoc->v_sanity != SOLARIS_X86_VTOC_SANE) || (svtoc->v_version != SOLARIS_X86_V_VERSION)) 40 | return (1); 41 | 42 | for (i = 0; i < SOLARIS_X86_NUMSLICE; i++) 43 | switch (svtoc->v_slice[i].s_tag) { 44 | case SOLARIS_X86_V_ROOT: 45 | rs = &svtoc->v_slice[i]; 46 | break; 47 | case SOLARIS_X86_V_BACKUP: 48 | ws = &svtoc->v_slice[i]; 49 | break; 50 | } 51 | 52 | /* 53 | * some simple sanity checks. 54 | */ 55 | 56 | if ((ws == 0) || (rs == 0)) 57 | return (1); 58 | if (svtoc->v_sectorsz != d->d_ssize) 59 | return (1); 60 | if (d->d_nsb + ws->s_start + ws->s_size > d->d_nsecs) 61 | return (1); 62 | if (d->d_nsb + rs->s_start + rs->s_size > d->d_nsecs) 63 | return (1); 64 | if ((rs->s_start < ws->s_start) || (rs->s_size > ws->s_size)) 65 | return (1); 66 | if (ws->s_flag && (ws->s_flag != SOLARIS_X86_V_UNMNT) && (ws->s_flag != SOLARIS_X86_V_RONLY)) 67 | return (1); 68 | if (rs->s_flag && (rs->s_flag != SOLARIS_X86_V_UNMNT) && (rs->s_flag != SOLARIS_X86_V_RONLY)) 69 | return (1); 70 | 71 | /* 72 | * If the recognition of the solaris vtoc isn't 73 | * enough, I'll have to read a ufs sb, but for 74 | * now the vtoc must suffice. 75 | */ 76 | 77 | m->m_part.p_typ = 0x82; 78 | m->m_part.p_start = d->d_nsb + le32(ws->s_start); 79 | m->m_part.p_size = le32(ws->s_size); 80 | m->m_guess = GM_YES; 81 | 82 | return (1); 83 | } 84 | -------------------------------------------------------------------------------- /src/gm_s86dl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_s86dl.h -- gpart solaris/x86 disklabel guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_S86DL_H 18 | #define _GM_S86DL_H 19 | 20 | #include 21 | 22 | #define SOLARIS_X86_NUMSLICE 8 23 | #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) 24 | #define SOLARIS_X86_V_VERSION (0x01) 25 | #define SOLARIS_X86_V_UNASSIGNED 0x00 /* unassigned partition */ 26 | #define SOLARIS_X86_V_BOOT 0x01 /* Boot partition */ 27 | #define SOLARIS_X86_V_ROOT 0x02 /* Root filesystem */ 28 | #define SOLARIS_X86_V_SWAP 0x03 /* Swap filesystem */ 29 | #define SOLARIS_X86_V_USR 0x04 /* Usr filesystem */ 30 | #define SOLARIS_X86_V_BACKUP 0x05 /* full disk */ 31 | #define SOLARIS_X86_V_STAND 0x06 /* Stand partition */ 32 | #define SOLARIS_X86_V_VAR 0x07 /* Var partition */ 33 | #define SOLARIS_X86_V_HOME 0x08 /* Home partition */ 34 | #define SOLARIS_X86_V_ALTSCTR 0x09 /* Alternate sector partition */ 35 | #define SOLARIS_X86_V_CACHE 0x0a /* Cache (cachefs) partition */ 36 | #define SOLARIS_X86_V_UNMNT 0x01 /* Unmountable partition */ 37 | #define SOLARIS_X86_V_RONLY 0x10 /* Read only */ 38 | 39 | 40 | 41 | struct solaris_x86_slice { 42 | ushort s_tag; /* ID tag of partition */ 43 | ushort s_flag; /* permision flags */ 44 | __kernel_daddr_t s_start; /* start sector no of partition */ 45 | long s_size; /* # of blocks in partition */ 46 | }; 47 | 48 | struct solaris_x86_vtoc { 49 | unsigned long v_bootinfo[3]; /* info needed by mboot (unsupported) */ 50 | unsigned long v_sanity; /* to verify vtoc sanity */ 51 | unsigned long v_version; /* layout version */ 52 | char v_volume[8]; /* volume name */ 53 | ushort v_sectorsz; /* sector size in bytes */ 54 | ushort v_nparts; /* number of partitions */ 55 | unsigned long v_reserved[10]; /* free space */ 56 | struct solaris_x86_slice 57 | v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ 58 | time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ 59 | char v_asciilabel[128]; /* for compatibility */ 60 | }; 61 | 62 | 63 | #endif /* _GM_S86DL_H */ 64 | -------------------------------------------------------------------------------- /src/gm_xfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_xfs.c -- gpart SGI xfs guessing module 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 30.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include 18 | #include "gpart.h" 19 | #include "gm_xfs.h" 20 | 21 | int xfs_init(disk_desc *d, g_module *m) 22 | { 23 | if ((d == 0) || (m == 0)) 24 | return (0); 25 | 26 | m->m_desc = "SGI XFS filesystem"; 27 | return (512); 28 | } 29 | 30 | int xfs_term(disk_desc *d) { return (1); } 31 | 32 | int xfs_gfun(disk_desc *d, g_module *m) 33 | { 34 | xfs_sb_t *sb; 35 | s64_t size; 36 | 37 | m->m_guess = GM_NO; 38 | sb = (xfs_sb_t *)d->d_sbuf; 39 | 40 | /* 41 | * Sanity checks from xfs_mount.c 42 | */ 43 | 44 | if (be32(sb->sb_magicnum) != XFS_SB_MAGIC) 45 | return (1); 46 | 47 | if (be32(sb->sb_blocksize) != getpagesize()) 48 | return (1); 49 | 50 | if ((sb->sb_imax_pct > 100) || (sb->sb_sectsize <= 0)) 51 | return (1); 52 | 53 | if ((be16(sb->sb_inodesize) < XFS_DINODE_MIN_SIZE) || (be16(sb->sb_inodesize) > XFS_DINODE_MAX_SIZE)) 54 | return (1); 55 | 56 | if (be32(sb->sb_blocksize) != 1 << sb->sb_blocklog) 57 | return (1); 58 | 59 | size = be64(sb->sb_logstart) ? (s64_t)be32(sb->sb_logblocks) : 0LL; 60 | size = be64(sb->sb_dblocks) - size; 61 | size *= be32(sb->sb_blocksize); 62 | size /= d->d_ssize; 63 | 64 | m->m_guess = GM_YES; 65 | m->m_part.p_start = d->d_nsb; 66 | m->m_part.p_size = (unsigned long)size; 67 | m->m_part.p_typ = 0x83; 68 | 69 | return (1); 70 | } 71 | -------------------------------------------------------------------------------- /src/gm_xfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gm_xfs.h -- gpart SGI xfs guessing module header 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 30.01.2001 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GM_XFS_H 18 | #define _GM_XFS_H 19 | 20 | /* imported from asm/types.h */ 21 | typedef __signed__ char __s8; 22 | typedef unsigned char __u8; 23 | 24 | typedef __signed__ short __s16; 25 | typedef unsigned short __u16; 26 | 27 | typedef __signed__ int __s32; 28 | typedef unsigned int __u32; 29 | 30 | typedef __signed__ long long int __s64; 31 | typedef unsigned long long int __u64; 32 | 33 | /* 34 | * Taken from SGI's Jan192001prerelease.patch for Linux kernel 2.4.0 35 | */ 36 | 37 | typedef __u32 xfs_agblock_t; /* blockno in alloc. group */ 38 | typedef __u32 xfs_extlen_t; /* extent length in blocks */ 39 | typedef __u32 xfs_agnumber_t; /* allocation group number */ 40 | typedef __s32 xfs_extnum_t; /* # of extents in a file */ 41 | typedef __s16 xfs_aextnum_t; /* # extents in an attribute fork */ 42 | typedef __s64 xfs_fsize_t; /* bytes in a file */ 43 | typedef __u64 xfs_ufsize_t; /* unsigned bytes in a file */ 44 | 45 | typedef __s32 xfs_suminfo_t; /* type of bitmap summary info */ 46 | typedef __s32 xfs_rtword_t; /* word type for bitmap manipulations */ 47 | 48 | typedef __s64 xfs_lsn_t; /* log sequence number */ 49 | typedef __s32 xfs_tid_t; /* transaction identifier */ 50 | 51 | typedef __u32 xfs_dablk_t; /* dir/attr block number (in file) */ 52 | typedef __u32 xfs_dahash_t; /* dir/attr hash value */ 53 | 54 | typedef __u16 xfs_prid_t; /* prid_t truncated to 16bits in XFS */ 55 | 56 | /* 57 | * These types are 64 bits on disk but are either 32 or 64 bits in memory. 58 | * Disk based types: 59 | */ 60 | typedef __u64 xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ 61 | typedef __u64 xfs_drfsbno_t; /* blockno in filesystem (raw) */ 62 | typedef __u64 xfs_drtbno_t; /* extent (block) in realtime area */ 63 | typedef __u64 xfs_dfiloff_t; /* block number in a file */ 64 | typedef __u64 xfs_dfilblks_t; /* number of blocks in a file */ 65 | 66 | typedef __u64 xfs_off_t; 67 | typedef __s32 xfs32_off_t; 68 | typedef __u64 xfs_ino_t; /* type */ 69 | typedef __s32 xfs_daddr_t; /* type */ 70 | typedef char * xfs_caddr_t; /* type */ 71 | typedef __u32 xfs_dev_t; 72 | 73 | typedef struct { 74 | unsigned char __u_bits[16]; 75 | } uuid_t; 76 | 77 | #define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ 78 | #define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ 79 | #define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ 80 | #define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ 81 | #define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ 82 | 83 | /* 84 | * Inode minimum and maximum sizes. 85 | */ 86 | #define XFS_DINODE_MIN_LOG 8 87 | #define XFS_DINODE_MAX_LOG 11 88 | #define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) 89 | #define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) 90 | 91 | typedef struct xfs_sb 92 | { 93 | __u32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ 94 | __u32 sb_blocksize; /* logical block size, bytes */ 95 | xfs_drfsbno_t sb_dblocks; /* number of data blocks */ 96 | xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ 97 | xfs_drtbno_t sb_rextents; /* number of realtime extents */ 98 | uuid_t sb_uuid; /* file system unique id */ 99 | xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ 100 | xfs_ino_t sb_rootino; /* root inode number */ 101 | xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ 102 | xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ 103 | xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ 104 | xfs_agblock_t sb_agblocks; /* size of an allocation group */ 105 | xfs_agnumber_t sb_agcount; /* number of allocation groups */ 106 | xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ 107 | xfs_extlen_t sb_logblocks; /* number of log blocks */ 108 | __u16 sb_versionnum; /* header version == XFS_SB_VERSION */ 109 | __u16 sb_sectsize; /* volume sector size, bytes */ 110 | __u16 sb_inodesize; /* inode size, bytes */ 111 | __u16 sb_inopblock; /* inodes per block */ 112 | char sb_fname[12]; /* file system name */ 113 | __u8 sb_blocklog; /* log2 of sb_blocksize */ 114 | __u8 sb_sectlog; /* log2 of sb_sectsize */ 115 | __u8 sb_inodelog; /* log2 of sb_inodesize */ 116 | __u8 sb_inopblog; /* log2 of sb_inopblock */ 117 | __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ 118 | __u8 sb_rextslog; /* log2 of sb_rextents */ 119 | __u8 sb_inprogress; /* mkfs is in progress, don't mount */ 120 | __u8 sb_imax_pct; /* max % of fs for inode space */ 121 | /* statistics */ 122 | /* 123 | * These fields must remain contiguous. If you really 124 | * want to change their layout, make sure you fix the 125 | * code in xfs_trans_apply_sb_deltas(). 126 | */ 127 | __u64 sb_icount; /* allocated inodes */ 128 | __u64 sb_ifree; /* free inodes */ 129 | __u64 sb_fdblocks; /* free data blocks */ 130 | __u64 sb_frextents; /* free realtime extents */ 131 | /* 132 | * End contiguous fields. 133 | */ 134 | xfs_ino_t sb_uquotino; /* user quota inode */ 135 | xfs_ino_t sb_pquotino; /* project quota inode */ 136 | __u16 sb_qflags; /* quota flags */ 137 | __u8 sb_flags; /* misc. flags */ 138 | __u8 sb_shared_vn; /* shared version number */ 139 | xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ 140 | __u32 sb_unit; /* stripe or raid unit */ 141 | __u32 sb_width; /* stripe or raid width */ 142 | __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ 143 | __u8 sb_dummy[7]; /* padding */ 144 | } xfs_sb_t; 145 | 146 | #endif /* _GM_XFS_H */ 147 | -------------------------------------------------------------------------------- /src/gmodules.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gmodules.c -- gpart module functions 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 29.01.2001 14 | * New modules: qnx & beos. 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "gpart.h" 22 | 23 | static g_module *g_head; 24 | static int g_count; 25 | 26 | g_module *g_mod_head() { return (g_head); } 27 | 28 | int g_mod_count() { return (g_count); } 29 | 30 | void g_mod_list() 31 | { 32 | g_module *m; 33 | 34 | pr(MSG, "Module\tWeight\n"); 35 | for (m = g_head; m; m = m->m_next) 36 | pr(MSG, "%s\t(%3.1f)\n", m->m_name, m->m_weight); 37 | pr(MSG, "\n"); 38 | } 39 | 40 | void g_mod_delete(g_module *m) 41 | { 42 | if (m) { 43 | if (m->m_name) 44 | free((void *)m->m_name); 45 | free(m); 46 | g_count--; 47 | } 48 | } 49 | 50 | void g_mod_deleteall() 51 | { 52 | g_module *m; 53 | 54 | while (g_head) { 55 | m = g_head->m_next; 56 | g_mod_delete(g_head); 57 | g_head = m; 58 | } 59 | } 60 | 61 | /* 62 | * set weight of module and re-insert as head. 63 | */ 64 | 65 | g_module *g_mod_setweight(char *name, float weight) 66 | { 67 | g_module *m, *prev = 0; 68 | 69 | for (m = g_head; m; m = m->m_next) 70 | if (strcmp(m->m_name, name) == 0) 71 | break; 72 | else 73 | prev = m; 74 | if (m == 0) 75 | return (0); 76 | if (prev) { 77 | prev->m_next = m->m_next; 78 | m->m_next = g_head; 79 | g_head = m; 80 | } 81 | g_head->m_weight = weight; 82 | return (g_head); 83 | } 84 | 85 | g_module *g_mod_lookup(int how, char *name) 86 | { 87 | g_module *m; 88 | 89 | if (g_head == 0) { 90 | if (how == GM_LOOKUP) 91 | return (0); 92 | g_head = (g_module *)alloc(sizeof(g_module)); 93 | m = g_head; 94 | } else { 95 | for (m = g_head; m->m_next; m = m->m_next) 96 | if (strcmp(m->m_name, name) == 0) 97 | return (m); 98 | if (how == GM_LOOKUP) 99 | return (0); 100 | m->m_next = (g_module *)alloc(sizeof(g_module)); 101 | m = m->m_next; 102 | } 103 | if ((m->m_name = strdup(name)) == 0) 104 | pr(FATAL, "out of memory in strdup"); 105 | m->m_weight = 1.0; 106 | g_count++; 107 | return (m); 108 | } 109 | 110 | /* 111 | * preloaded modules 112 | */ 113 | 114 | void g_mod_addinternals() 115 | { 116 | g_module *m; 117 | 118 | #define GMODINS(mod) \ 119 | do { \ 120 | m = g_mod_lookup(GM_INSERT,#mod); \ 121 | if (m) { \ 122 | m->m_init=mod##_init; \ 123 | m->m_term=mod##_term; \ 124 | m->m_gfun=mod##_gfun; \ 125 | } \ 126 | } while (0); 127 | 128 | /* 129 | * If no weights are given on the command line, the order 130 | * is somehow important. 131 | */ 132 | 133 | #define G_MODULE(mod) GMODINS(mod) 134 | G_MODULES 135 | #undef G_MODULE 136 | } 137 | -------------------------------------------------------------------------------- /src/gmodules.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gmodules.h -- gpart module header file 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 29.01.2001 14 | * New modules: qnx & beos. 15 | * 16 | */ 17 | 18 | #ifndef _GMODULES_H 19 | #define _GMODULES_H 20 | 21 | 22 | #define GM_NO (0.0) /* predefined probabilities */ 23 | #define GM_PERHAPS (0.5) 24 | #define GM_YES (0.8) 25 | #define GM_UNDOUBTEDLY (1.0) 26 | 27 | typedef struct g_mod 28 | { 29 | char *m_name; /* name of module */ 30 | char *m_desc; /* readable description */ 31 | int (*m_init)(disk_desc *,struct g_mod *); 32 | int (*m_term)(disk_desc *); 33 | int (*m_gfun)(disk_desc *,struct g_mod *); 34 | float m_guess; 35 | float m_weight; /* probability weight */ 36 | dos_part_entry m_part; /* a guessed partition entry */ 37 | long m_align; /* alignment of partition */ 38 | struct g_mod *m_next; 39 | unsigned int m_hasptbl : 1; /* has a ptbl like entry in sec 0 */ 40 | unsigned int m_notinext : 1; /* cannot exist in an ext part. */ 41 | unsigned int m_skip : 1; /* skip this module this time */ 42 | } g_module; 43 | 44 | #define GM_LOOKUP 0 45 | #define GM_INSERT 1 46 | 47 | void g_mod_list(), g_mod_delete(g_module *), g_mod_deleteall(); 48 | g_module *g_mod_head(), *g_mod_lookup(int,char *); 49 | void g_mod_addinternals(); 50 | int g_mod_count(); 51 | g_module *g_mod_setweight(char *,float); 52 | 53 | 54 | 55 | /* 56 | * preloaded guessing modules, order is important as it is also the order of registering and guessing 57 | */ 58 | 59 | #define G_MODULES \ 60 | G_MODULE(bsddl) \ 61 | G_MODULE(lswap) \ 62 | G_MODULE(qnx4) \ 63 | G_MODULE(reiserfs) \ 64 | G_MODULE(ntfs) \ 65 | G_MODULE(hpfs) \ 66 | G_MODULE(minix) \ 67 | G_MODULE(beos) \ 68 | G_MODULE(ext2) \ 69 | G_MODULE(btrfs) \ 70 | G_MODULE(fat) \ 71 | G_MODULE(s86dl) \ 72 | G_MODULE(hmlvm) \ 73 | G_MODULE(lvm2) \ 74 | G_MODULE(xfs) 75 | 76 | #define G_MODULE(mod) int mod##_init(disk_desc *,g_module *), \ 77 | mod##_term(disk_desc *), \ 78 | mod##_gfun(disk_desc *,g_module *); 79 | G_MODULES 80 | #undef G_MODULE 81 | 82 | #endif /* _GMODULES_H */ 83 | -------------------------------------------------------------------------------- /src/gpart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gpart.c -- gpart main 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 11.06.1999 14 | * Handle disk read errors. 15 | * Minor fixes. 16 | * 17 | * 29.06.1999 18 | * Made every disk read/write buffer aligned to pagesize. 19 | * 20 | * 29.08.1999 21 | * Default scan increment now 's'. 22 | * Extended ptbl boundary condition now depends on scan 23 | * increment. 24 | * 25 | * 26.02.2000 26 | * Default scan increment 'h' again. 27 | * Fixed faulty head boundary condition. 28 | * Introduced ptbl entry editing after guess loop. 29 | * First scanned sector is no of sects/head, if no start 30 | * sector was given. 31 | * m_notinext now honoured. 32 | * Make a MBR backup. 33 | * Interactive mode now somehow works. 34 | * 35 | * 14.05.2000 36 | * Made writing of guessed table also aligned. 37 | * Fixed stupid copy&paste bug in the check routine 38 | * (found by Bruno Bozza . 39 | * 40 | * 29.01.2001 41 | * Extended partition type on an LBA disk now 0x0f instead 42 | * of 0x05. Changed some partition types (get_part_type). 43 | * When comparing partition types in extptbl links, try 44 | * to compare similarity, not equality (is_same_partition_type). 45 | * 46 | */ 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include "gpart.h" 59 | 60 | static const char *gpart_version = PACKAGE_NAME " v" VERSION; 61 | 62 | int f_check = 0, f_verbose = 0, f_dontguess = 0, f_fast = 1; 63 | int f_getgeom = 1, f_interactive = 0, f_quiet = 0, f_testext = 1; 64 | int f_skiperrors = 1, berrno = 0; 65 | int (*boundary_fun)(disk_desc *, s64_t); 66 | unsigned long increment = 's', gc = 0, gh = 0, gs = 0; 67 | s64_t skipsec = 0, maxsec = 0; 68 | FILE *logfile = 0; 69 | 70 | void usage() 71 | { 72 | FILE *fp = stderr; 73 | 74 | fprintf(fp, "Usage: %s [options] device\n", PACKAGE_NAME); 75 | fprintf(fp, "Options: [-b ][-C c,h,s][-c][-d][-E][-e][-f][-g][-h][-i]\n"); 76 | fprintf(fp, " [-K ][-k <# of sectors>][-L][-l ]\n"); 77 | fprintf(fp, " [-n ][-q][-s ]\n"); 78 | fprintf(fp, " [-V][-v][-W ][-w ]\n"); 79 | fprintf(fp, "%s (c) 1999-2001 Michail Brzitwa .\n", gpart_version); 80 | fprintf(fp, "Guess PC-type hard disk partitions.\n\n"); 81 | fprintf(fp, "Options:\n"); 82 | fprintf(fp, " -b Save a backup of the original MBR to specified file.\n"); 83 | fprintf(fp, " -C Set c/h/s to be used in the scan.\n"); 84 | fprintf(fp, " -c Check/compare mode.\n"); 85 | fprintf(fp, " -d Do not start the guessing loop.\n"); 86 | fprintf(fp, " -E Do not try to identify extended partition tables.\n"); 87 | fprintf(fp, " -e Do not skip disk read errors.\n"); 88 | fprintf(fp, " -f Full scan.\n"); 89 | fprintf(fp, " -g Do not try to get the disk geometry.\n"); 90 | fprintf(fp, " -h Show this help.\n"); 91 | fprintf(fp, " -i Run interactively (ask for confirmation).\n"); 92 | fprintf(fp, " -K Scan only up to given sector.\n"); 93 | fprintf(fp, " -k Skip sectors before scan.\n"); 94 | fprintf(fp, " -L List available modules and their weights, then exit.\n"); 95 | fprintf(fp, " -l Logfile name.\n"); 96 | fprintf(fp, " -n Scan increment: number or 's' sector, 'h' head, 'c' cylinder.\n"); 97 | fprintf(fp, " -q Run quiet (however log file is written if specified).\n"); 98 | fprintf(fp, " -s Sector size to use (disable sector size probing).\n"); 99 | fprintf(fp, " -V Show version.\n"); 100 | fprintf(fp, " -v Verbose mode. Can be given more than once.\n"); 101 | fprintf(fp, " -W Write guessed primary partition table to given device or file.\n"); 102 | fprintf(fp, " -w Weight factor of module.\n"); 103 | fprintf(fp, "\n"); 104 | } 105 | 106 | void pr(int type, char *fmt, ...) 107 | { 108 | va_list vl; 109 | static char msg[512]; 110 | 111 | va_start(vl, fmt); 112 | vsnprintf(msg, 511, fmt, vl); 113 | va_end(vl); 114 | msg[511] = 0; 115 | switch (type) { 116 | case FATAL: 117 | g_mod_deleteall(); 118 | if (!f_quiet) 119 | fprintf(stderr, EM_FATALERROR, msg); 120 | if (logfile) { 121 | fprintf(logfile, EM_FATALERROR, msg); 122 | fclose(logfile); 123 | } 124 | exit(1); 125 | case ERROR: 126 | if (!f_quiet) 127 | fprintf(stderr, EM_SIMPLEERROR, msg); 128 | if (logfile) 129 | fprintf(logfile, EM_SIMPLEERROR, msg); 130 | break; 131 | case WARN: 132 | if (!f_quiet) 133 | fprintf(stderr, EM_WARNING, msg); 134 | if (logfile) 135 | fprintf(logfile, EM_WARNING, msg); 136 | break; 137 | case MSG: 138 | if (!f_quiet) 139 | fputs(msg, stdout); 140 | fflush(stdout); 141 | if (logfile) 142 | fputs(msg, logfile); 143 | break; 144 | } 145 | if (logfile) 146 | fflush(logfile); 147 | } 148 | 149 | byte_t *alloc(ssize_t s) 150 | { 151 | byte_t *p = (byte_t *)malloc(s); 152 | 153 | if (p == 0) 154 | pr(FATAL, EM_MALLOCFAILED, s); 155 | memset(p, 0, s); 156 | return (p); 157 | } 158 | 159 | /* 160 | * read nsecs blocks of ssize bytes from fd 161 | */ 162 | 163 | ssize_t bread(int fd, byte_t *buf, size_t ssize, size_t nsecs) 164 | { 165 | const size_t total = ssize * nsecs; 166 | size_t read_bytes = 0; 167 | 168 | while (read_bytes < total) { 169 | ssize_t ret = read(fd, buf + read_bytes, total - read_bytes); 170 | if (ret > 0) 171 | read_bytes += ret; 172 | else if (ret == 0) { 173 | return read_bytes; 174 | } else { 175 | // ret < 0, an error case 176 | if (errno == EINTR) 177 | continue; // Rogue signal interruption, retry 178 | berrno = errno; 179 | break; 180 | } 181 | } 182 | 183 | return read_bytes ? read_bytes : -1; 184 | } 185 | 186 | static int yesno(char *q) 187 | { 188 | int ch = 0; 189 | char buf[3]; 190 | 191 | pr(MSG, q); 192 | pr(MSG, " %s : ", DM_YESNO); 193 | if (fgets(buf, 3, stdin)) 194 | ch = *buf; 195 | pr(MSG, "\n"); 196 | return (strchr(DM_YES, ch) == 0 ? 0 : 1); 197 | } 198 | 199 | static long number_or_quit(char *m, long lo, long up) 200 | { 201 | char buf[32]; 202 | long num = -1; 203 | 204 | pr(MSG, m); 205 | pr(MSG, DM_NUMORQUIT, lo, up); 206 | if (fgets(buf, 32, stdin)) { 207 | if (strchr(DM_QUIT, *buf)) 208 | return (-1); 209 | num = strtoul(buf, 0, 0); 210 | if (errno == ERANGE) 211 | return (-1); 212 | } 213 | return (num); 214 | } 215 | 216 | /* 217 | * get three comma separated strings. 218 | */ 219 | 220 | static int get_csep_arg(char *arg, char **p1, char **p2, char **p3) 221 | { 222 | char *p; 223 | 224 | if (p1) 225 | *p1 = arg; 226 | else 227 | return (0); 228 | if ((p = strchr(arg, ',')) == 0) 229 | return (0); 230 | *p = 0; 231 | arg = p + 1; 232 | if (p2) 233 | *p2 = arg; 234 | else 235 | return (1); 236 | if (p3) { 237 | if ((p = strchr(arg, ',')) == 0) 238 | return (0); 239 | *p = 0; 240 | *p3 = p + 1; 241 | } 242 | return (1); 243 | } 244 | 245 | /* 246 | * partition type list, taken from *BSD i386 fdisk, cfdisk etc. 247 | */ 248 | 249 | static char *get_part_type(int type) 250 | { 251 | int i; 252 | struct { 253 | int t; 254 | char *n; 255 | } ptypes[] = {{0x00, "unused"}, 256 | {0x01, "Primary DOS with 12 bit FAT"}, 257 | {0x02, "XENIX / filesystem"}, 258 | {0x03, "XENIX /usr filesystem"}, 259 | {0x04, "Primary DOS with 16 bit FAT (<= 32MB)"}, 260 | {0x05, "Extended DOS"}, 261 | {0x06, "Primary 'big' DOS (> 32MB)"}, 262 | {0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX"}, 263 | {0x08, "AIX filesystem"}, 264 | {0x09, "AIX boot partition or Coherent"}, 265 | {0x0A, "OS/2 Boot Manager or OPUS"}, 266 | {0x0B, "DOS or Windows 95 with 32 bit FAT"}, 267 | {0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"}, 268 | {0x0E, "Primary 'big' DOS (> 32MB, LBA)"}, 269 | {0x0F, "Extended DOS, LBA"}, 270 | {0x10, "OPUS"}, 271 | {0x11, "Hidden DOS with 12 bit FAT"}, 272 | {0x12, "Compaq Diagnostics"}, 273 | {0x14, "Hidden DOS with 16 bit FAT (<= 32MB)"}, 274 | {0x16, "Hidden 'big' DOS (> 32MB)"}, 275 | {0x17, "OS/2 Boot Manager HPFS"}, 276 | {0x18, "AST special Windows swap file"}, 277 | {0x24, "NEC MS-DOS 3.x"}, 278 | {0x3C, "PowerQuest PartitionMagic recovery partition"}, 279 | {0x40, "VENIX 286"}, 280 | {0x4D, "QNX4.x"}, 281 | {0x4E, "QNX4.x 2nd part"}, 282 | {0x4F, "QNX4.x 3rd part"}, 283 | {0x50, "DM"}, 284 | {0x51, "DM"}, 285 | {0x51, "DM"}, 286 | {0x52, "CP/M or Microport SysV/AT"}, 287 | {0x55, "EZ Drive"}, 288 | {0x56, "GB"}, 289 | {0x61, "SpeedStor"}, 290 | {0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}, 291 | {0x64, "Novell Netware 2.xx"}, 292 | {0x65, "Novell Netware 3.xx"}, 293 | {0x70, "DiskSecure Multi-Boot"}, 294 | {0x75, "PCIX"}, 295 | {0x80, "Minix V1"}, 296 | {0x81, "Minix V2/Linux"}, 297 | {0x82, "Linux swap or Solaris/x86"}, 298 | {0x83, "Linux ext2 filesystem"}, 299 | {0x85, "Extended Linux"}, 300 | {0x86, "FAT16 volume/stripe set"}, 301 | {0x8E, "Linux LVM physical volume"}, 302 | {0x93, "Amoeba filesystem"}, 303 | {0x94, "Amoeba bad block table"}, 304 | {0xA5, "FreeBSD/NetBSD/386BSD"}, 305 | {0xA6, "OpenBSD"}, 306 | {0xA7, "NEXTSTEP"}, 307 | {0xB7, "BSDI BSD/386 filesystem"}, 308 | {0xB8, "BSDI BSD/386 swap"}, 309 | {0xC7, "Syrinx"}, 310 | {0xDB, "Concurrent CPM or C.DOS or CTOS"}, 311 | {0xE1, "SpeedStor 12-bit FAT extended"}, 312 | {0xE3, "Speed"}, 313 | {0xE4, "SpeedStor 16-bit FAT"}, 314 | {0xEB, "BeOS fs"}, 315 | {0xF1, "SpeedStor"}, 316 | {0xF2, "DOS 3.3+ Secondary"}, 317 | {0xF4, "SpeedStor"}, 318 | {0xFD, "Linux raid autodetect"}, 319 | {0xFE, "LANstep"}, 320 | {0xFF, "BBT (Bad Blocks Table)"}}; 321 | 322 | for (i = 0; i < sizeof(ptypes) / sizeof(ptypes[0]); i++) 323 | if (type == ptypes[i].t) 324 | return (ptypes[i].n); 325 | return (0); 326 | } 327 | 328 | static int is_ext_parttype(dos_part_entry *p) 329 | { 330 | return (p->p_size && ((p->p_typ == 0x05) || (p->p_typ == 0x0F) || (p->p_typ == 0x85))); 331 | } 332 | 333 | static int is_sane_partentry(disk_desc *d, dos_part_entry *p, int c) 334 | { 335 | if (p->p_start >= d->d_nsecs) { 336 | if (c) 337 | pr(WARN, EM_PSTART2BIG, get_part_type(p->p_typ)); 338 | return (0); 339 | } 340 | if (p->p_size > d->d_nsecs) { 341 | if (c) 342 | pr(WARN, EM_PSIZE2BIG, get_part_type(p->p_typ)); 343 | return (0); 344 | } 345 | if (p->p_start + p->p_size > d->d_nsecs) { 346 | if (c) 347 | pr(WARN, EM_PEND2BIG, get_part_type(p->p_typ)); 348 | return (0); 349 | } 350 | if (p->p_flag && (p->p_flag != DOSPARTACTIVE)) { 351 | if (c) 352 | pr(WARN, EM_STRANGEPTYPE, get_part_type(p->p_typ)); 353 | return (0); 354 | } 355 | return (1); 356 | } 357 | 358 | static int is_real_parttype(dos_part_entry *p) { return (!is_ext_parttype(p) && p->p_typ && get_part_type(p->p_typ)); } 359 | 360 | static int no_of_ext_partitions(dos_part_entry *p) 361 | { 362 | dos_part_entry *t; 363 | int ne = 0; 364 | 365 | for (t = &p[0]; t <= &p[NDOSPARTS - 1]; t++) 366 | if (is_ext_parttype(t)) 367 | ne++; 368 | return (ne); 369 | } 370 | 371 | static int no_of_real_partitions(dos_part_entry *p) 372 | { 373 | dos_part_entry *t; 374 | int nr = 0; 375 | 376 | for (t = &p[0]; t <= &p[NDOSPARTS - 1]; t++) 377 | if (is_real_parttype(t)) 378 | nr++; 379 | return (nr); 380 | } 381 | 382 | /* 383 | * Test similarity of partition types 384 | */ 385 | 386 | static int is_same_partition_type(dos_part_entry *p1, dos_part_entry *p2) 387 | { 388 | int ret = 0; 389 | 390 | switch (p1->p_typ) { 391 | case 0x01: 392 | case 0x11: 393 | ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E); 394 | break; 395 | 396 | case 0x06: 397 | case 0x0E: 398 | case 0x16: 399 | ret = (p2->p_typ == 0x06) || (p2->p_typ == 0x0E) || (p2->p_typ == 0x16); 400 | break; 401 | 402 | case 0x05: 403 | case 0x0F: 404 | ret = (p2->p_typ == 0x05) || (p2->p_typ == 0x0F); 405 | break; 406 | 407 | case 0x0B: 408 | case 0x0C: 409 | ret = (p2->p_typ == 0x0B) || (p2->p_typ == 0x0C); 410 | break; 411 | 412 | case 0x8E: 413 | case 0xFE: 414 | ret = (p2->p_typ == 0x8E) || (p2->p_typ == 0xFE); 415 | break; 416 | 417 | default: 418 | ret = p1->p_typ == p2->p_typ; 419 | break; 420 | } 421 | return (ret); 422 | } 423 | 424 | /* 425 | * detecting an extended ptbl isn't unambiguous, the boot code 426 | * preceding the ptbl should be zeroed but isn't always. The 427 | * ptbl should in theory contain one 'normal' entry, zero or 428 | * one link to the next extended ptbl and two or three zeroed 429 | * entries. 430 | */ 431 | 432 | static int is_ext_parttable(disk_desc *d, byte_t *buf) 433 | { 434 | int r, e; 435 | byte_t *magic; 436 | dos_part_entry *p, *t; 437 | 438 | p = (dos_part_entry *)(buf + DOSPARTOFF); 439 | magic = (byte_t *)&p[NDOSPARTS]; 440 | if (*(unsigned short *)magic != le16(DOSPTMAGIC)) 441 | return (0); 442 | 443 | /* 444 | * ptbl sanity checks. 445 | */ 446 | 447 | for (t = p; t <= &p[NDOSPARTS - 1]; t++) 448 | if (!is_sane_partentry(d, t, 0)) 449 | return (0); 450 | 451 | /* 452 | * one real, zero or one extended and two or three unused 453 | * partition entries. 454 | */ 455 | 456 | r = no_of_real_partitions(p); 457 | e = no_of_ext_partitions(p); 458 | return ((r == 1) && ((e == 0) || (e == 1))); 459 | } 460 | 461 | static void fillin_dos_chs(disk_desc *d, dos_part_entry *p, s64_t offset) 462 | { 463 | unsigned long n; 464 | 465 | n = p->p_start; 466 | if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s) { 467 | p->p_ssect = d->d_dg.d_s | ((1023 >> 2) & 0xc0); 468 | p->p_shd = d->d_dg.d_h - 1; 469 | p->p_scyl = 1023 & 0xff; 470 | } else { 471 | p->p_ssect = (n % d->d_dg.d_s) + 1; 472 | n /= d->d_dg.d_s; 473 | p->p_shd = n % d->d_dg.d_h; 474 | n /= d->d_dg.d_h; 475 | p->p_scyl = n & 0xff; 476 | p->p_ssect |= (n >> 2) & 0xc0; 477 | } 478 | n = p->p_size + p->p_start - 1; 479 | if (n > 1023 * d->d_dg.d_h * d->d_dg.d_s) { 480 | p->p_esect = d->d_dg.d_s | ((1023 >> 2) & 0xc0); 481 | p->p_ehd = d->d_dg.d_h - 1; 482 | p->p_ecyl = 1023 & 0xff; 483 | } else { 484 | p->p_esect = (n % d->d_dg.d_s) + 1; 485 | n /= d->d_dg.d_s; 486 | p->p_ehd = n % d->d_dg.d_h; 487 | n /= d->d_dg.d_h; 488 | p->p_ecyl = n & 0xff; 489 | p->p_esect |= (n >> 2) & 0xc0; 490 | } 491 | } 492 | 493 | static void u_to_chs(disk_desc *d, unsigned long u, long *c, long *h, long *s) 494 | { 495 | struct disk_geom *g = &d->d_dg; 496 | 497 | *c = *h = *s = 0; 498 | if (g->d_h && g->d_s && u) { 499 | *c = u / (g->d_h * g->d_s); 500 | *h = (u / g->d_s) % g->d_h; 501 | *s = u % g->d_s + 1; 502 | } 503 | } 504 | 505 | static int on_cyl_boundary(disk_desc *d, s64_t sec) 506 | { 507 | struct disk_geom *g = &d->d_dg; 508 | 509 | if (g->d_h && g->d_s) 510 | return ((sec % (g->d_h * g->d_s)) == 0); 511 | return (1); 512 | } 513 | 514 | static int on_head_boundary(disk_desc *d, s64_t sec) 515 | { 516 | struct disk_geom *g = &d->d_dg; 517 | 518 | if (g->d_s) 519 | return ((sec % g->d_s) == 0); 520 | return (1); 521 | } 522 | 523 | static void print_partition(disk_desc *d, dos_part_entry *p, int inset, s64_t offset) 524 | { 525 | long i, c = 0, h = 0, s = 0; 526 | s64_t size; 527 | char *ptyp = get_part_type(p->p_typ); 528 | 529 | #define indent(s) \ 530 | for (i = 0; i < s; i++) \ 531 | pr(MSG, " ") 532 | 533 | size = p->p_size; 534 | s2mb(d, size); 535 | indent(inset); 536 | pr(MSG, PM_PT_TYPE, p->p_typ, p->p_typ, ptyp ? ptyp : "UNKNOWN"); 537 | if (p->p_flag == DOSPARTACTIVE) 538 | pr(MSG, " (BOOT)"); 539 | pr(MSG, "\n"); 540 | 541 | indent(inset); 542 | pr(MSG, PM_PT_SIZE, size, (s64_t)p->p_size); 543 | size = p->p_start; 544 | size += offset; 545 | size += p->p_size; 546 | if (size) 547 | size -= 1; 548 | pr(MSG, " s(%qd-%qd)\n", (s64_t)p->p_start + offset, size); 549 | 550 | indent(inset); 551 | 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), 552 | p->p_ehd, DOSSEC(p->p_esect)); 553 | if (size) 554 | u_to_chs(d, p->p_start + offset, &c, &h, &s); 555 | pr(MSG, " (%ld/%ld/%ld)-", c, h, s); 556 | if (size) 557 | u_to_chs(d, p->p_start + offset + p->p_size - 1, &c, &h, &s); 558 | pr(MSG, "(%ld/%ld/%ld)r\n", c, h, s); 559 | 560 | if (f_verbose > 0) { 561 | indent(inset); 562 | pr(MSG, PM_PT_HEX); 563 | for (i = 0; i < sizeof(dos_part_entry); i++) 564 | pr(MSG, " %02X", ((byte_t *)p)[i]); 565 | pr(MSG, "\n"); 566 | } 567 | pr(MSG, "\n"); 568 | } 569 | 570 | static void print_ext_partitions(disk_desc *d, s64_t offset) 571 | { 572 | dos_part_table *pt = d->d_pt.t_ext; 573 | dos_part_entry *p; 574 | s64_t extst = 0; 575 | 576 | for (; pt; pt = pt->t_ext) { 577 | pr(MSG, PM_EXTPART); 578 | for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) 579 | if (is_real_parttype(p)) 580 | print_partition(d, p, 1, offset + extst); 581 | 582 | for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) 583 | if (is_ext_parttype(p)) 584 | extst = p->p_start; 585 | } 586 | } 587 | 588 | static void print_ptable(disk_desc *d, dos_part_table *pt, int pr_ext) 589 | { 590 | int n; 591 | 592 | for (n = 0; n < NDOSPARTS; n++) { 593 | pr(MSG, PM_PRIMPART, n + 1); 594 | print_partition(d, &pt->t_parts[n], 0, 0); 595 | if (pr_ext && is_ext_parttype(&pt->t_parts[n])) 596 | print_ext_partitions(d, pt->t_parts[n].p_start); 597 | } 598 | } 599 | 600 | static void print_disk_desc(disk_desc *d) 601 | { 602 | s64_t s; 603 | 604 | pr(MSG, PM_DEVDESC1, d->d_dev, d->d_ssize); 605 | if (f_getgeom) { 606 | s = d->d_nsecs; 607 | s2mb(d, s); 608 | 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); 609 | } 610 | pr(MSG, "\n"); 611 | if (d->d_pt.t_magic != le16(DOSPTMAGIC)) 612 | pr(WARN, EM_STRANGEPTBLMAGIC, d->d_pt.t_magic); 613 | print_ptable(d, &d->d_pt, 1); 614 | } 615 | 616 | static void print_mboot_block(disk_desc *d) 617 | { 618 | int n, m, cols = 16; 619 | byte_t *boot = d->d_pt.t_boot; 620 | 621 | pr(MSG, PM_MBRPRINT, d->d_dev); 622 | for (n = 0; n < DOSPARTOFF - cols; n += cols) { 623 | pr(MSG, " %04X: ", n); 624 | for (m = n; m < n + cols; m++) 625 | pr(MSG, " %02x", boot[m]); 626 | pr(MSG, "\n "); 627 | for (m = n; m < n + cols; m++) 628 | pr(MSG, " %c ", isprint(boot[m]) ? boot[m] : '.'); 629 | pr(MSG, "\n"); 630 | } 631 | } 632 | 633 | static void read_part_table(disk_desc *d, s64_t sec, byte_t *where) 634 | { 635 | ssize_t rd; 636 | size_t psize; 637 | byte_t *ubuf, *buf; 638 | 639 | psize = getpagesize(); 640 | ubuf = alloc(MAXSSIZE + psize); 641 | buf = align(ubuf, psize); 642 | sec *= d->d_ssize; 643 | if (l64seek(d->d_fd, sec, SEEK_SET) == -1) 644 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 645 | 646 | if (d->d_ssize < 512) 647 | rd = bread(d->d_fd, buf, d->d_ssize, 512 / d->d_ssize); 648 | else 649 | rd = bread(d->d_fd, buf, d->d_ssize, 1); 650 | 651 | if (rd == -1) 652 | pr(FATAL, EM_PTBLREAD); 653 | memcpy(where, buf, 512); 654 | free((void *)ubuf); 655 | } 656 | 657 | static void read_ext_part_table(disk_desc *d, dos_part_table *pt) 658 | { 659 | dos_part_entry *p, *ep; 660 | s64_t epsize, epstart, epoffset; 661 | int epcount; 662 | 663 | epsize = epstart = epoffset = epcount = 0; 664 | while (1) { 665 | ep = 0; 666 | for (p = pt->t_parts; p <= &pt->t_parts[NDOSPARTS - 1]; p++) 667 | if (is_ext_parttype(p)) { 668 | if (ep == 0) { 669 | ep = p; 670 | break; 671 | } 672 | pr(ERROR, EM_TOOMANYEXTP); 673 | } 674 | 675 | if (ep == 0) 676 | return; 677 | if (++epcount > 128) /* arbitrary maximum */ 678 | { 679 | pr(ERROR, EM_TOOMANYLOGP, 128); 680 | return; 681 | } 682 | if (epstart == 0) { 683 | epstart = ep->p_start; 684 | epsize = ep->p_size; 685 | epoffset = 0; 686 | } else 687 | epoffset = ep->p_start; 688 | if (epoffset > epsize) { 689 | pr(ERROR, EM_EPILLEGALOFS); 690 | return; 691 | } 692 | 693 | /* 694 | * link in new extended ptbl. 695 | */ 696 | 697 | pt->t_ext = (dos_part_table *)alloc(sizeof(dos_part_table)); 698 | read_part_table(d, epstart + epoffset, (pt = pt->t_ext)->t_boot); 699 | if (!is_ext_parttable(d, pt->t_boot)) { 700 | pr(ERROR, EM_INVXPTBL, epstart + epoffset); 701 | return; 702 | } 703 | } 704 | } 705 | 706 | static void free_disk_desc(disk_desc *d) 707 | { 708 | dos_part_table *pt; 709 | dos_guessed_pt *pg; 710 | void *t; 711 | 712 | for (pt = d->d_pt.t_ext; pt;) { 713 | t = pt->t_ext; 714 | free((void *)pt); 715 | pt = t; 716 | } 717 | for (pt = d->d_gpt.t_ext; pt;) { 718 | t = pt->t_ext; 719 | free((void *)pt); 720 | pt = t; 721 | } 722 | for (pg = d->d_gl; pg;) { 723 | t = pg->g_next; 724 | free((void *)pg); 725 | pg = t; 726 | } 727 | free((void *)d); 728 | } 729 | 730 | static disk_desc *get_disk_desc(char *dev, int sectsize) 731 | { 732 | byte_t *ubuf, *buf; 733 | disk_desc *d; 734 | int psize, ssize; 735 | struct disk_geom *dg; 736 | 737 | psize = getpagesize(); 738 | ubuf = alloc(MAXSSIZE + psize); 739 | buf = align(ubuf, psize); 740 | d = (disk_desc *)alloc(sizeof(disk_desc)); 741 | 742 | /* 743 | * I don't care if the given name denotes a block or character 744 | * special file or just a regular file. 745 | */ 746 | 747 | if ((d->d_fd = open(dev, O_RDONLY)) == -1) 748 | pr(FATAL, EM_OPENFAIL, dev, strerror(errno)); 749 | 750 | /* 751 | * try to test for sector sizes (doesn't work under many systems). 752 | */ 753 | 754 | if (sectsize > MAXSSIZE) 755 | pr(FATAL, EM_WRONGSECTSIZE, MAXSSIZE); 756 | 757 | if (sectsize) { 758 | ssize = bread(d->d_fd, buf, sectsize, 1); 759 | if (ssize != sectsize) 760 | pr(FATAL, EM_FAILSSIZEATTEMPT, sectsize); 761 | d->d_ssize = sectsize; 762 | } else { 763 | for (d->d_ssize = MINSSIZE; d->d_ssize <= MAXSSIZE; d->d_ssize *= 2) { 764 | if (l64seek(d->d_fd, 0, SEEK_SET) == -1) 765 | pr(FATAL, EM_SEEKFAILURE, dev); 766 | ssize = bread(d->d_fd, buf, d->d_ssize, 1); 767 | if (ssize == d->d_ssize) 768 | break; 769 | } 770 | if (ssize == -1) 771 | pr(FATAL, EM_CANTGETSSIZE, dev); 772 | } 773 | 774 | d->d_dev = dev; 775 | read_part_table(d, 0, d->d_pt.t_boot); 776 | if (f_getgeom) { 777 | if ((dg = disk_geometry(d)) == 0) 778 | pr(FATAL, EM_CANTGETGEOM); 779 | memcpy(&d->d_dg, dg, sizeof(struct disk_geom)); 780 | 781 | d->d_nsecs = dg->d_nsecs; 782 | 783 | /* 784 | * command line geometry overrides 785 | */ 786 | 787 | if (gc) 788 | d->d_dg.d_c = gc; 789 | if (gh) 790 | d->d_dg.d_h = gh; 791 | if (gs) 792 | d->d_dg.d_s = gs; 793 | } else { 794 | d->d_dg.d_c = gc; 795 | d->d_dg.d_h = gh; 796 | d->d_dg.d_s = gs; 797 | } 798 | if (d->d_dg.d_c < 1024) 799 | d->d_dosc = 1; 800 | if ((d->d_dg.d_h > 16) || (d->d_dg.d_s > 63)) 801 | d->d_lba = 1; 802 | 803 | if (gh && gc && gs) { 804 | /* Override number of sectors with command line parameters */ 805 | d->d_nsecs = d->d_dg.d_c; 806 | d->d_nsecs *= d->d_dg.d_h; 807 | d->d_nsecs *= d->d_dg.d_s; 808 | } 809 | 810 | read_ext_part_table(d, &d->d_pt); 811 | close(d->d_fd); 812 | free((void *)ubuf); 813 | return (d); 814 | } 815 | 816 | static void add_guessed_p(disk_desc *d, dos_part_entry *p, int cnt) 817 | { 818 | dos_guessed_pt *gpt; 819 | 820 | if (d->d_gl == 0) 821 | gpt = d->d_gl = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt)); 822 | else { 823 | for (gpt = d->d_gl; gpt->g_next; gpt = gpt->g_next) 824 | ; 825 | gpt->g_next = (dos_guessed_pt *)alloc(sizeof(dos_guessed_pt)); 826 | gpt = gpt->g_next; 827 | } 828 | 829 | gpt->g_ext = (cnt > 1); 830 | for (; cnt > 0; cnt--) 831 | memcpy(&gpt->g_p[cnt - 1], &p[cnt - 1], sizeof(dos_part_entry)); 832 | gpt->g_sec = d->d_nsb; 833 | } 834 | 835 | static g_module *get_best_guess(g_module **g, int count) 836 | { 837 | int mx, i; 838 | float bestg = 0.0; 839 | 840 | /* 841 | * up to now the best guess is simple that one which 842 | * reported the largest probability (if there are more 843 | * than one, the last one of them). 844 | */ 845 | 846 | for (mx = i = 0; i < count; i++) 847 | if (g[i]->m_guess * g[i]->m_weight > bestg) 848 | bestg = g[mx = i]->m_guess * g[i]->m_weight; 849 | 850 | return ((bestg > 0.0) ? g[mx] : 0); 851 | } 852 | 853 | static int mod_is_aligned(disk_desc *d, g_module *m) 854 | { 855 | s64_t al; 856 | 857 | switch (m->m_align) { 858 | case 'h': 859 | return (on_head_boundary(d, d->d_nsb)); 860 | 861 | case 'c': 862 | return (on_cyl_boundary(d, d->d_nsb)); 863 | 864 | case 1: 865 | case 's': 866 | return (1); 867 | default: 868 | if (m->m_align > 0) { 869 | al = d->d_nsb; 870 | al %= m->m_align; 871 | return (al == 0); 872 | } 873 | break; 874 | } 875 | return (1); 876 | } 877 | 878 | /* 879 | * the main guessing loop. 880 | */ 881 | 882 | static void do_guess_loop(disk_desc *d) 883 | { 884 | g_module *m, **guesses; 885 | unsigned long incr = 0; 886 | int nsecs, in_ext = 0, end_of_ext = 0, psize; 887 | ssize_t rd, bsize = d->d_ssize; 888 | s64_t bincr, noffset, start; 889 | byte_t *ubuf; 890 | 891 | if ((d->d_fd = open(d->d_dev, O_RDONLY)) == -1) 892 | pr(FATAL, EM_OPENFAIL, d->d_dev, strerror(errno)); 893 | 894 | #if HAVE_POSIX_FADVISE 895 | posix_fadvise(d->d_fd, 0, 0, POSIX_FADV_SEQUENTIAL); 896 | posix_fadvise(d->d_fd, 0, 0, POSIX_FADV_WILLNEED); 897 | #endif /* HAVE_POSIX_FADVISE */ 898 | /* 899 | * initialize modules. Each should return the minimum 900 | * size in bytes it wants to receive for a test. 901 | */ 902 | 903 | for (m = g_mod_head(); m; m = m->m_next) 904 | if (m->m_init) { 905 | int sz; 906 | 907 | if ((sz = (*m->m_init)(d, m)) <= 0) 908 | pr(ERROR, EM_MINITFAILURE, m->m_name); 909 | bsize = max(sz, bsize); 910 | } 911 | 912 | if (bsize % d->d_ssize) 913 | bsize += d->d_ssize - bsize % d->d_ssize; 914 | nsecs = bsize / d->d_ssize; 915 | switch (increment) { 916 | case 's': 917 | incr = 1; 918 | break; 919 | case 'h': 920 | incr = d->d_dg.d_s; 921 | break; 922 | case 'c': 923 | incr = d->d_dg.d_s * d->d_dg.d_h; 924 | break; 925 | default: 926 | incr = increment; 927 | break; 928 | } 929 | if (incr == 0) 930 | incr = 1; 931 | 932 | boundary_fun = (incr == 1) ? on_head_boundary : on_cyl_boundary; 933 | psize = getpagesize(); 934 | ubuf = alloc(bsize + psize); 935 | d->d_sbuf = align(ubuf, psize); 936 | d->d_nsb = 0; 937 | bincr = incr * d->d_ssize; 938 | 939 | start = skipsec ? skipsec : d->d_dg.d_s; 940 | d->d_nsb = start - incr; 941 | start *= d->d_ssize; 942 | if (l64seek(d->d_fd, start, SEEK_SET) == -1) 943 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 944 | 945 | /* 946 | * do the work: read blocks, distribute to modules, check 947 | * for probable hits. 948 | */ 949 | 950 | guesses = (g_module **)alloc(g_mod_count() * sizeof(g_module *)); 951 | pr(MSG, DM_STARTSCAN); 952 | 953 | scanloop: 954 | while ((rd = bread(d->d_fd, d->d_sbuf, d->d_ssize, nsecs)) == bsize) { 955 | int mod, have_ext = 0; 956 | g_module *bg; 957 | s64_t sz, ofs, fpos; 958 | 959 | d->d_nsb += incr; 960 | noffset = 0; 961 | ofs = d->d_nsb; 962 | s2mb(d, ofs); 963 | fpos = d->d_nsb * d->d_ssize + bsize; 964 | if (maxsec && (d->d_nsb > maxsec)) 965 | break; 966 | 967 | /* 968 | * reset modules 969 | */ 970 | 971 | for (m = g_mod_head(); m; m = m->m_next) 972 | m->m_skip = 0; 973 | 974 | guessit: 975 | bg = 0; 976 | mod = 0; 977 | for (m = g_mod_head(); m; m = m->m_next) { 978 | if (m->m_skip || (in_ext && m->m_notinext) || !mod_is_aligned(d, m)) 979 | continue; 980 | 981 | /* 982 | * because a gmodule is allowed to seek on 983 | * d->d_fd the current file position must be 984 | * restored after calling it. 985 | */ 986 | 987 | memset(&m->m_part, 0, sizeof(dos_part_entry)); 988 | m->m_guess = GM_NO; 989 | if ((*m->m_gfun)(d, m) && (m->m_guess * m->m_weight >= GM_PERHAPS)) 990 | guesses[mod++] = m; 991 | l64seek(d->d_fd, fpos, SEEK_SET); 992 | } 993 | 994 | /* 995 | * now fetch the best guess. 996 | */ 997 | 998 | if (mod && (bg = get_best_guess(guesses, mod))) { 999 | noffset = bg->m_part.p_size; 1000 | fillin_dos_chs(d, &bg->m_part, 0); 1001 | } 1002 | 1003 | /* 1004 | * extended partition begin? 1005 | */ 1006 | 1007 | if (f_testext && boundary_fun(d, d->d_nsb) && (!bg || !bg->m_hasptbl) && is_ext_parttable(d, d->d_sbuf)) { 1008 | dos_part_entry *p; 1009 | int no_ext; 1010 | 1011 | p = (dos_part_entry *)(d->d_sbuf + DOSPARTOFF); 1012 | no_ext = no_of_ext_partitions(p); 1013 | if (!in_ext) { 1014 | pr(MSG, PM_POSSIBLEEXTPART, ofs); 1015 | in_ext = 1; 1016 | end_of_ext = 0; 1017 | noffset = 0; 1018 | } else if (no_ext == 0) 1019 | end_of_ext = 1; 1020 | 1021 | if (in_ext) { 1022 | if (f_interactive) { 1023 | if (yesno(DM_ACCEPTGUESS)) 1024 | add_guessed_p(d, p, have_ext = NDOSPARTS); 1025 | else if (mod && bg) { 1026 | bg->m_skip = 1; 1027 | goto guessit; 1028 | } 1029 | } else 1030 | add_guessed_p(d, p, have_ext = NDOSPARTS); 1031 | } 1032 | } 1033 | 1034 | if (!have_ext && noffset) { 1035 | sz = noffset; 1036 | s2mb(d, sz); 1037 | if (in_ext) 1038 | pr(MSG, " "); 1039 | pr(MSG, PM_POSSIBLEPART, bg->m_desc ? bg->m_desc : bg->m_name, sz, ofs); 1040 | if (f_verbose) 1041 | print_partition(d, &bg->m_part, in_ext ? 1 : 0, 0); 1042 | if (f_interactive) 1043 | if (!yesno(DM_ACCEPTGUESS)) { 1044 | noffset = 0; 1045 | if (mod && bg) { 1046 | bg->m_skip = 1; 1047 | goto guessit; 1048 | } 1049 | } 1050 | 1051 | if (noffset) { 1052 | add_guessed_p(d, &bg->m_part, 1); 1053 | if (end_of_ext) 1054 | in_ext = 0; 1055 | } 1056 | } 1057 | 1058 | /* 1059 | * seek to next sectors to investigate (may seek 1060 | * backwards). 1061 | */ 1062 | 1063 | if (noffset && f_fast) { 1064 | if (noffset % incr) 1065 | noffset += incr - noffset % incr; 1066 | d->d_nsb += noffset - incr; 1067 | noffset -= nsecs; 1068 | noffset *= d->d_ssize; 1069 | if (l64seek(d->d_fd, noffset, SEEK_CUR) == -1) 1070 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 1071 | } else if (bincr) 1072 | if (l64seek(d->d_fd, bincr - bsize, SEEK_CUR) == -1) 1073 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 1074 | } 1075 | 1076 | /* 1077 | * short read? 1078 | */ 1079 | 1080 | if ((rd > 0) && (rd < bsize)) 1081 | if (d->d_nsb + nsecs + 1 < d->d_nsecs) { 1082 | /* 1083 | * short read not at end of disk 1084 | */ 1085 | 1086 | pr(f_skiperrors ? WARN : FATAL, EM_SHORTBREAD, d->d_nsb, rd, bsize); 1087 | noffset = l64tell(d->d_fd); 1088 | noffset /= d->d_ssize; 1089 | noffset *= d->d_ssize; 1090 | if (l64seek(d->d_fd, noffset, SEEK_SET) == -1) 1091 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 1092 | d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr; 1093 | goto scanloop; 1094 | } 1095 | 1096 | if (rd == -1) { 1097 | /* 1098 | * EIO is ignored (skipping current sector(s)) 1099 | */ 1100 | 1101 | if (f_skiperrors && (berrno == EIO)) { 1102 | pr(WARN, EM_BADREADIO, d->d_nsb); 1103 | noffset = l64tell(d->d_fd); 1104 | noffset /= d->d_ssize; 1105 | noffset += incr; 1106 | noffset *= d->d_ssize; 1107 | if (l64seek(d->d_fd, noffset, SEEK_SET) == -1) 1108 | pr(FATAL, EM_SEEKFAILURE, d->d_dev); 1109 | d->d_nsb = l64tell(d->d_fd) / d->d_ssize - incr; 1110 | goto scanloop; 1111 | } 1112 | pr(FATAL, EM_READERROR, d->d_dev, d->d_nsb, strerror(berrno)); 1113 | } 1114 | 1115 | pr(MSG, DM_ENDSCAN); 1116 | if (guesses) 1117 | free((void *)guesses); 1118 | 1119 | for (m = g_mod_head(); m; m = m->m_next) 1120 | if (m->m_term) 1121 | (*m->m_term)(d); 1122 | free((void *)ubuf); 1123 | close(d->d_fd); 1124 | } 1125 | 1126 | static void edit_partition(disk_desc *d, dos_part_entry *p) 1127 | { 1128 | char ans[32]; 1129 | int n; 1130 | unsigned long val; 1131 | 1132 | while (1) { 1133 | pr(MSG, DM_NOCHECKWARNING); 1134 | pr(MSG, PM_EDITITEM1, p->p_start); 1135 | pr(MSG, PM_EDITITEM2, p->p_size); 1136 | pr(MSG, PM_EDITITEM3, p->p_typ, get_part_type(p->p_typ)); 1137 | if ((n = number_or_quit(DM_EDITWHICHITEM, 1, 3)) < 0) 1138 | break; 1139 | if ((n < 1) || (n > 3)) 1140 | continue; 1141 | pr(MSG, "Enter value for %d : ", n); 1142 | if (fgets(ans, 32, stdin)) { 1143 | val = strtoul(ans, 0, 0); 1144 | switch (n) { 1145 | case 1: 1146 | p->p_start = val; 1147 | fillin_dos_chs(d, p, 0); 1148 | break; 1149 | case 2: 1150 | p->p_size = val; 1151 | fillin_dos_chs(d, p, 0); 1152 | break; 1153 | case 3: 1154 | p->p_typ = val & 0xFF; 1155 | break; 1156 | } 1157 | } 1158 | } 1159 | } 1160 | 1161 | static int make_mbr_backup(disk_desc *d, char *bfile) 1162 | { 1163 | int fd, ret = 0; 1164 | 1165 | if ((fd = open(bfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) 1166 | return (ret); 1167 | 1168 | if (write(fd, d->d_pt.t_boot, 512) == 512) 1169 | ret = 1; 1170 | close(fd); 1171 | return (ret); 1172 | } 1173 | 1174 | static void write_primary_ptbl(disk_desc *d, char *dev) 1175 | { 1176 | struct stat sbuf; 1177 | byte_t *ptbl, *uptbl; 1178 | int fd, doesntexist = 0, n; 1179 | 1180 | uptbl = alloc(d->d_ssize + getpagesize()); 1181 | ptbl = align(uptbl, getpagesize()); 1182 | 1183 | if (stat(dev, &sbuf) == -1) { 1184 | if (errno != ENOENT) 1185 | pr(FATAL, EM_STATFAILURE, dev, strerror(errno)); 1186 | else 1187 | doesntexist = 1; 1188 | } 1189 | fd = open(dev, O_WRONLY | (doesntexist ? O_CREAT | O_EXCL : 0), 0660); 1190 | if (fd == -1) 1191 | pr(FATAL, EM_OPENFAIL, dev, strerror(errno)); 1192 | if (l64seek(fd, 0, SEEK_SET) == -1) 1193 | pr(FATAL, EM_SEEKFAILURE, dev); 1194 | 1195 | /* 1196 | * is there a guessed partition table? 1197 | */ 1198 | 1199 | if (d->d_gpt.t_magic == le16(DOSPTMAGIC)) { 1200 | /* 1201 | * ask if table should be hand-edited 1202 | */ 1203 | 1204 | if (yesno(DM_EDITPTBL)) 1205 | while (1) { 1206 | if ((n = number_or_quit(DM_EDITWHICHPART, 1, NDOSPARTS)) < 0) 1207 | break; 1208 | if ((n >= 1) && (n <= NDOSPARTS)) 1209 | edit_partition(d, &d->d_gpt.t_parts[n - 1]); 1210 | else 1211 | break; 1212 | print_ptable(d, &d->d_gpt, 0); 1213 | } 1214 | 1215 | /* 1216 | * ask for the active partition. 1217 | */ 1218 | 1219 | while (1) { 1220 | if ((n = number_or_quit(DM_ACTWHICHPART, 1, NDOSPARTS)) < 0) 1221 | break; 1222 | if ((n >= 1) && (n <= NDOSPARTS) && get_part_type(d->d_gpt.t_parts[n].p_typ)) { 1223 | d->d_gpt.t_parts[n - 1].p_flag = DOSPARTACTIVE; 1224 | break; 1225 | } 1226 | } 1227 | 1228 | if (yesno(DM_WRITEIT)) { 1229 | memcpy(ptbl, d->d_pt.t_boot, DOSPARTOFF); 1230 | memcpy(ptbl + DOSPARTOFF, d->d_gpt.t_parts, NDOSPARTS * sizeof(dos_part_entry) + 2); 1231 | if (write(fd, ptbl, d->d_ssize) != d->d_ssize) 1232 | pr(FATAL, EM_PTBLWRITE); 1233 | 1234 | if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) { 1235 | sync(); 1236 | sleep(1); 1237 | sync(); 1238 | reread_partition_table(fd); 1239 | pr(WARN, DM_ASKTOREBOOT); 1240 | } 1241 | } else 1242 | pr(MSG, DM_NOTWRITTEN); 1243 | } 1244 | close(fd); 1245 | free((void *)uptbl); 1246 | } 1247 | 1248 | static void warn_invalid(disk_desc *d, dos_part_entry *p, char *w) 1249 | { 1250 | if (f_verbose > 1) { 1251 | pr(MSG, EM_PINVALID, w); 1252 | print_partition(d, p, 0, 0); 1253 | } 1254 | } 1255 | 1256 | /* 1257 | * after having gathered a list of possible partitions they 1258 | * have to be checked for consistency. This routine must be 1259 | * improved, it's too weird and is mistaken too often. 1260 | */ 1261 | 1262 | static int check_partition_list(disk_desc *d) 1263 | { 1264 | dos_guessed_pt *gp, *prev; 1265 | dos_part_entry *p, *rp, *ep, *lep; 1266 | int n, npp, epp, maxp, in_ext; 1267 | s64_t size, ofs; 1268 | 1269 | p = rp = ep = lep = 0; 1270 | 1271 | pr(MSG, DM_STARTCHECK); 1272 | 1273 | /* 1274 | * 1. pass: discard overlapping entries. This means 1275 | * that the first entry is assumed to be ok. 1276 | */ 1277 | 1278 | ofs = 0; 1279 | prev = 0; 1280 | npp = 0; 1281 | for (gp = d->d_gl; gp; gp = gp->g_next) { 1282 | if (gp->g_ext || gp->g_inv) 1283 | continue; 1284 | p = &gp->g_p[0]; 1285 | if (gp == d->d_gl) 1286 | ofs = p->p_start + p->p_size; 1287 | else { 1288 | if (p->p_start < ofs) { 1289 | /* 1290 | * overlap. unlink and discard. 1291 | */ 1292 | 1293 | prev->g_next = gp->g_next; 1294 | free((void *)gp); 1295 | gp = prev; 1296 | npp++; 1297 | } else 1298 | ofs += p->p_size; 1299 | } 1300 | prev = gp; 1301 | } 1302 | 1303 | if (npp) 1304 | pr(WARN, EM_DISCARDOVLP, npp); 1305 | 1306 | /* 1307 | * 2. pass: decide type of every partition, 1308 | * marking inconsistent ones as invalid. 1309 | */ 1310 | 1311 | size = 0; 1312 | in_ext = npp = epp = 0; 1313 | maxp = NDOSPARTS; 1314 | for (n = 1, gp = d->d_gl; gp; gp = gp->g_next, n++) { 1315 | if (gp->g_inv) 1316 | continue; 1317 | if (gp->g_ext) { 1318 | if (gp->g_next == 0) { 1319 | /* 1320 | * ext ptbl without logical p. 1321 | */ 1322 | 1323 | gp->g_inv = 1; 1324 | warn_invalid(d, p, EM_P_EATEND); 1325 | break; 1326 | } 1327 | if (!in_ext) { 1328 | /* 1329 | * new extended p. chain. 1330 | */ 1331 | 1332 | if (no_of_ext_partitions(gp->g_p) == 0) { 1333 | gp->g_inv = 1; 1334 | warn_invalid(d, p, EM_P_EWLP); 1335 | continue; 1336 | } 1337 | 1338 | in_ext = 1; 1339 | epp++; 1340 | if (maxp >= NDOSPARTS) 1341 | maxp--; 1342 | 1343 | /* 1344 | * already had one? 1345 | */ 1346 | 1347 | if (epp > 1) { 1348 | gp->g_inv = 1; 1349 | warn_invalid(d, p, EM_P_MTOE); 1350 | continue; 1351 | } 1352 | } 1353 | if (no_of_ext_partitions(gp->g_p) == 0) 1354 | in_ext = 0; 1355 | rp = 0; 1356 | for (p = &gp->g_p[0]; p <= &gp->g_p[NDOSPARTS - 1]; p++) { 1357 | if (is_real_parttype(p)) 1358 | rp = p; 1359 | else if (is_ext_parttype(p) && (n == 1)) 1360 | size = p->p_start; 1361 | } 1362 | gp = gp->g_next; 1363 | if (gp->g_ext) { 1364 | /* 1365 | * should not happen: a supposedly logical 1366 | * partition which is an extended p itself. 1367 | */ 1368 | 1369 | gp->g_inv = 1; 1370 | warn_invalid(d, p, EM_P_LISAE); 1371 | continue; 1372 | } else 1373 | gp->g_log = 1; 1374 | 1375 | /* 1376 | * the p. type in the extended ptbl and the following 1377 | * logical p. type must be identical. Also check size. 1378 | */ 1379 | 1380 | p = &gp->g_p[0]; 1381 | if (is_real_parttype(p) && is_same_partition_type(rp, p) && (rp->p_size >= p->p_size)) { 1382 | if (!is_sane_partentry(d, p, 1)) 1383 | gp->g_inv = 1; 1384 | else 1385 | size += gp->g_p[0].p_size + 1; 1386 | } else { 1387 | gp->g_inv = 1; 1388 | warn_invalid(d, p, EM_P_UTS); 1389 | } 1390 | } else if (!in_ext) { 1391 | /* 1392 | * primary entry. 1393 | */ 1394 | 1395 | gp->g_prim = 1; 1396 | p = &gp->g_p[0]; 1397 | if (n == 1) 1398 | size = p->p_start; 1399 | if (npp++ >= maxp) { 1400 | gp->g_inv = 1; 1401 | warn_invalid(d, p, EM_P_2MANYPP); 1402 | } else { 1403 | if (!is_sane_partentry(d, p, 1)) { 1404 | gp->g_inv = 1; 1405 | warn_invalid(d, p, EM_P_NOTSANE); 1406 | } else 1407 | size += p->p_size; 1408 | } 1409 | } else { 1410 | /* 1411 | * in_ext && !gp->g_ext. This means the end 1412 | * of the logical partition chain hasn't been 1413 | * found. Reset it. 1414 | */ 1415 | 1416 | in_ext = 0; 1417 | gp->g_inv = 1; 1418 | warn_invalid(d, p, EM_P_ENDNOTF); 1419 | } 1420 | } 1421 | 1422 | if (epp > 1) 1423 | pr(WARN, EM_TOOMANYXPTS, epp); 1424 | if (npp > maxp) 1425 | pr(WARN, EM_TOOMANYPPTS, maxp, npp); 1426 | 1427 | /* 1428 | * 3. pass: check logical partition chain. Logical 1429 | * partitions which seem ok but are not found in the 1430 | * link chain are marked orphaned. 1431 | */ 1432 | 1433 | in_ext = size = ofs = 0; 1434 | lep = 0; 1435 | for (gp = d->d_gl; gp; gp = gp->g_next) { 1436 | if (gp->g_inv) 1437 | continue; 1438 | if (gp->g_ext) { 1439 | if (!in_ext) { 1440 | in_ext = 1; 1441 | ofs = gp->g_sec; 1442 | } 1443 | rp = ep = 0; 1444 | for (p = &gp->g_p[0]; p <= &gp->g_p[NDOSPARTS - 1]; p++) { 1445 | if (is_real_parttype(p)) 1446 | rp = p; 1447 | else if (is_ext_parttype(p)) 1448 | ep = p; 1449 | } 1450 | 1451 | if (lep && rp) 1452 | if (gp->g_sec != ofs + lep->p_start) 1453 | gp->g_next->g_orph = 1; 1454 | if (ep) 1455 | lep = ep; 1456 | gp = gp->g_next; 1457 | } 1458 | } 1459 | 1460 | /* 1461 | * if the list was consistent the size of the whole 1462 | * extended ptbl is equal to the end of the last eptbl 1463 | * link. 1464 | */ 1465 | 1466 | if (rp && lep) 1467 | size = lep->p_start + lep->p_size; 1468 | else 1469 | size = ofs = 0; 1470 | 1471 | for (gp = d->d_gl; gp; gp = gp->g_next) { 1472 | if (gp->g_ext) 1473 | continue; 1474 | p = &gp->g_p[0]; 1475 | if (gp->g_log) 1476 | pr(MSG, " "); 1477 | pr(MSG, "Partition(%s): ", get_part_type(p->p_typ)); 1478 | if (gp->g_inv) 1479 | pr(MSG, PM_G_INVALID); 1480 | if (gp->g_orph) 1481 | pr(MSG, PM_G_ORPHANED); 1482 | if (gp->g_prim) 1483 | pr(MSG, PM_G_PRIMARY); 1484 | if (gp->g_log) 1485 | pr(MSG, PM_G_LOGICAL); 1486 | pr(MSG, "\n"); 1487 | if (f_verbose > 1) 1488 | print_partition(d, p, gp->g_log ? 1 : 0, 0); 1489 | } 1490 | 1491 | /* 1492 | * now fill in the guessed primary partition table. 1493 | */ 1494 | 1495 | in_ext = n = 0; 1496 | memset(&d->d_gpt, 0, sizeof(dos_part_table)); 1497 | for (gp = d->d_gl; gp; gp = gp->g_next) { 1498 | if (n >= NDOSPARTS) 1499 | break; 1500 | if (gp->g_inv) 1501 | continue; 1502 | if (gp->g_ext) { 1503 | if (!in_ext) { 1504 | in_ext = 1; 1505 | if (size && ofs) { 1506 | p = &d->d_gpt.t_parts[n++]; 1507 | p->p_start = ofs; 1508 | p->p_typ = 0x05; 1509 | p->p_typ = d->d_lba ? 0x0F : 0x05; 1510 | p->p_size = size; 1511 | fillin_dos_chs(d, p, 0); 1512 | } 1513 | } 1514 | gp = gp->g_next; 1515 | continue; 1516 | } 1517 | if (gp->g_prim) 1518 | memcpy(&d->d_gpt.t_parts[n++], &gp->g_p[0], sizeof(dos_part_entry)); 1519 | } 1520 | 1521 | /* 1522 | * final step: re-check this table. If ok, set the 1523 | * ptbl magic number which is the indicator for 1524 | * write_primary_ptbl that it seems to be ok. 1525 | */ 1526 | 1527 | ep = 0; 1528 | npp = 0; 1529 | for (n = 0; n < NDOSPARTS; n++) { 1530 | p = &d->d_gpt.t_parts[n]; 1531 | if (ep && p->p_typ) { 1532 | if ((ep->p_start + ep->p_size > p->p_start) || !is_sane_partentry(d, p, 1)) { 1533 | /* 1534 | * zis is not funny. Perhaps the p. list 1535 | * can be re-checked but for now only 1536 | * inconsistencies are counted. 1537 | */ 1538 | 1539 | npp++; 1540 | if (f_verbose > 2) { 1541 | pr(WARN, EM_PINCONS); 1542 | print_partition(d, p, 0, 0); 1543 | } 1544 | } 1545 | } 1546 | ep = p; 1547 | } 1548 | if (npp == 0) { 1549 | d->d_gpt.t_magic = le16(DOSPTMAGIC); 1550 | pr(MSG, "Ok.\n"); 1551 | } else 1552 | pr(MSG, DM_NOOFINCONS, npp); 1553 | return (npp); 1554 | } 1555 | 1556 | /* 1557 | * compare both existing and guessed partition tables. 1558 | * The order of the ptbl entries is not important (the 1559 | * physically first partition on disk can be in the last 1560 | * ptbl slot). 1561 | */ 1562 | 1563 | static int compare_parttables(disk_desc *d) 1564 | { 1565 | int ret, i, j, diff; 1566 | byte_t *pr, *pg; 1567 | 1568 | ret = 0; 1569 | for (i = 0; i < NDOSPARTS; i++) { 1570 | pr = (byte_t *)&d->d_pt.t_parts[i]; 1571 | for (j = 0; j < NDOSPARTS; j++) { 1572 | pg = (byte_t *)&d->d_gpt.t_parts[j]; 1573 | 1574 | /* 1575 | * the p_flag entry cannot be included 1576 | * in the comparison. 1577 | */ 1578 | 1579 | diff = memcmp(pr + 1, pg + 1, sizeof(dos_part_entry) - 1); 1580 | if (diff == 0) 1581 | break; 1582 | } 1583 | if (diff) 1584 | ret++; 1585 | } 1586 | return (ret); 1587 | } 1588 | 1589 | /* 1590 | * main 1591 | */ 1592 | 1593 | int main(int ac, char **av) 1594 | { 1595 | char *optstr = "b:C:cdEefghiK:k:Ll:n:qs:t:VvW:w:"; 1596 | char *p1, *p2, *p3, *odev = 0, *backup = 0; 1597 | int opt, sectsize = 0, no_of_incons = 0; 1598 | disk_desc *d; 1599 | 1600 | g_mod_addinternals(); 1601 | while ((opt = getopt(ac, av, optstr)) != -1) 1602 | switch (opt) { 1603 | case 'b': 1604 | backup = optarg; 1605 | break; 1606 | case 'C': 1607 | if (!get_csep_arg(optarg, &p1, &p2, &p3)) { 1608 | usage(); 1609 | return (EXIT_FAILURE); 1610 | } 1611 | gc = strtoul(p1, 0, 0); 1612 | if (errno == ERANGE) 1613 | pr(FATAL, EM_INVVALUE); 1614 | gh = strtoul(p2, 0, 0); 1615 | if (errno == ERANGE) 1616 | pr(FATAL, EM_INVVALUE); 1617 | gs = strtoul(p3, 0, 0); 1618 | if (errno == ERANGE) 1619 | pr(FATAL, EM_INVVALUE); 1620 | break; 1621 | case 'c': 1622 | f_check = 1; 1623 | break; 1624 | case 'd': 1625 | f_dontguess = 1; 1626 | break; 1627 | case 'E': 1628 | f_testext = 0; 1629 | break; 1630 | case 'e': 1631 | f_skiperrors = 0; 1632 | break; 1633 | case 'f': 1634 | f_fast = 0; 1635 | break; 1636 | case 'g': 1637 | f_getgeom = 0; 1638 | break; 1639 | case 'i': 1640 | f_interactive = 1; 1641 | break; 1642 | case 'K': 1643 | maxsec = strtoul(optarg, 0, 0); 1644 | if ((maxsec <= 0) || (errno == ERANGE)) 1645 | pr(FATAL, EM_INVVALUE); 1646 | break; 1647 | case 'k': 1648 | /* strtos64? */ 1649 | skipsec = strtoul(optarg, 0, 0); 1650 | if (errno == ERANGE) 1651 | pr(FATAL, EM_INVVALUE); 1652 | break; 1653 | case 'n': 1654 | if ((*optarg == 's') || (*optarg == 'h') || (*optarg == 'c')) 1655 | increment = *optarg; 1656 | else { 1657 | increment = strtoul(optarg, 0, 0); 1658 | if (errno == ERANGE) 1659 | pr(FATAL, EM_INVVALUE); 1660 | } 1661 | break; 1662 | case 'l': 1663 | if (logfile) 1664 | fclose(logfile); 1665 | if ((logfile = fopen(optarg, "w")) == 0) 1666 | pr(FATAL, EM_OPENLOG, optarg); 1667 | break; 1668 | case 'L': 1669 | g_mod_list(); 1670 | return (EXIT_SUCCESS); 1671 | case 'q': 1672 | f_quiet = 1; 1673 | break; 1674 | case 's': 1675 | if ((sectsize = atoi(optarg)) <= 0) 1676 | pr(FATAL, "sector size must be >= 0"); 1677 | break; 1678 | case 'v': 1679 | f_verbose++; 1680 | break; 1681 | case 'V': 1682 | fprintf(stderr, "%s\n", gpart_version); 1683 | return (EXIT_SUCCESS); 1684 | case 'w': 1685 | if (!get_csep_arg(optarg, &p1, &p2, 0)) { 1686 | usage(); 1687 | return (EXIT_FAILURE); 1688 | } 1689 | if (!g_mod_setweight(p1, atof(p2))) 1690 | pr(FATAL, EM_NOSUCHMOD, p1); 1691 | break; 1692 | case 'W': 1693 | odev = optarg; 1694 | break; 1695 | case '?': 1696 | case 'h': 1697 | default: 1698 | usage(); 1699 | return (EXIT_FAILURE); 1700 | } 1701 | 1702 | if ((optind + 1) != ac) { 1703 | usage(); 1704 | return (EXIT_FAILURE); 1705 | } 1706 | 1707 | if (f_dontguess) 1708 | f_check = 0; 1709 | if (f_check) { 1710 | f_quiet = 1; 1711 | f_dontguess = 0; 1712 | odev = 0; 1713 | } 1714 | if (f_quiet) 1715 | f_interactive = 0; 1716 | 1717 | sync(); 1718 | d = get_disk_desc(av[optind], sectsize); 1719 | if (f_verbose > 0) 1720 | print_disk_desc(d); 1721 | if (f_verbose > 2) 1722 | print_mboot_block(d); 1723 | 1724 | if (!f_dontguess) { 1725 | sleep(1); 1726 | sync(); 1727 | do_guess_loop(d); 1728 | no_of_incons = check_partition_list(d); 1729 | pr(MSG, DM_GUESSEDPTBL); 1730 | print_ptable(d, &d->d_gpt, 0); 1731 | 1732 | if ((no_of_incons == 0) && f_check) 1733 | no_of_incons = compare_parttables(d); 1734 | 1735 | if ((no_of_incons == 0) && odev) { 1736 | if (backup) 1737 | make_mbr_backup(d, backup); 1738 | write_primary_ptbl(d, odev); 1739 | } 1740 | } 1741 | free_disk_desc(d); 1742 | if (logfile) 1743 | fclose(logfile); 1744 | 1745 | return (f_check ? no_of_incons : 0); 1746 | } 1747 | -------------------------------------------------------------------------------- /src/gpart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gpart.h -- gpart main header file 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _GPART_H 18 | #define _GPART_H 19 | 20 | #include "config.h" 21 | 22 | #include "errmsgs.h" 23 | #include "l64seek.h" 24 | 25 | #include 26 | 27 | typedef uint8_t byte_t; 28 | 29 | #define le16(x) htole16(x) 30 | #define be16(x) htobe16(x) 31 | #define le32(x) htole32(x) 32 | #define be32(x) htobe32(x) 33 | #define le64(x) htole64(x) 34 | #define be64(x) htobe64(x) 35 | 36 | 37 | #ifndef max 38 | # define max(a,b) ((a)>(b)?(a):(b)) 39 | # define min(a,b) ((a)<(b)?(a):(b)) 40 | #endif 41 | 42 | #define MINSSIZE (512) /* min. sector size */ 43 | #define MAXSSIZE (16384) 44 | 45 | #define FATAL 1 /* fatal error, exit */ 46 | #define ERROR 2 /* non-fatal error */ 47 | #define WARN 3 48 | #define MSG 4 /* normal message */ 49 | 50 | void pr(int,char *,...); 51 | ssize_t bread(int,byte_t *,size_t,size_t); 52 | byte_t *alloc(ssize_t); 53 | 54 | 55 | 56 | /* 57 | * dos partition table stuff 58 | */ 59 | 60 | #define DOSMBSECTOR 0 /* absolute sector # of mbr */ 61 | #define NDOSPARTS 4 /* # of primary partitions */ 62 | #define DOSPARTOFF 446 /* offset of part-table in mbr */ 63 | #define DOSPARTACTIVE 0x80 /* active (boot) flag */ 64 | #define DOSPTMAGIC 0xaa55 /* signature */ 65 | #define DOSCYL(cyl,s) ((cyl)+(((s)&0xc0)<<2)) 66 | #define DOSSEC(s) ((s)&0x3f) 67 | 68 | 69 | typedef struct 70 | { 71 | byte_t p_flag; /* bootstrap flags */ 72 | byte_t p_shd; /* starting head */ 73 | byte_t p_ssect; /* starting sector */ 74 | byte_t p_scyl; /* starting cylinder */ 75 | byte_t p_typ; /* partition type */ 76 | byte_t p_ehd; /* end head */ 77 | byte_t p_esect; /* end sector */ 78 | byte_t p_ecyl; /* end cylinder */ 79 | uint32_t p_start; /* start sector (absolute) */ 80 | uint32_t p_size; /* # of sectors */ 81 | } dos_part_entry; 82 | 83 | 84 | typedef struct dos_pt 85 | { 86 | struct dos_pt *t_ext; /* -> extended parttable */ 87 | byte_t _align[2]; 88 | byte_t t_boot[DOSPARTOFF]; 89 | dos_part_entry t_parts[NDOSPARTS]; 90 | uint16_t t_magic; /* DOSPTMAGIC */ 91 | } dos_part_table; 92 | 93 | 94 | typedef struct dos_gp 95 | { 96 | dos_part_entry g_p[NDOSPARTS]; 97 | struct dos_gp *g_next; 98 | s64_t g_sec; /* found there */ 99 | unsigned int g_ext : 1; /* extended ptbl */ 100 | unsigned int g_prim : 1; /* primary partition */ 101 | unsigned int g_log : 1; /* logical partition */ 102 | unsigned int g_inv : 1; /* invalid entry */ 103 | unsigned int g_orph : 1; /* orphaned partition */ 104 | } dos_guessed_pt; 105 | 106 | /* 107 | * disk description used 108 | */ 109 | 110 | typedef struct 111 | { 112 | char *d_dev; /* device name */ 113 | int d_fd; /* file descriptor when open */ 114 | ssize_t d_ssize; /* sector size */ 115 | byte_t *d_sbuf; /* sector buffer */ 116 | s64_t d_nsecs; /* total no of sectors */ 117 | s64_t d_nsb; /* # of first sector in sbuf on disk */ 118 | struct disk_geom /* disk geometry */ 119 | { 120 | long d_c; /* cylinder count */ 121 | long d_h; /* heads/cyl */ 122 | long d_s; /* sectors/head */ 123 | uint64_t d_nsecs; /* Number of sectors total */ 124 | } d_dg; 125 | unsigned int d_lba : 1; 126 | unsigned int d_dosc : 1; /* dos compatible? (g_c < 1024) */ 127 | dos_part_table d_pt; /* table of primary partitions */ 128 | dos_part_table d_gpt; /* guessed ptbl */ 129 | dos_guessed_pt *d_gl; /* list of gathered guesses */ 130 | } disk_desc; 131 | 132 | 133 | struct disk_geom *disk_geometry(disk_desc *); 134 | int reread_partition_table(int); 135 | 136 | #define s2mb(d,s) { (s)*=(d)->d_ssize; (s)/=1024; (s)/=1024; } 137 | #define align(b,s) (byte_t *)(((size_t)(b)+(s)-1)&~((s)-1)) 138 | 139 | #include "gmodules.h" 140 | 141 | 142 | #endif /* _GPART_H */ 143 | -------------------------------------------------------------------------------- /src/l64seek.c: -------------------------------------------------------------------------------- 1 | /* 2 | * l64seek.c -- gpart signed 64bit seek 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #include "config.h" /* for large file support */ 18 | #include "l64seek.h" 19 | 20 | #define OSTACKLEN 16 21 | static struct { 22 | s64_t fpos; 23 | int fd; 24 | } ostck[OSTACKLEN]; 25 | static int osptr = -1; 26 | 27 | off64_t l64seek(int fd, off64_t offset, int whence) 28 | { 29 | off64_t ret = (off64_t)-1; 30 | 31 | ret = lseek(fd, offset, whence); 32 | 33 | return (ret); 34 | } 35 | 36 | int l64opush(int fd) 37 | { 38 | s64_t fpos; 39 | 40 | if (osptr < OSTACKLEN - 1) { 41 | if ((fpos = l64tell(fd)) >= 0) { 42 | ostck[++osptr].fd = fd; 43 | ostck[osptr].fpos = fpos; 44 | return (1); 45 | } 46 | } 47 | return (0); 48 | } 49 | 50 | s64_t l64opop(int fd) 51 | { 52 | if ((osptr >= 0) && (ostck[osptr].fd == fd)) 53 | return (ostck[osptr--].fpos); 54 | return (-1); 55 | } 56 | -------------------------------------------------------------------------------- /src/l64seek.h: -------------------------------------------------------------------------------- 1 | /* 2 | * l64seek.h -- gpart signed 64bit seek header file 3 | * 4 | * gpart (c) 1999-2001 Michail Brzitwa 5 | * Guess PC-type hard disk partitions. 6 | * 7 | * gpart is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published 9 | * by the Free Software Foundation; either version 2, or (at your 10 | * option) any later version. 11 | * 12 | * Created: 04.01.1999 13 | * Modified: 14 | * 15 | */ 16 | 17 | #ifndef _L64SEEK_H 18 | #define _L64SEEK_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | /* 25 | * define a type 'off64_t' which is at least 64bit, and a 26 | * lseek function capable of seeking with at least 64bit 27 | * offsets. 28 | */ 29 | 30 | typedef loff_t off64_t; 31 | typedef off64_t s64_t; 32 | 33 | off64_t l64seek(int fd, off64_t offset, int whence); 34 | #define l64tell(fd) l64seek(fd, 0, SEEK_CUR) 35 | int l64opush(int); 36 | s64_t l64opop(int); 37 | 38 | #endif 39 | --------------------------------------------------------------------------------