File: readpart.c

package info (click to toggle)
atari-fdisk 0.7.1-1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 236 kB
  • ctags: 225
  • sloc: ansic: 2,946; makefile: 136; sh: 23
file content (403 lines) | stat: -rw-r--r-- 10,714 bytes parent folder | download | duplicates (4)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
/* readpart.c: read the partition table
 *
 * Copyright (C) 1995-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
 *               1996-97 Michael Schlueter <schlue00@marvin.informatik.uni-dortmund.de>
 *
 * This program is free software.  You can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation: either version 2 or
 * (at your option) any later version.
 *
 */

/* $Id: readpart.c,v 1.11 1998/02/07 21:24:32 rnhodek Exp $
 *
 * $Log: readpart.c,v $
 * Revision 1.11  1998/02/07 21:24:32  rnhodek
 * Open disk device in exclusive mode, to avoid several concurrent fdisks
 * on it.
 * Fix wrong if condition in get_boot (don't go to O_RDWR part in listing
 * mode...)
 * More descriptive messages if BLKRRPART failed.
 *
 * Revision 1.10  1998/02/04 14:51:35  rnhodek
 * Add missing brace
 *
 * Revision 1.9  1998/02/04 14:47:23  rnhodek
 * Make get_boot() more silent in listing mode
 *
 * Revision 1.8  1997/12/19 09:12:35  rnhodek
 * Don't ask "assume disk is unpartitioned?" in listing mode.
 *
 * Revision 1.7  1997/06/22 10:30:57  rnhodek
 * Add __attribute__((unused)) to cvid
 *
 * Revision 1.6  1997/06/21 20:47:49  rnhodek
 * Added RCS keywords
 *
 * Revision 1.5  1997/06/13 12:57:04  rnhodek
 * Little fixes
 * 
 * Revision 1.4  1997/06/13 12:50:44  rnhodek
 * Forgot byte swaps on writing
 * 
 * Revision 1.3  1997/06/12 13:43:39  rnhodek
 * Fix many small bugs here and there. The ones you find when first running a
 * program...
 * 
 * Revision 1.2  1997/06/11 19:49:17  rnhodek
 * Implemented bad sector list handling
 * 
 * Revision 1.1  1997/06/11 14:36:36  rnhodek
 * Initial revision
 * 
 * Revision 1.1.1.1  1997/06/11 14:36:36  rnhodek
 * Started using CVS for atafdisk
 *
 */

#ifndef lint
static char vcid[] __attribute__ ((unused)) =
"$Id: readpart.c,v 1.11 1998/02/07 21:24:32 rnhodek Exp $";
#endif /* lint */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

#include "fdisk.h"
#include "disk.h"
#include "writepart.h"
#include "input.h"
#include "util.h"


/***************************** Prototypes *****************************/

static __inline__ void swab_part( struct apartition *p );
static void diskpart2PART( struct apartition *dp, unsigned long sec,
                           PARTITION *cp );
static void check_n_partitions( void );
static void read_extended( struct apartition *pi, int *errs );

/************************* End of Prototypes **************************/



static __inline__ void swab_part( struct apartition *p )
{
#if BYTE_ORDER != BIG_ENDIAN
    swab( p->start );
    swab( p->size );
#endif
}

void swab_rs( struct rootsector *rs )
{
#if BYTE_ORDER != BIG_ENDIAN
    int i;

    for( i = 0; i < 8; ++i )
	swab_part( &rs->icdpart[i] );
    swab( rs->hd_size );
    for( i = 0; i < 4; ++i )
	swab_part( &rs->part[i] );
    swab( rs->bsl_st );
    swab( rs->bsl_cnt );
    swab( rs->checksum );
#endif
}

static void diskpart2PART( struct apartition *dp, unsigned long sec,
						   PARTITION *cp )

{
    cp->start   = sec + dp->start;
    cp->size    = dp->size;
    cp->flag    = dp->flag & ~PART_FLAG_VALID;
    cp->rootsec = sec;
    /* assume valid contents for any partition initially found on the disk */
    cp->contents_valid = 1;
    
    memcpy( cp->id, dp->id, 3 );
    cp->id[3] = 0;
}


static void check_n_partitions( void )

{
    if (partitions == MAXIMUM_PARTS) {
	fprintf( stderr, "Too many (more than %d) partitions on this disk!\n",
		 MAXIMUM_PARTS );
	fatal( general );
    }
}


