Flush stdout before writing Done to stderr, and make 'type' 3 columns wide
[part-list.git] / part-list.c
1 /*
2    Display partition tables entries in a file
3    Copyright (C) 2010 TJ
4    Author: TJ <linux@tjworld.net>
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, version 3 of the License.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <sys/mman.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28
29 #define PT_BASE 0x1BE
30 #define PT_SIGNATURE 0x1FE
31
32 static const char const *version = "1.0.0";
33
34 enum pt_table_entry {
35  PT_STATUS = 0,
36  PT_FIRST_HEAD,
37  PT_FIRST_CYLINDER,
38  PT_FIRST_SECTOR,
39  PT_TYPE,
40  PT_LAST_HEAD,
41  PT_LAST_CYLINDER,
42  PT_LAST_SECTOR,
43  PT_FIRST_LBA,
44  PT_COUNT_LBA = 12
45 };
46
47 struct partition_table {
48  unsigned char status;
49  unsigned char first_head;
50  unsigned int first_cylinder;
51  unsigned char first_sector;
52  unsigned char type;
53  unsigned char last_head;
54  unsigned int last_cylinder;
55  unsigned char last_sector;
56  unsigned int first_LBA;
57  unsigned int count_LBA;
58 };
59
60 void
61 usage(const char *name) {
62  printf("Usage: %s [-d] -f <needle>\n"
63         " version %s\n", name, version);
64  printf("Copyright 2010 TJ <linux@tjworld.net>\n"
65         "Licensed under the terms of the GNU GPL v3\n\n"
66         "\t-d\tprint values in decimal not hexadecimal\n"
67         "\t-f\tpath to the file containing the partition table (it is scanned for sectors containing the signature)\n"
68  );
69 }
70
71 int
72 main(int argc, char *argv[], char *env[]) {
73  int ret = 0;
74  int c, use_decimal, pt_fd;
75  char *pt_name;
76  void *pt_mmap;
77  struct stat pt_stat;
78  char signature[2] = {0x55, 0xAA};
79  pt_name = pt_mmap = NULL;
80  use_decimal = 0;
81
82  if (argc > 1) { // must have some parameters
83   opterr = 0;
84
85   while ((c = getopt(argc, argv, "f:d")) != -1 ) { // iterate the options
86    switch(c) {
87     case 'f':
88      pt_name = optarg;
89      break;
90     case 'd':
91      use_decimal = 1;
92      break;
93     default:
94      abort();
95    }
96   }
97
98   if ((pt_fd = open(pt_name, O_RDONLY)) == -1) {
99    perror("Unable to open file");
100    ret |= 1;
101   }
102
103   if (!ret) {
104    fstat(pt_fd, &pt_stat);
105    fprintf(stderr, "Base:\t%s\n", use_decimal == 1 ? "decimal" : "hexadecimal");
106    fprintf(stderr, "File:\t\t%12ld\t%s\n", pt_stat.st_size, pt_name);
107
108    if(MAP_FAILED == (pt_mmap = mmap(pt_mmap, pt_stat.st_size, PROT_READ, MAP_SHARED, pt_fd, 0))) {
109     perror("Unable to memory-map file");
110     exit(4);
111    }
112    {
113     char fmt_spec[100];
114     char *format[2][5] = {
115      { "%8lX", "%08lX", "%02X", "%04X", "%03X" },
116      { "%8ld",  "%10ld", "%2d", "%4d",  "%3d" }
117     };
118     struct partition_table pt_table[4];
119     unsigned long offset, found;
120     unsigned long sector;
121     unsigned int pt_entry;
122     unsigned int pt_offset;
123
124     fprintf(stderr, "Searching...\n");
125     for (offset = 0, sector = 0; offset <= pt_stat.st_size; offset+=512, sector++) {
126      if ( memcmp(signature, pt_mmap + offset + PT_SIGNATURE, 2) == 0) {
127       found = offset;
128       sprintf(fmt_spec, "Signature found. sector: %s offset:%s\n", format[use_decimal][0], format[use_decimal][1]);
129       printf(fmt_spec, sector, offset);
130
131       for (pt_entry = 0; pt_entry < 4; pt_entry++) {
132        pt_offset = offset + (pt_entry * 16);
133        pt_table[pt_entry].status = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_STATUS);
134        pt_table[pt_entry].type = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_TYPE);
135        pt_table[pt_entry].first_cylinder = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_FIRST_CYLINDER);
136        pt_table[pt_entry].first_cylinder |= (((*(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_FIRST_SECTOR)) && 0xC0) << 8);
137        pt_table[pt_entry].first_head = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_FIRST_HEAD);
138        pt_table[pt_entry].first_sector = (*(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_FIRST_SECTOR)) && 0x3F;
139        pt_table[pt_entry].last_cylinder = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_LAST_CYLINDER);
140        pt_table[pt_entry].last_cylinder |= (((*(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_LAST_SECTOR)) && 0xC0) << 8);
141        pt_table[pt_entry].last_head = *(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_LAST_HEAD);
142        pt_table[pt_entry].last_sector = (*(unsigned char *)(pt_mmap + pt_offset + PT_BASE + PT_LAST_SECTOR)) && 0x3F;
143        pt_table[pt_entry].first_LBA = *(unsigned int *)(pt_mmap + pt_offset + PT_BASE + PT_FIRST_LBA);
144        pt_table[pt_entry].count_LBA = *(unsigned int *)(pt_mmap + pt_offset + PT_BASE + PT_COUNT_LBA);
145        
146        sprintf(fmt_spec, "%%d %%s %s %s %s %s %s %s %s %s %s (next %s)\n",
147         format[use_decimal][4], // type
148         format[use_decimal][3], // cyl
149         format[use_decimal][2], // head
150         format[use_decimal][2], // sector
151         format[use_decimal][3], // cyl
152         format[use_decimal][2], // head
153         format[use_decimal][2], // sector
154         format[use_decimal][1], // LBA
155         format[use_decimal][1], // LBA count
156         format[use_decimal][1] // LBA next
157        );
158        printf(fmt_spec,
159         pt_entry,
160         pt_table[pt_entry].status == 0x80 ? "A" : " ",
161         pt_table[pt_entry].type,
162         pt_table[pt_entry].first_cylinder,
163         pt_table[pt_entry].first_head,
164         pt_table[pt_entry].first_sector,
165         pt_table[pt_entry].last_cylinder,
166         pt_table[pt_entry].last_head,
167         pt_table[pt_entry].last_sector,
168         pt_table[pt_entry].first_LBA,
169         pt_table[pt_entry].count_LBA,
170         pt_table[pt_entry].first_LBA + pt_table[pt_entry].count_LBA
171        );
172       }
173      }
174     }
175     fflush(stdout);
176     fprintf(stderr, "Done.\n");
177    }
178   }
179  }
180  else
181   usage(argv[0]);
182
183  if (pt_mmap > 0) munmap(pt_mmap, pt_stat.st_size);
184  if (pt_fd > 0) close(pt_fd);
185
186  return ret;
187 }