File: identify_bootdisk.in

package info (click to toggle)
yard 1.17.patch1-5
  • links: PTS
  • area: main
  • in suites: potato
  • size: 600 kB
  • ctags: 74
  • sloc: perl: 1,729; sh: 250; makefile: 176; asm: 32
file content (205 lines) | stat: -rw-r--r-- 6,356 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#! @PERL@
# -*- Mode: Perl -*-
# @configure_input@
#
#  $Id: identify_bootdisk.pl,v 1.1 1998/10/12 15:54:26 fawcett Exp fawcett $
#  IDENTIFY_BOOTDISK: Given a bootdisk image or floppy device, analyze
#  it and present as much information as possible.
#
#  Usage:
#     identify_bootdisk disk_or_file
#
#
##############################################################################
use strict qw(subs refs);
use FileHandle;
use Cwd;
use English;
use File::Find;

##############################################################################
# Constants from /usr/src/linux/arch/i386/kernel/setup.c:
$::RAMDISK_IMAGE_START_MASK   =	0x07FF;
$::RAMDISK_PROMPT_FLAG        =	0x8000;
$::RAMDISK_LOAD_FLAG          = 0x4000;

##############################################################################
STDOUT->autoflush(1);

#require "find.pl";
#sub wanted { &$wanted }

#  Filename for root filesystem listing
my($root_listing) = "rootfs.ls_alR";

%VGA_modestr
    = (-3  => "Prompt",
       -2  => "Extended VGA",
       -1  => "Normal VGA",
        0  => "as if 0 was pressed at the prompt",
        1  => "as if 1 was pressed at the prompt",
        2  => "as if 2 was pressed at the prompt"
      );


if ($#ARGV == -1) {
    print "\nUsage:\n";
    print "$PROGRAM_NAME disk_or_floppy_drive\n";
    exit;
}

my($boot_image) = @ARGV;

#  First, figure out what we're looking at
chomp($file_output = `file $boot_image`);

if ($file_output =~ /block special/) {
   ##  It's a device
   print "$boot_image is a device -- transferring contents\n";
   system("@DD@ if=$boot_image of=/tmp/boot_image");
   $boot_image = "/tmp/boot_image";
   chop($file_output = `file $boot_image`);

}   

print "File says:  $file_output\n";

my($kernel);
if ($file_output =~ /filesystem/) {
    mkdir("/tmp/mnt", 0777) unless -d "/tmp/mnt";
    system("@MOUNT@ -o loop $boot_image /tmp/mnt");
    sub wanted {
       print "Seeing $File::Find::name\n";
       $kernel = $File::Find::name 
	   if $File::Find::name =~ m!/(vmlinuz|zImage)$!;
    };
    find(\&wanted, "/tmp/mnt");

    die "Couldn't find a kernel!\n" unless defined($kernel);
    print "Found kernel file $kernel\n";
    undef &wanted;
#    #  We're done with the kernel filesystem
#    system("@UMOUNT@ /tmp/mnt");

} elsif ($file_output =~ /x86 boot sector/) {
   ## It's an image file
    $kernel = $boot_image;
 
} elsif ($file_output =~ /data/) {
    print "Boot image has no filesystem\n";
    $kernel = $boot_image;

} else {
    die "Can't identify boot image $boot_image\n";
}


open(KERNEL, "<$kernel")   or die "open $kernel: $!";
read(KERNEL, $header, 512) or die "couldn't read kernel header: $!";
close(KERNEL);

my($str)	       = "";
my($version_start) = "";

open(DATA, $boot_image) or die "can't open $boot_image.\n";
# check signature of kernel image
seek(DATA, 514, 0);
read(DATA, $str, 4);
die "Kernel image file ($boot_image) does not have Linux kernel signature\n"
    unless $str =~ "HdrS";
# setup header version should be 0x201
read(DATA, $str, 2);
$str = unpack("S",$str);
print "Kernel setup header version is 0x" .
    sprintf("%04x",$str)." (expected 0x0201).\n" unless $str == 0x201;