static void read_extended( struct apartition *pi, int *errs )
{
    char buffer[SECTOR_SIZE];
    struct rootsector *xrs;
    unsigned long partsect, extensect;
    int i;

    partsect = extensect = pi->start;
    
    while( 1 ) {
	sread( buffer, partsect );
	xrs = (struct rootsector *)buffer;
	swab_rs( xrs );

	for( i = 0; i < 3; ++i ) {
	    if (xrs->part[i].flag & PART_FLAG_VALID)
		break;
	}
	if (i == 3) {
	    *errs += 2;
	    fprintf( stderr, "Partition format error:\n"
		     "  One of the first three sub-partitions in auxiliary "
		     "root sector must be valid!\n" );
	    return;
	}
	if (i != 0) {
	    printf( "Warning: Strange partition format.\n"
		    "  Empty slot(s) at start of auxiliary root sector\n" );
	}
	if (PID_EQ( xrs->part[i].id, "XGM" )) {
	    *errs += 2;
	    fprintf( stderr, "Partition format error:\n"
		     "  First valid entry in sub-partition is again XGM\n" );
	    return;
	}

	if (!is_valid_part_entry( &xrs->part[i] )) {
	    *errs += 2;
	    printf( "Partition entry in auxiliary root sector %lu contains "
		    "junk data! Ignored.\n", partsect );
	}
	else {
	    check_n_partitions();
	    diskpart2PART( &xrs->part[i], partsect, &part_table[partitions] );
	    ++partitions;
	}
		
	if (!(xrs->part[i+1].flag & PART_FLAG_VALID))
	    /* end of linked partition list */
	    break;

	if (!PID_EQ( xrs->part[i+1].id, "XGM" )) {
	    *errs += 2;
	    fprintf( stderr, "Partition format error:\n"
		     "  Second sub-partition in extended partion is "
		     "not XGM or empty!\n" );
	    return;
	}
	
	if (!is_valid_part_entry( &xrs->part[i+1] )) {
	    *errs += 2;
	    printf( "Chaining entry in auxiliary root sector %lu contains "
		    "junk data! Ignored.\n", partsect );
	    return;
	}
	    
	partsect = xrs->part[i+1].start + extensect;
    }
}

/* read the partition table */

