lphdisk-0.9.1.debian/0000755000175000017500000000000011155065454013462 5ustar roverroverlphdisk-0.9.1.debian/CREDITS0000644000175000017500000000111607341271467014506 0ustar roverroverCREDITS ------- Patrick D. Ashmore Original author and current maintainer Alex Stewart Added many features, rewrote nearly the entire lphdisk program (see ChangeLog and NEWS for details) Jeremy L. Wade Figured out the checksum method used in the hibernation partition Mark Allen and Heather Stern Initial help with these laptops and the suspend-to-disk feature. Last, but not least... to everyone who helped test lpdisk and send in success reports. Thanks! lphdisk-0.9.1.debian/ChangeLog0000644000175000017500000000266707432174760015253 0ustar roverroverChangeLog --------- 12 February 2002 - lphdisk-0.9.1 (minor bug fixes) 23 August 2001 - Second release of lphdisk (lphdisk-0.9) 16 July 2001 - Large rewrite. - Changed to access only the device specified - Hibernate partition can now be any primary partition, not just 4 - Removed restrictions on device file (now just prints warning) - Added probing of video/system RAM and calculation of reccomended partition size - Added lots of error checking - Added device type, partition table sanity checking - Added sanity checking against /proc/partitions - Added GNU-style long options - Added '-n' flag to disable writing - Added '-d' flag to turn on debugging output - '-f' flag is now useful (changes sanity errors to warnings) - Added all, install, clean, and distclean targets to Makefile - Added .spec file for building RPMs 27 July 2000 - First release of lphdisk (lphdisk-0.4) 26 July 2000 - Added man page and README file 25 July 2000 - lphdisk can now properly create headers and format partitions 24 July 2000 - Name changed from "phoodisk" to "lphdisk" 1 July 2000 - We Linux users need something better than a bootable DOS disk and PHDISK.EXE lphdisk-0.9.1.debian/LICENSE0000644000175000017500000001461007137424205014467 0ustar roverroverThe "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a. place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b. use the modified Package only within your corporation or organization. c. rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d. make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a. distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b. accompany the distribution with the machine-readable source of the Package with your modifications. c. give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d. make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End lphdisk-0.9.1.debian/Makefile0000644000175000017500000000123407432155446015126 0ustar roverrover# # Makefile for lphdisk - hibernation partition creation utility # # lphdisk 0.9.1 # INSTALL_PREFIX = /usr/local CFLAGS = -g -Wall LIBS = LRMIDIR = lrmi-0.6m all: lphdisk lphdisk: lphdisk.o lrmi.o $(CC) $(CFLAGS) -o lphdisk lphdisk.o lrmi.o $(LIBS) lphdisk.o: lphdisk.c lrmi.h vbe.h lrmi.o: cd $(LRMIDIR) && $(MAKE) $@ cp $(LRMIDIR)/lrmi.o . %.h: $(LRMIDIR)/%.h cp $^ $@ install: all install -m 755 lphdisk $(INSTALL_PREFIX)/sbin install -m 644 lphdisk.8 $(INSTALL_PREFIX)/man/man8 clean: cd $(LRMIDIR) && $(MAKE) $@ rm -f *.o lrmi.h vbe.h distclean: clean cd $(LRMIDIR) && $(MAKE) $@ rm -f lphdisk .PHONY: all install clean distclean lphdisk-0.9.1.debian/NEWS0000644000175000017500000001515407432174322014165 0ustar roverroverNEWS ---- 12 February 2002 - lphdisk 0.9.1 - Alex Stewart (Fixed a couple of minor bugs submitted by users) 23 August 2001 - Second release, lphdisk 0.9. "Oh yeah..." 16 July 2001 - lphdisk 0.4as1 - Alex Stewart There are quite a few changes in this release. First of all, it's been largely rewritten (I didn't set out to do it, but it ended up that way, for a couple of reasons). In the process, much of the code was made to be more modular, with well-defined APIs and removal of most of the global variables. A good chunk of the rewriting was needed to support some of the new features. A side effect is that it will now also be cleaner to add partition table modification should anyone ever get around to that. OK, some of the changes and reasons: = lphdisk can now handle hibernate partitions on any primary partition, not just partition 4. As far as I know, all versions of Phoenix NoteBIOS will handle a hibernate partition on any of the primary partitions, and some new notebooks are even coming with it on partition 1 now. In some cases it's also more convenient to have it on another partition, so it seemed reasonable to remove this limitation. = It can now be used on drives besides /dev/hda and /dev/sda. There are several reasons for this, one of the biggies being the unix philosophy that, yes, the user really does know best. There is also the point that on some strange systems, the /dev entries may be named differently or even point to different disks (and on devfs systems they will follow a completely different naming scheme, for example), and in some configurations (prepping a disk for moving into another machine) it may also be desirable to perform this on something that isn't the first drive in the system. That's not to say that lphdisk will just use any destination blindly. A lot of additional checks have been built in (see below). If something other than the first IDE disk in the system is used, a warning will still be given to the user that the BIOS may not be able to use it there, but it won't outright prohibit the use of it. Oh, and you can also now use a normal file as an argument to lphdisk. Pointing it at anything other than a block device does require the use of the '-f' (force) switch, and it does still require that the first 512 bytes contain a valid partition table. This, however, makes it possible to use lphdisk on disk image files which can later be transferred to an actual physical drive, etc. = lphdisk will now automagically calculate and print the required partition size. Detection of physical memory size (through /proc/mtrr and /proc/meminfo) and video memory (via VESA BIOS Extensions) is now done to figure out the right size for a hibernate partition. This information is displayed to the user and also checked against the actual partition used to make sure it'll be big enough (a warning is given if it doesn't appear to be). A '-p' (--probeonly) option has also been added to tell lphdisk to just calculate and print the reccomended size without doing any formatting. = lphdisk now performs all of its updates using only the (raw) disk device/file specified (i.e. just /dev/hda instead of using both /dev/hda and /dev/hda4) Making assumptions about relationships between different device filenames is potentially very bad, and this prevents somebody who's done something silly like 'mknod /dev/hda4 b 3 1' from accidentally getting something important clobbered. This does require using raw unix fd IO instead of stdio streams, which for some reason I don't quite fathom turns out to be somewhere around 10 times slower. I'm still working on figuring out if there's a way to speed this up, but on decent sized partitions (260MB) it still only takes a minute and a half or so, which considering this is usually a one-time operation isn't that bad, and the safety added by doing things this way outweighs an extra minute of runtime, IMHO. This also makes it possible to use regular files the same as disks for this purpose, as mentioned above. = A lot of error-checking has been added, as well as sanity-checking of some of the data it's getting from the partition table. lphdisk will now check some of the obvious things like making sure partitions don't overlap, and checking of return values has been added to the couple of system calls which previously didn't have it. = Sanity-checking against /proc/partitions For block devices, lphdisk will attempt to correlate what it's seeing in the partition table against what the running kernel reports via /proc/partitions. This both double-checks that it's looking at something that should be a partitionable device, and ensures that the running system is in sync with what's actually on the disk (i.e. the user has rebooted since changing things with fdisk). One exception is made if it appears that the user may have just run fdisk to create the "A0" partition out of free space and hasn't yet rebooted, but all other partitions check out. This avoids the need for one more reboot in this reasonably common scenario, and should be fairly safe as long as everything else matches up. = Long option support added Added support for GNU-style long options, just for completeness/linuxness. = Added '-d' (--debug) flag All of the debug messages previously enabled by compiling with the DEBUG define set have been changed to be runtime-selectable using the '-d' command line option (and a lot of additional debug messages have been added). This is particularly useful in troubleshooting situations where users may only have ready access to a precompiled binary (and in a program like this there isn't a great deal of speed or size advantage to conditional compilation). = Added '-n' (--nowrite) flag The '-n' flag will cause lphdisk to do everything it would normally do, except actually writing sectors to the disk. This can be used for testing, or in combination with '-d' to gather information about a potentially dangerous issue. = '-f' (--force) flag is now useful '-f' will now cause most sanity-checking errors to be demoted to warnings an allow execution to proceed anyway. This can be used to: a) Use a regular file instead of a block device. b) Ignore mismatches between the partition table and /proc/partitions 27 July 2000 - First release, lphdisk 0.4. "Spooooon!" lphdisk-0.9.1.debian/README0000644000175000017500000001503407432174406014346 0ustar roverrover lphdisk release 0.9.1 February 12, 2000 Patrick D. Ashmore Alex Stewart =============================================================================== 1. What is lphdisk? 2. How do I install/use lphdisk? 3. Do I need lphdisk to use hibernation with Linux? 4. What kind of laptops will lphdisk work with? 5. About the Artistic License 1. What is lphdisk? ------------------- lphdisk (pronounced "elf-disk") This utility is intended to be the Linux equivalent of the DOS-only utility "PHDISK.EXE" from Phoenix. This utility prepares and formats the hibernation partition for notebook computers that use Phoenix NoteBIOS. Once this partition has been prepared, it can be used with the BIOS's APM Suspend-To-Disk feature. Note that one does not need this utility to be able to take advantage of the Suspend-To-Disk feature of these Phoenix NoteBIOS laptops. Once the hibernation partition is prepared, either from the DOS utility PHDISK.EXE that Phoenix provides, or lphdisk, it can be used to suspend a machine's memory to disk. This utility was created for two reasons. For the longest time Linux users had to boot off of a DOS floppy and use Phoenix's buggy PHDISK.EXE program to prepare their hibernation partition. True, this isn't a concern for most users since they only have to do it once. It's a fire-and-forget sort of thing. However, if they ever upgraded their memory, or replaced/repartitioned their hard drive, they would have to once again dig out the DOS PHDISK.EXE. The second reason is that the company I worked for at the time I started this program (Tuxtops) sold laptops with Linux, and having to involve DOS in our laptop build process greatly slowed things down. The entire build process was much faster and less error prone if it was done in a single pass with Linux. There is sort of a third reason (or at least there was at the time). PHDISK.EXE was somewhat buggy. Running it on a system that you had already prepared other- wise was somewhat dangerous. You risked having PHDISK.EXE nuke preexisting partitions (FAT or ext2, it didn't matter), create partitions with bad or overlapping boundaries, or partitions that simply ran off the end of the disk. Heck, to this date MicroSoft's own FDISK program is full of bugs... bugs that have been around since the days of DOS. Both of these closed-source programs are out of our reach to fix... so we turn to our own. 2. How do I use/install lphdisk? -------------------------------- Grab the latest source from http://www.procyon.com/~pda/lphdisk/ then: tar -xvvvzf lphdisk-0.9.1.tar.gz cd lphdisk-0.9.1 make install ... and you're all set and ready to use lpdisk to prep your partition. Currently, usage is very simple for lphdisk. First you need to determine how much space to allocate. A general rule of thumb that works fine is to add your physical system memory, your video memory, and 2 megabytes (for caches and bad block growth) together. For example, my laptop has 256MB of RAM and 8MB of video RAM. That's 256+8+2, or 266 megabytes. Alternately, you can run "lphdisk --probeonly" and it will try to determine a good size for you. Use a partitioning utility to create a partition of this size. This partition should be a primary partition. You may need to use GNU parted to resize other partitions and filesystems on the hard drive to get enough space. Once you create the partition, set its type to a0 - the IBM "ThinkPad" Hibernation format. Save the partition table and you're ready to use lphdisk. NOTE: If the kernel fails to reread the partition table after repartitioning, you should reboot to ensure this happens. It's probably a good idea to reboot anyway to make sure the kernel knows the partition table... otherwise, this could interfere with lphdisk and do Bad Things(tm) to your hard drive. AS WITH ANY SOFTWARE THAT DIRECTLY MANIPULATES THE HARD DRIVE AND RUNS WITH ROOT PRIVILEGES, BE WARNED THAT THIS COULD BRING ABOUT UNFORESEEN CONSEQUENCES. In other words, BACK UP YOUR DATA BEFORE USING THIS!!! While I am confident that my utility is less likely to destroy data than the official DOS equivalent, and I personally trust my code enough to use it without backing up my partitions, I cannot suggest anyone else do the same. Use this at your own risk. Now that you're all set, the partition is in place, and you have backed up your drive (you DID back up your drive, didn't you?), you're ready to evoke ye old magic incantation: lphdisk or lphdisk /dev/hda Now reboot so that the Phoenix NoteBIOS can find and verify the new hibernation partition, and you're ready to use the suspend-to-disk feature. There are a few more options and functions now available in lphdisk. Type "lphdisk --help" or read the included man page for more information. 3. Do I need lphdisk to use hibernation with Linux? --------------------------------------------------- No. If your laptop already has a prepared hibernation partition, either as shipped from the laptop manufacturer or as generated by the DOS-only PHDISK.EXE utility, you should be able to suspend-to-disk from any operating system that can handle APM suspend events. This utility just makes it easier for Linux users to prepare a valid hibernation partition. It also makes it safer. Before this utility, one had to obtain the PHDISK.EXE from Phoenix (or usually on a rescue CD shipped with the laptop), boot to DOS, and hope that it didn't nuke anything else on the drive when it ran. 4. What kind of laptops will lphdisk work with? ----------------------------------------------- Theoretically, any laptop that uses Phoenix NoteBIOS, but I do not have an extremely wide test base to verify this. All of the models I have tested use Phoenix NoteBIOS 4.0 Release 6.1, but earlier version may (should?) work. There is a fairly good size list of laptops that have been tested and work just fine with hibernation partitions available on lphdisk's home page at: http://www.procyon.com/~pda/lphdisk/tested.html 5. About the Artistic License ----------------------------- This software is released under the Artistic License. Please see the "LICENSE" file included with this package or online at either of the following URLs: http://www.perl.com/language/misc/Artistic.html http://www.opensource.org/licenses/artistic-license.html I chose to release lphdisk under the Artistic License rather than the GPL because the GPL is too restrictive and is incompatible with other licenses that could possibly restrict redistribution. (example, the BSD license) lphdisk-0.9.1.debian/TODO0000644000175000017500000000042507324610274014152 0ustar roverroverOrder of business: o get partition manipulation working Allow program to talk directly with disk to determine cylinder size, perform math to determine needed table entry, and write to the partition table itself. (Currently we read-only from partition table) lphdisk-0.9.1.debian/lphdisk.80000644000175000017500000000752707341257464015232 0ustar roverrover.\" Process this file with .\" groff -man -Tascii foo.1 .\" .TH lphdisk 8 "23 August 2001" Linux "Linux System Administrator's Manual" .SH NAME lphdisk \- prepare a hibernation partition for NoteBIOS suspend-to-disk .SH SYNOPSIS .B lphdisk [ .B -h, --help ] [ .B -p, --probeonly ] [ .B -q, --quiet ] [ .B -d, --debug ] [ .B -n, --nowrite ] [ .B -f, --force ] [ .I device ] .SH DESCRIPTION .B lphdisk prepares a hard disk for use with APM "Suspend-to-disk" features, as implemented on laptop computers running Phoenix NoteBIOS. Currently, the utility only formats an already created partition set to type .B A0 with a disk partitioning utility such as .BR fdisk (8). .I device should be a full-disk device (such as .B /dev/hda or .B /dev/sda ) and defaults to .B /dev/hda . .PP Since most laptops only have one IDE hard disk, and all known NoteBIOS configurations will only look to the first bootable hard drive anyway, the default value for .I device is correct for most cases. .PP In order to properly prepare a hard disk for suspend-to-disk on your laptop, you will need to make sure there is enough space free to accommodate an additional hibernation partition. The hibernation partition must be a primary partition (1-4), and the required size will be determined by the amount of physical and video RAM in your laptop. To determine the size you need to make the partition, the following calculation is a good rule of thumb: .sp .RS .B physical RAM + .B video memory + 2MB .RE .sp Alternately, you can run .B lphdisk --probeonly to have lphdisk attempt to determine your memory requirements and calculate a reccomended partition size for you. .PP Having created a primary partition of the proper size using a disk partitioning utility, you should set it to type .B A0 hex (identified by .BR fdisk as "IBM ThinkPad Hibernation", though "Phoenix NoteBIOS Hibernation" would be a more correct label). .PP .B lphdisk will then locate, verify, and format this partition for use. At this point you will need to reboot the system so that BIOS can locate and use the new hibernation partition. .PP Once the system has been rebooted, you should be able to perform the suspend-to-disk function of your BIOS using the normal procedure ( .B Fn-F12 on many laptops, though some differ. The .B apm --suspend command may or may not also do this, depending on the BIOS). You will know it is working properly if you see a Phoenix NoteBIOS screen appear indicating the progress of saving memory to disk before the machine powers off, and a similar screen indicating resume progress when it is started up again (if you do not see this screen, it is likely that the BIOS has entered suspend-to-RAM mode instead, and is not successfully using the hibernate partition). .SH OPTIONS .TP .B -h, --help show terse usage information and available options. .TP .B -p, --probeonly Probe for and calculate the required partition size for the current system, but do not attempt to format anything. .TP .B -q, --quiet tells lphdisk to be quiet: the normal output messages will not be displayed. .TP .B -d, --debug turns on (copious) debugging output. .TP .B -n, --nowrite tells lphdisk to do everything it would normally do, but not to actually write data to the disk. Useful for testing. .TP .B -f, --force force lphdisk to proceed, regardless of potential problems. .B This option is dangerous and could cause disk corruption! .SH TODO Currently .I lphdisk only formats an already properly created hibernation partition. It is the goal of this utility to be able to detect physical and video memory as well as create the partition before formatting it. .SH BUGS No known bugs, but that doesn't mean they're not in there. However, functionality is not yet complete. .SH AUTHORS .nf Patrick D. Ashmore Alex Stewart .fi .SH "SEE ALSO" .BR fdisk (8), .BR cfdisk (8), .BR sfdisk (8), .BR apm (1) .BR apmd (8) lphdisk-0.9.1.debian/lphdisk.c0000644000175000017500000007574407432173273015307 0ustar roverrover/* * lphdisk - Hibernation Parititon Prep Utility for laptops running Phoenix * NoteBIOS. * * Copyright 2000-2001 Patrick D. Ashmore and * Alex Stewart * This software is released under the Artistic License * * lphdisk 0.9.1 */ /* A couple of notes: - Partition numbers are always passed and used base-one (i.e. the first partition is partition 1, not 0). This ensures consistency both throughout the program and with convention elsewhere, reducing the risk of something using a different partition than it thought it was. This does mean, however, that if you ever see something like "pi[partnum]", it is probably _wrong_ (it probably should be "pi[partnum-1]"). Be careful! */ #include #include #include #include #include #include #include #include #include #include #include "lrmi.h" #include "vbe.h" /* General Program Defines: */ #define SECTOR_SIZE 512 /* Bytes per sector */ #define PP_BLOCK_SIZE 2 /* Sectors per "block" in /proc/partitions */ #define MBR_SIZE 512 /* Boot record is 512-bytes long */ #define TABLE_START 0x1BE /* Start of partition table in MBR */ #define TABLE_MAGIC 0x1FE /* Start of "magic number" in MBR */ #define TABLE_ENTRY 16 /* Length of a single partition table entry */ #define PART_TYPE 4 /* Position of partition type byte */ #define PART_START 8 /* Position of start sector (32-bit value) */ #define PART_SIZE 12 /* Position of partition size (32-bit value) */ #define MAGIC_ID 0xAA55 /* "magic number" (little-endian reversed) */ #define HIBERNATION_ID 0xA0 /* NoteBIOS Hibernation partition ID */ #define EXTENDED_ID 0x05 /* ID for an "extended partition" area */ #define PROBE_PADDING 2048 /* Add 2MB "padding" to probed requirements */ /* Error Exit Codes: */ #define ERR_USAGE 1 /* User requested usage message */ #define ERR_BADARGS 2 /* User entered bad command arguments */ #define ERR_OPEN 3 /* Open of device failed */ #define ERR_STAT 4 /* Statting open device failed */ #define ERR_BADFILE 5 /* Bad file type */ #define ERR_READ 6 /* Read error */ #define ERR_TABLE 7 /* Error reading/checking partition table */ #define ERR_FINDPART 8 /* Problem determining which partition to use */ #define ERR_WRITE 9 /* Problem formatting hibernate partition */ #define ERR_CANTPROBE 10 /* Asked to probe only, but can't obtain info */ /* Structs and Type Declarations: */ typedef struct { int type; /* Partition type ID */ size_t start; /* Start sector of partition */ size_t size; /* Length of partition in sectors */ } partinfo; /* Global Variables: */ const char *version_string = "lphdisk 0.9.1, by Patrick D. Ashmore and Alex Stewart"; const char *pp_filename = "/proc/partitions"; const char *mtrr_filename = "/proc/mtrr"; const char *meminfo_filename = "/proc/meminfo"; int force_flag = 0; /* "force" is off by default */ int quiet_flag = 0; /* Be noisy by default */ int debug_flag = 0; /* Debugging messages off by default */ int write_flag = 1; /* Do actually write things, though */ int probeonly_flag = 0; /* Continue after probing by default */ char phasers[] = "stun"; /* We come in peace! (Shoot to kill!) */ /* The header, with sector and checksum values set to 0, looks like this: */ /* __ __ __ __ __ __ */ /* 54 69 6D 4F 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 */ /* Checksum Size in Sectors */ const unsigned char header_base[] = { /* first 16 bytes of an empty header */ 0x54, 0x69, 0x6D, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, }; /*****************************************************************************/ /* General Purpose Utility Routines */ /*****************************************************************************/ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* The following is a hack to take advantage of the ext2 "_llseek" system */ /* call to do seeks to "long long" offsets under linux (this is needed to */ /* seek to sectors beyond 4194303 (2GB)). This isn't directly supported by */ /* glibc, so we need to make our own interface function for it. We should */ /* be able to get the _NR__llseek define from linux/unistd.h. From this we */ /* can construct a wrapper to perform the right system call. */ #include /* for __NR__llseek */ typedef long long lloff_t; #ifdef __NR__llseek static _syscall5(int,_llseek, unsigned int,fd, unsigned long,offset_high, unsigned long,offset_low, lloff_t *,result, unsigned int,origin) lloff_t llseek (unsigned int fd, lloff_t offset, unsigned int origin) { lloff_t result; int retval; retval = _llseek (fd, ((unsigned long long) offset) >> 32, ((unsigned long long) offset) & 0xffffffff, &result, origin); return (retval == -1 ? (lloff_t) retval : result); } #else /* __NR__llseek */ /* Somehow, __NR__llseek wasn't in linux/unistd.h. This shouldn't ever */ /* happen, but better safe than sorry.. The best we can do is emulate it */ /* with lseek, and hope we don't get an offset that's too large (throw an */ /* error if we do) */ lloff_t llseek (unsigned int fd, lloff_t offset, unsigned int origin) { off_t offt_offset = (off_t) offset; if ((lloff_t)offt_offset != offset) { /* converting to off_t and back yields different result, indicating an */ /* overflow.. */ errno = EINVAL; return -1; } else { return lseek(fd, offt_offset, origin); } } #endif /* __NR__llseek */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define get16(p) get_int_le(p,2) #define get32(p) get_int_le(p,4) /* get_int_le(): Pull an integer in little-endian format from 'buf'. */ /* 'numbytes' should be 2 or 4, for an 16-bit or 32-bit value. Returns the */ /* value read. Generally called using the get16 and get32 macros above. */ int get_int_le (const unsigned char *buf, int numbytes) { int value = 0; int i; for (i=numbytes-1; i>=0; i--) { value = (value << 8) + buf[i]; } return value; } #define put16(p,v) put_int_le(p,2,v) #define put32(p,v) put_int_le(p,4,v) /* put_int_le(): Insert 'value' into 'buf' in little-endian format. */ /* 'numbytes' should be 2 or 4, for an 16-bit or 32-bit value. */ /* Generally called using the put16 and put32 macros above. */ void put_int_le (unsigned char *buf, int numbytes, int value) { int i; for (i=numbytes-1; i>=0; i--) { buf[i] = value & 0xFF; value = value >> 8; } } /* seek_sector(): Seek to a particular sector on the disk. Returns zero on */ /* success, nonzero on error. */ int seek_sector (int fd, size_t secno) { lloff_t offset = (lloff_t) secno * SECTOR_SIZE; if (llseek(fd, offset, SEEK_SET) == (lloff_t) -1) return -1; return 0; } /*****************************************************************************/ /* lphdisk-specific Functions */ /*****************************************************************************/ /* debug(): Write a debugging message (if debug_flag is set). Arguments are */ /* the same as for printf. */ void debug (char *fmt, ...) { va_list ap; va_start(ap, fmt); if (debug_flag) vprintf(fmt, ap); va_end(ap); } /* do_write(): Write 'count' bytes from 'buf' to file 'fd'. Returns number */ /* of bytes written. (this is a wrapper for the write() system call which */ /* simply checks write_flag first, to support the -n command line option) */ ssize_t do_write (int fd, const void *buf, size_t count) { //static FILE *f = 0; if (write_flag) { //if (f == 0) f = fdopen(fd, "a"); //return fwrite(buf, 1, count, f); return write(fd, buf, count); } else { return count; } } /* read_mbr(): Read the Master Boot Record from sector 0 of 'fd' and store */ /* it in 'buf'. 'buf' must point to a buffer at least MBR_SIZE. Returns */ /* nonzero on error. */ int read_mbr (int fd, unsigned char *buf) { if (seek_sector(fd, 0) || (read(fd, buf, MBR_SIZE) != MBR_SIZE)) { if (errno) { perror("read_mbr"); } else { fprintf(stderr, "read_mbr: short read\n"); } return 1; } return 0; } /* parse_table(): Take an MBR in 'buf', parse the important bits of the */ /* primary partition table, and store them in 'pi' (an array of 4 partinfo */ /* structs, one for each primary partition). Performs basic sanity checking */ /* on what it finds. Returns nonzero on error. */ int parse_table (const unsigned char *buf, partinfo *pi) { int i, i_start, i_end; int j, j_start, j_end; const unsigned char *pos; /* Do some minimal sanity checking by verifying that the sector we've */ /* read has the right (two-byte) magic number at the end of it for a */ /* partition table */ if (get16(buf + TABLE_MAGIC) != MAGIC_ID) { debug("magic number=%04X\n", get16(buf + TABLE_MAGIC)); fprintf(stderr, "parse_table: Invalid partition table magic number!\n"); return 1; } /* Parse the important bits of the 4 primary partitions in the MBR */ debug("Parsing Partition table:\n"); for (i=1; i<5; i++) { pos = buf + TABLE_START + ((i-1) * TABLE_ENTRY); pi[i-1].type = *(pos + PART_TYPE); pi[i-1].start = get32(pos + PART_START); pi[i-1].size = get32(pos + PART_SIZE); debug(" %d: type=%02x, start=%u, size=%u\n", i, pi[i-1].type, pi[i-1].start, pi[i-1].size); /* Also sanity-check the partition's allocation on the disk.. */ if (pi[i-1].type) { i_start = pi[i-1].start; i_end = i_start + pi[i-1].size; for (j=1; j= j_start) && (i_start < j_end)) || ((j_start >= i_start) && (j_start < i_end)))) { fprintf(stderr, "parse_table: Partition %d overlaps with" " partition %d!\n", i, j); return 1; } } } } return 0; } /* check_proc_partitions(): Take parsed partition information for a device */ /* (in 'pi' array) and attempt to correlate it with what the kernel reports */ /* in /proc/partitions for that device. 'dev' indicates the major/minor */ /* numbers for the device that 'pi' contains info for. Returns nonzero on */ /* error. */ int check_proc_partitions (dev_t dev, const partinfo *pi) { FILE *f; int devmajor = major(dev); int devminor = minor(dev); int checked[4] = {0,0,0,0}; int result, major, minor, size, partition; int i; if (!(f = fopen(pp_filename, "r"))) { fprintf(stderr, "Unable to open %s: %s\n", pp_filename, strerror(errno)); return 1; } result = fscanf(f, "%*[^\n]\n"); /* Read the header line and discard it */ while (result != EOF) { result = fscanf(f, "%d %d %d %*[^\n]\n", &major, &minor, &size); if (result == 3 && major == devmajor) { if (minor > devminor && minor < devminor+5) { /* Found one within the first four partitions of our disk.. */ partition = minor - devminor; if (!(pi[partition-1].type)) { debug("Warning: Partition %d is listed in %s, but is not present in " "partition table!\n", partition, pp_filename); return 1; } if (size != (pi[partition-1].size / PP_BLOCK_SIZE)) { /* Sizes don't match! */ if (pi[partition-1].type == EXTENDED_ID) { /* It's ok, the extended partition doesn't have an accurate size */ /* listed in /proc/partitions, so we can't expect it to match. */ } else { debug("Warning: Size of partition %d in partition table (%u) does" " not match size listed in %s (%u)!\n", partition, pi[partition-1].size, pp_filename, size * PP_BLOCK_SIZE); return 1; } } /* Everything checks out for this partition.. */ checked[partition-1] = 1; } } } for (i=1; i<5; i++) { if (pi[i-1].type && !checked[i-1]) { /* Found a partition in the table that isn't in /proc/partitions! */ if (pi[i-1].type == HIBERNATION_ID) { /* We'll make an exception if the (apparently newly created) */ /* partition is the hibernation partition and there's nothing else */ /* odd about the disk (if the user just created it, and we're not in */ /* danger of clobbering some other partition, it'll save on reboots */ /* if they can run this immediately afterward, and it should be */ /* safe). */ debug("Hibernation partition %d is not listed in %s.\n", i, pp_filename); } else { debug("Partition %d is listed in partition table, but is not" " present in %s!\n", i, pp_filename); return 1; } } } /* All systems are go! */ return 0; } /* seek_a0(): Given a partinfo array ('pi'), find the partition with the */ /* right ID for a hibernation partition. Returns the partition number if */ /* found, 0 if not found, or -1 if more than one partition matches. */ int seek_a0 (const partinfo *pi) { /* FUNCTION - find a0 partition */ int i; int partition = 0; for (i=1; i<5; i++) { if (pi[i-1].type && (pi[i-1].type == HIBERNATION_ID)) { debug("Hibernation partition found on partition %d\n", i); if (partition == 0) { partition = i; } else { partition = -1; } } } return partition; } /* create_header(): Given a buffer of size SECTOR_SIZE in 'buf', create a */ /* NoteBIOS hibernation header sector appropriate for a hibernation */ /* partition of size 'partsize'. */ void create_header (unsigned char *buf, size_t partsize) { unsigned int word; /* byte pair for checksum addition */ unsigned int checksum; /* running checksum total */ int i; /* general counter variable */ memcpy(buf, header_base, 16); /* Start off with the base header */ buf[16] = partsize & 0xFF; /* first byte in sector size */ buf[17] = (partsize >> 8) & 0xFF; /* second byte in sector size */ buf[18] = (partsize >> 16) & 0xFF; /* third byte in sector size */ buf[19] = (partsize >> 24) & 0xFF; /* fourth byte in sector size */ debug("create_header: read_sz_b0: %02X\n", buf[16]); debug("create_header: read_sz_b1: %02X\n", buf[17]); debug("create_header: read_sz_b2: %02X\n", buf[18]); debug("create_header: read_sz_b3: %02X\n", buf[19]); debug("create_header: Bytes for total sectors: %08X\n", partsize); for (i = 20; i < SECTOR_SIZE; i++) buf[i] = 0xFF; /* header filler with FFs */ checksum = 0; for (i = SECTOR_SIZE-2; i > 6; i -= 2) { /* compute the checksum */ word = get16(buf+i); checksum = checksum + word; /* add word to checksum */ debug("create_header: i=%03d W=%04X CS=%08X %08X %08X\n", i, word, checksum, -checksum, ~checksum); } checksum = ~checksum; /* invert checksum */ buf[6] = checksum & 0xFF; /* significant high byte of checksum */ buf[7] = (checksum >> 8) & 0xFF; /* significant low byte of checksum */ debug("create_header: Bytes (in order) to insert in checksum spot:"); debug(" %02X %02X\n", buf[6], buf[7]); } /* do_format(): Actually do the formatting of a hibernate partition. 'fd' */ /* is a descriptor for the "master" disk device (_not_ the partition */ /* device), and 'pinfo' contains the partinfo struct for the appropriate */ /* partition to use. Returns nonzero on failure. */ int do_format (int fd, partinfo pinfo) { int i; unsigned char *buf; unsigned int start_sector = pinfo.start; unsigned int partsize = pinfo.size; buf = malloc(SECTOR_SIZE); if (!buf) { fprintf(stderr, "do_format: memory allocation failed!\n"); return 1; } create_header(buf, partsize); /* debug section */ if (debug_flag) { char *spacer; /* debug output beautifier :) */ debug("do_format: Partition header:\ndo_format: "); for (i=0; i<512; i++) { if ((i+1) % 16 == 0) { spacer = "\ndo_format: "; } else { if ((i+1) % 8 == 0) { spacer = " "; } else if ((i+1) % 4 == 0) { spacer = " "; } else { spacer = " "; } } debug("%02X%s", buf[i], spacer); } debug("End of header...\n"); } /* end debug section */ debug("seeking to sector %u...\n", start_sector); seek_sector(fd, start_sector); /* position to beginning of partition */ /* Write two copies of the header sector */ if ((do_write(fd, buf, SECTOR_SIZE) != SECTOR_SIZE) || (do_write(fd, buf, SECTOR_SIZE) != SECTOR_SIZE)) { perror("do_format(header)"); return 1; } for (i = 0; i < SECTOR_SIZE; i++) buf[i] = 0x50; /* Write partsize-2 "blank" sectors */ for (i = 3; i <= partsize; i++) { if (do_write(fd, buf, SECTOR_SIZE) != SECTOR_SIZE) { perror("do_format"); return 1; } /* only update output every 50 sectors */ if (((i % 50) == 0) || (i == partsize)) { if (quiet_flag == 0) { printf("Formatting sector %d of %u.", i, partsize); printf(" (sectors of %d bytes)\r", SECTOR_SIZE); } } } return 0; } /* mtrr_physmem(): Use /proc/mtrr to attempt to determine the amount of */ /* physical RAM in the system. Returns the size of RAM (in KB) indicated */ /* by /proc/mtrr, or zero if it could not determine an appropriate value. */ int mtrr_physmem(void) { FILE *f; int base, size; if (!(f = fopen(mtrr_filename, "r"))) { debug("Unable to open %s: %s\n", mtrr_filename, strerror(errno)); return 0; } if ((fscanf(f, "reg%*d: base=0x%*x (%dMB), size=%dMB", &base, &size) != 2) || (base != 0)) { debug("Parse of %s failed.\n", mtrr_filename); return 0; } fclose(f); size *= 1024; debug("%s reports main RAM as %d KB\n", mtrr_filename, size); return size; } /* meminfo_physmem(): Use /proc/meminfo to attempt to determine the amount */ /* of physical RAM in the system. Returns the size of RAM (in KB) indicated */ /* by /proc/meminfo, or zero if it could not determine an appropriate value. */ int meminfo_physmem(void) { FILE *f; unsigned int size; int ramsize; if (!(f = fopen(meminfo_filename, "r"))) { debug("Unable to open %s: %s\n", meminfo_filename, strerror(errno)); return 0; } fscanf(f, "%*[^\n]\n"); /* Read the header line and discard it */ if (fscanf(f, "Mem: %u", &size) != 1) { debug("Parse of %s failed.\n", meminfo_filename); return 0; } fclose(f); /* convert to KB and then round up to the next power of 2 (since RAM */ /* sizes don't come in anything else, so this should correct for the */ /* kernel size, etc) */ size >>= 10; debug("%s reports memory size of %d KB", meminfo_filename, size); for (ramsize = 1; size; size >>= 1) ramsize <<= 1; debug(" (adjusted=%d)\n", ramsize); return ramsize; } /* get_physmem(): Use all available methods to get a best guess of the */ /* amount of physical RAM in the system. Returns the size of RAM (in KB), */ /* or zero if it could not determine an appropriate value. */ int get_physmem(void) { int mtrr_size, meminfo_size; /* First try /proc/mtrr, as this gives us actual physical memory on most */ /* systems. This info won't exist on earlier kernels or if the kernel */ /* wasn't compiled with it enabled, though. (this can also give rather */ /* wonky info on non-IA32 systems, or possibly really odd IA32 ones, but */ /* it's very unlikely we'll find a laptop with one of these */ /* configurations, especially one with a NoteBIOS in it) */ mtrr_size = mtrr_physmem(); /* Now try /proc/meminfo. This is the total usable memory reported by the */ /* kernel, and should always be available, but this can be reduced by the */ /* kernel's size and internal allocations, as well as being overridable by */ /* boot parameters, etc. The meminfo_physmem() routine attempts to */ /* compensate for the space used by the kernel, but can't do anything */ /* about boot parameters or some other things that can change this value. */ meminfo_size = meminfo_physmem(); if (mtrr_size >= meminfo_size) { debug("get_physmem: RAM size is %d KB\n", mtrr_size); return mtrr_size; } else { debug("get_physmem: RAM size is %d KB\n", meminfo_size); return meminfo_size; } } /* vesa_videomem(): Use VESA BIOS Extension calls to attempt to query the */ /* amount of RAM on the video card (this should work on almost all modern */ /* models). This routine uses a copy of Josh Vanderhoof's LRMI library */ /* taken from svgalib to perform the appropriate BIOS interrupts. Returns */ /* the amount of video RAM detected (in KB) or zero if it was unable to */ /* obtain a number. */ int vesa_videomem(void) { struct LRMI_regs r; struct vbe_info_block *info; int video_mem; /* (we do this first so we can catch the case of the user not being root */ /* (and quietly handle it with a debug message) before LRMI_init fails to */ /* open /dev/mem and prints an error message (since the user not being */ /* root is not technically an error, it just reduces some of the */ /* functionality we can provide) */ /* Allow read/write to all IO ports: */ if (iopl(3) == -1) { debug("Can't set privilege level for VESA probe: %s\n", strerror(errno)); return 0; } if (!LRMI_init()) { debug("LRMI initialization failed.\n"); iopl(0); return 0; } info = LRMI_alloc_real(sizeof(struct vbe_info_block)); if (info == NULL) { debug("vesa_videomem: can't alloc real mode memory.\n"); iopl(0); return 0; } memcpy(info->vbe_signature, "VBE2", 4); memset(&r, 0, sizeof(r)); r.eax = 0x4f00; r.es = (unsigned int)info >> 4; r.edi = 0; if (!LRMI_int(0x10, &r)) { debug("Can't get VESA info (vm86 failure).\n"); iopl(0); return 0; } /* Set privilege level back to normal now that we're done with it */ iopl(0); if ((r.eax & 0xffff) != 0x4f || strncmp(info->vbe_signature, "VESA", 4) != 0) { debug("No VESA bios.\n"); return 0; } debug("VBE Version %x.%x\n", (int)(info->vbe_version >> 8) & 0xff, (int)info->vbe_version & 0xff); debug("Video card identified as: %s\n", (char *)(info->oem_string_seg * 16 + info->oem_string_off)); /* The VESA BIOS call returns memory in 64KB units. Multiply to get KB.. */ video_mem = (int)(info->total_memory) * 64; debug("Total video memory: %u KB\n", video_mem); LRMI_free_real(info); return video_mem; } /* get_videomem(): Use all available methods to get a best guess of the */ /* amount of RAM in the video card. Returns the size of RAM (in KB), */ /* or zero if it could not determine an appropriate value. */ /* (currently vesa_videomem() is the only method, so this is just a wrapper */ /* define) */ #define get_videomem() vesa_videomem() /*****************************************************************************/ /* Main Program */ /*****************************************************************************/ char *argv0; const char short_opts[] = "hpqdnf"; const struct option long_opts[] = { {"help", 0, 0, 'h'}, {"probeonly", 0, 0, 'p'}, {"quiet", 0, 0, 'q'}, {"debug", 0, 0, 'd'}, {"nowrite", 0, 0, 'n'}, {"force", 0, 0, 'f'}, {0,0,0,0}}; const char usage_string[] = "\ Usage: %1$s [options] [device] Prepare a hibernation partition for APM suspend-to-disk. options: -h, --help Display brief usage and option information (this screen) -p, --probeonly Only calculate and display required size, do not format -q, --quiet Turn off informational messages, useful for scripts -d, --debug Turn on (verbose) debugging messages -n, --nowrite Do not actually write to the disk -f, --force **DANGEROUS** Format without regard to potential problems 'device' should be a raw disk device (not a partition). The default device is /dev/hda. (%2$s)\n\n"; void print_usage (void) { char *progname = rindex(argv0, '/'); progname = progname ? progname+1 : argv0; printf(usage_string, progname, version_string); } int main (int argc, char **argv) { /* MAIN FUNCTION - the beast */ char drive[FILENAME_MAX] = "/dev/hda";/* Default to /dev/hda */ int fd; struct stat st; unsigned char mbr_buf[MBR_SIZE]; partinfo pi[4]; dev_t dev; int partition; int ramsize, vramsize, required_size; size_t required_sectors; argv0 = argv[0]; while (1) { /* loop to parse command line args */ int c; /* current getopt option */ c = getopt_long (argc, argv, short_opts, long_opts, 0); if (c == -1) break; /* break if error */ switch (c) { /* case switch for options */ case 'h': /* case h - help */ print_usage(); /* print help information */ return ERR_USAGE; case 'p': /* case p - probeonly */ probeonly_flag = 1; break; case 'q': /* case q - be quiet! */ quiet_flag = 1; /* set quiet flag */ break; case 'd': /* case d - debug on */ debug_flag = 1; break; case 'n': /* case n - no write */ write_flag = 0; break; case 'f': /* case f - force */ force_flag = 1; /* use the force */ break; case '?': case ':': print_usage(); return ERR_BADARGS; } } if (optind < argc) strcpy(drive, argv[optind++]); if (optind < argc) { /* extra argument routine */ printf("Unexpected arguments: "); /* print error */ while (optind < argc) { printf ("%s ", argv[optind++]); /* print bad args */ } printf ("\n"); print_usage(); return ERR_BADARGS; } /* That takes care of argument parsing, now on with the actual work... */ if (!(ramsize = get_physmem())) { if (!quiet_flag) printf("Warning: Cannot determine physical RAM.\n"); required_size = 0; } else if (!(vramsize = get_videomem())) { if (!quiet_flag) printf("Warning: Unable to determine the amount of video" " RAM.\n"); required_size = 0; required_sectors = 0; } else { required_size = ramsize + vramsize + PROBE_PADDING; required_sectors = (((size_t)required_size * 1024) / SECTOR_SIZE) + 2; } if (!required_size) { if (!quiet_flag) printf("Reccomended partition size is unknown.\n"); } else { if (!quiet_flag) printf("Reccomended partition size is %d MB" " (%d sectors)\n", ((required_size+1023) >> 10), required_sectors); } if (probeonly_flag) { return (required_size ? 0 : ERR_CANTPROBE); } /* Open the file. */ if ((fd = open(drive, O_RDWR)) == -1) { fprintf(stderr, "Error: cannot open %s: %s\n", drive, strerror(errno)); /* This error pops up a lot if someone runs lphdisk with no arguments */ /* and isn't root, which can happen if they've just */ /* installed/encountered it and don't know what it does or how it works. */ /* Give 'em a hint if this is the case. */ if (argc == 1) printf("(Try '%s --help' for help)\n", argv0); return ERR_OPEN; } /* Are we looking at a block device? */ if (fstat(fd, &st)) { perror("fstat"); return ERR_STAT; } if (S_ISBLK(st.st_mode)) { dev = st.st_rdev; debug("%s is a block device (major=%d, minor=%d)\n", drive, major(dev), minor(dev)); } else { if (force_flag) { if (!quiet_flag) fprintf(stderr, "Warning: %s is not a block device.\n", drive); dev = 0; } else { fprintf(stderr, "Error: %s is not a block device (override with -f)\n", drive); return ERR_BADFILE; } } /* Read the MBR and parse the partition table. */ if (read_mbr(fd, mbr_buf)) { fprintf(stderr, "Unable to read master boot record.\n"); return ERR_READ; } if (parse_table(mbr_buf, pi)) { fprintf(stderr, "Unable to parse partition table.\n"); return ERR_TABLE; } /* If we're using a block device, then verify it against /proc/partitions */ if (dev && check_proc_partitions(dev, pi)) { if (force_flag) { if (!quiet_flag) fprintf(stderr, "Warning: /proc/partitions does not" " match partition table.\n"); } else { fprintf(stderr, "Error: /proc/partitions does not match partition table" " (override with -f).\n"); return ERR_TABLE; } } /* Find the right partition. */ partition = seek_a0(pi); if (!partition) { fprintf(stderr, "Error: Unable to find partition of type %02X.\n", HIBERNATION_ID); return ERR_FINDPART; } else if (partition < 0) { fprintf(stderr, "Error: More than one partition is of type %02X. Unable" " to determine which to use.\n", HIBERNATION_ID); return ERR_FINDPART; } /* So far so good.. now it's time to actually _do_ it. */ if (!quiet_flag) printf("Creating hibernate area on %s, partition %d...\n", drive, partition); /* Check for a couple of things to warn people about.. */ if ((dev != makedev(3, 0)) && !quiet_flag) { fprintf(stderr, "Warning: The BIOS will probably be unable to use this" " hibernate partition\n because it is not on the first IDE" " drive.\n"); } if ((pi[partition-1].size < required_sectors) && !quiet_flag) { fprintf(stderr, "Warning: hibernate partition size (%d) is smaller than" " reccomended size (%d).\n", pi[partition-1].size, required_sectors); } /* And off we go! */ if (do_format(fd, pi[partition-1])) { if (!quiet_flag) printf("\n"); fprintf(stderr, "Format failed.\n"); return ERR_WRITE; } else { if (!quiet_flag) printf("\nFormat complete.\n"); } /* All done.. Clean up and exit. */ close(fd); return 0; } lphdisk-0.9.1.debian/lphdisk.spec0000644000175000017500000000273207432174561016003 0ustar roverroverSummary: Utility for formatting Phoenix NoteBIOS hibernation partitions under Linux Name: lphdisk Version: 0.9.1 Release: 1 Vendor: Patrick D. Ashmore Packager: Alex Stewart Copyright: Artistic License Group: System Environment/Base Source: http://www.procyon.com/~pda/lphdisk/lphdisk-0.9.1.tar.gz BuildRoot: %{_tmppath}/%{name}-root %description lphdisk is a linux reimplementation of the PHDISK.EXE (DOS) utility provided with most Phoenix NoteBIOS-equipped laptop models. It will properly format a NoteBIOS hibernation partition (type A0) to make it usable by the BIOS for suspending to disk, avoiding the need to use buggy and outdated DOS utilities to perform this configuration step. %prep %setup -q %build make %install rm -rf ${RPM_BUILD_ROOT} mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man8 mkdir -p ${RPM_BUILD_ROOT}%{_sbindir} install -m 755 lphdisk ${RPM_BUILD_ROOT}%{_sbindir} install -m 644 lphdisk.8 ${RPM_BUILD_ROOT}%{_mandir}/man8 %clean [ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,bin,bin) %doc ChangeLog %doc CREDITS %doc LICENSE %doc NEWS %doc README %doc TODO %{_sbindir}/lphdisk %{_mandir}/man8/lphdisk.8.gz %changelog * Tue Feb 12 2002 Alex Stewart - Updated to version 0.9.1 * Thu Aug 23 2001 Patrick D. Ashmore - Updated version information in spec file (0.4as1 to 0.9) * Sun Jul 15 2001 Alex Stewart - Initial RPM packaging of lphdisk 0.4as1