# get offset of version string (indirect) and read version string
seek(DATA, 526, 0);
read(DATA, $version_start, 2) or die "can't read from $boot_image.\n";
$version_start = unpack("S",$version_start) + 512;
seek(DATA, $version_start, 0);
read(DATA, $str, 10) or
    die "can't read from offset $version_start of $boot_image.\n";
close(DATA);
# extract the version number
my($version) = $str =~ /^(\d+\.\d+\.\d+)\s/;
print "Kernel version is $version\n";

#        In a bootable image for the Linux kernel, there  are  sev-
#        eral  pairs  of  bytes  which specify the root device, the
#        video mode, the size of the RAM disk, and the swap device.
#        These  pairs  of  bytes,  by  default, begin at offset 504
#        (decimal) in the kernel image:
#
#                498 Root flags
#               (500 and 502 Reserved)
#                504 RAM Disk Size
#                506 VGA Mode
#                508 Root Device
#               (510 Boot Signature)

my($root_flags, $x, $x, $ramdisk_word, $VGA_mode, $rdev_low, $rdev_high,
   $boot_signature) = unpack("x498 SSSSsCCS", $header);

if ($boot_signature == 0xAA55) {
    print "(Found boot signature on image)\n";
} else {
    die "Didn't find boot signature (0xAA55) on image!\n$boot_signature\n";
}


my($devname) = device_name($rdev_high, $rdev_low);
print "Root filesystem: ", $root_flags == 0 ? "Read/Write" : "Read-only", "\n";
print "Root device: major $rdev_high, minor $rdev_low" .
    ($devname ? " (= $devname)" : "") . "\n";
print "VGA mode: ", ($VGA_modestr{$VGA_mode} or $VGA_mode), "\n";

#  Now interpret the ramdisk word
print "Raw RAMDISK word: ", sprintf("0x%X", $ramdisk_word), "\n";
my($ramdisk_offset) = $ramdisk_word & $RAMDISK_IMAGE_START_MASK;
my($ramdisk_load)   = $ramdisk_word & $RAMDISK_LOAD_FLAG   ? 1 : 0;
my($ramdisk_prompt) = $ramdisk_word & $RAMDISK_PROMPT_FLAG ? 1 : 0;
print "\tRamdisk load: $ramdisk_load\n";
if ($ramdisk_load > 0) {
   printf("\tRamdisk offset: %d (0x%X) blocks\n",
	  $ramdisk_offset, $ramdisk_offset);
   print "\tRamdisk prompt: $ramdisk_prompt\n";
}

if ($ramdisk_prompt != 0) {
    exit;
} else {
    system("@DD@ if=$boot_image skip=$ramdisk_start of=/tmp/ramdisk.gz bs=1k");
    system("@GUNZIP@ --force /tmp/ramdisk.gz");
    mkdir("/tmp/mnt2", 0777) unless -d "/tmp/mnt2";
    system("@MOUNT@ -o loop /tmp/ramdisk /tmp/mnt2");
    my($here) = cwd();
    system("cd /tmp/mnt2 ; ls -alR . > $here/$root_listing");
    system("@UMOUNT@ /tmp/mnt2");
    unlink("/tmp/ramdisk") or die "unlink ramdisk: $!";
}

print "Done, listing of root filesystem is on $root_listing\n";
exit(0);


#  DEVICE_NAME(major,minor)
#
#  Given a pair of numbers (major, minor), print the device name.
#  Does this somewhat crudely by scanning your /dev directory and
#  seeing which device matches.
#  Tries to fail noiselessly.
sub device_name {
   my($major, $minor) = @_;

   opendir(DEVS, "/dev") or return("");
   my($file);
   while (defined($file = readdir(DEVS))) {
      my($device) = (stat("/dev/$file"))[6];
      if (-b _ and ($device >> 8) == $major  and ($device & 0xFF) == $minor) {
	 closedir(DEVS);
	 return("/dev/$file");
      }
   }
   closedir(DEVS);
   ""
}