void get_boot( void )
{
    char buffer[SECTOR_SIZE];
    struct rootsector *rs;
    struct apartition *pi;
    unsigned long blk_size;
    int i, errs = 0;

    if ((fd = open(disk_device, type_open|O_EXCL)) < 0) {
	/* try again without write access (doesn't hurt if type_open was
	 * already O_RDONLY, simply fails again) */
	type_open = O_RDONLY;
	if ((fd = open(disk_device, type_open|O_EXCL)) < 0)
	    fatal(unable_to_open);
    }

    if (type_open == O_RDONLY) {
	if (!listing)
	    printf("You will not be able to write the partition table.\n");
    }
    else {
	/* device is opened read-write; check nothing is mounted */
	printf( "Checking that no-one is using this disk right now... " );
	fflush(stdout);
	if (reread_ioctl( fd )) {
	    if (errno == EBUSY) {
		fprintf( stderr, "\nThis disk is currently in use - "
			 "repartitioning is probably a bad idea.\n" );
		if (!force)
		    fprintf( stderr, "Umount all file systems, and swapoff "
			     "all swap partitions on this disk.\n" );
	    }
	    else if (errno == EINVAL) {
		fprintf( stderr,"\nThis device is usually not partitioned.\n");
		if (!force)
		    fprintf( stderr, "Use -f if you want to run fdisk on it "
			     "nevertheless.\n" );
	    }
	    else {
		fprintf( stderr, "BLKRRPART failed with unknown reason...\n" );
	    }
	    if (!force) {
		close( fd );
		exit( 1 );
	    }
	    fprintf( stderr, "Continuing due to -f\n" );
	}
	else
	    printf( "OK\n" );
    }

    sread( buffer, 0 );
    rs = (struct rootsector *)buffer;
    swab_rs( rs );

    xpart_fmt = xfmt_unknown; /* don't know yet... */
    partitions = 0;

    /* disk size from root sector */
    rs_hd_size = rs->hd_size;
    /* real disk size */
    if (ioctl( fd, BLKGETSIZE, &blk_size )) {
	perror( "ioctl(BLKGETSIZE)" );
	fatal(general);
    }
    /* use real size by default */
    hd_size = blk_size;

    /* Unfortunately, there's no way to get the hard sector size of a device
     * :-( Ok, hss != 512 would be really strange, but a lot of things will
     * fail for this case. We should really check, but we can't :-((( */
    
    if (blk_size != rs_hd_size) {
	++errs;
	printf( "hd_size seems to be incorrect (%lu vs. real %lu)\n", 
		rs_hd_size, blk_size );
	if (listing)
	    /* don't ask in list mode... */
	    hd_size = blk_size;
	else if (read_yesno( "Correct hd_size on disk (when writing table)", 1 ))
	    rs_hd_size = blk_size;
	else {
	    if (rs_hd_size < blk_size) {
		printf( "Ok, using smaller size (from root sector) as limit\n" );
		hd_size = rs_hd_size;
	    }
	    else
		printf( "Nevertheless using physical size as limit, since "
			"hd_size is too big!\n" );
	}
    }

    /* check if bad sector list is either empty or data seem valid */
    if ((!rs->bsl_st && !rs->bsl_cnt) ||
	(rs->bsl_st > 0 && rs->bsl_st < hd_size &&
	 rs->bsl_cnt > 0 && rs->bsl_st+rs->bsl_cnt <= hd_size)) {
	bsl_start = saved_bsl_start = rs->bsl_st;
	bsl_size  = saved_bsl_size  = rs->bsl_cnt;
    }
    else {
	errs += 2;
	printf( "Bad data for bad sector list (start %lu, size %lu)\n"
		"Assuming it to be empty.\n",
		rs->bsl_st, rs->bsl_cnt );
	bsl_start = bsl_size = 0;
    }

    bsl_HDX_compat = 0;
    if (bsl_start > 0 && bsl_size == 1) {
	/* test for HDX compability BSL */
	char bsl_buf[SECTOR_SIZE];
	sread( bsl_buf, bsl_start );
	bsl_HDX_compat = 1;
	for( i = 0; i < SECTOR_SIZE; ++i ) {
	    if (bsl_buf[i] != (i == 3 ? 0xa5 : 0)) {
		bsl_HDX_compat = 0;
		break;
	    }
	}
    }
    
    for( i = 0; i < 4; i++ ) {
	pi = &rs->part[i];
	if (pi->flag & PART_FLAG_VALID) {
	    /* valid partition entry */
	    if (PID_EQ( pi->id, "XGM" )) {
		/* extended part. -> cannot be ICD format */
		xpart_fmt = xfmt_AHDI;
		XGM_flag = pi->flag & ~PART_FLAG_VALID;
		read_extended( pi, &errs );
	    }
	    else {
		/* "normal" partiton */
		if (is_valid_part_entry(pi)) {
		    check_n_partitions();
		    diskpart2PART( pi, 0, &part_table[partitions] );
		    ++partitions;
		}
		else {
		    printf( "Entry #%d in root sector contains "
			    "junk data! Ignored.\n", i );
		    errs += 2;
		}
	    }
	}
    }

    if (xpart_fmt != xfmt_AHDI) {
	/* no extended partitions found -> test for ICD format */
	pi = &rs->icdpart[0];
	/* sanity check: no ICD format if first partion invalid */
	if ((pi->flag & PART_FLAG_VALID) && is_reasonable_PID( pi->id )) {
	    xpart_fmt = xfmt_ICD;
	    for ( ; pi < &rs->icdpart[8]; pi++ ) {
		if ((pi->flag & PART_FLAG_VALID) &&
		    is_reasonable_PID( pi->id )) {
		    if (is_valid_part_entry(pi)) {
			check_n_partitions();
			diskpart2PART( pi, 0, &part_table[partitions] );
			++partitions;
		    }
		    else {
			printf( "ICD entry #%d in root sector contains junk "
				"data! Ignored.\n", pi - &rs->icdpart[0] );
			errs += 2;
		    }
		}
	    }
	}
    }

    if (errs) {
	if (!listing) {
	    printf( "Errors have been found in the partition table.\n" );
	    if (errs > 2)
		printf( "Probably this disk isn't partitioned in an "
			"Atari-compatible way.\n" );
	}
	if (listing || read_yesno( "Assume disk is unpartitioned", -1 )) {
	    hd_size = blk_size;
	    bsl_start = bsl_size = 0;
	    partitions = 0;
	}
    }
}

/* Local Variables: */
/* tab-width: 8     */
/* End:             */