2 * s390-tools/zipl/src/disk.c
3 * Functions to handle disk layout specific operations.
5 * Copyright IBM Corp. 2001, 2009.
7 * Author(s): Carsten Otte <cotte@de.ibm.com>
8 * Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
14 #include <sys/types.h>
16 #include <sys/ioctl.h>
32 #define FIBMAP _IO(0x00,1)
33 #define FIGETBSZ _IO(0x00,2)
34 #define BLKGETSIZE _IO(0x12,96)
35 #define BLKSSZGET _IO(0x12,104)
37 /* from linux/hdregs.h */
38 #define HDIO_GETGEO 0x0301
40 #define DASD_IOCTL_LETTER 'D'
41 #define BIODASDINFO _IOR(DASD_IOCTL_LETTER, 1, \
42 struct dasd_information)
43 #define DASD_PARTN_MASK 0x03
44 #define SCSI_PARTN_MASK 0x0f
46 /* Definitions for dasd device driver, taken from linux/include/asm/dasd.h */
47 struct dasd_information
{
48 unsigned int devno
; /* S/390 devno */
49 unsigned int real_devno
; /* for aliases */
50 unsigned int schid
; /* S/390 subchannel identifier */
51 unsigned int cu_type
: 16; /* from SenseID */
52 unsigned int cu_model
: 8; /* from SenseID */
53 unsigned int dev_type
: 16; /* from SenseID */
54 unsigned int dev_model
: 8; /* from SenseID */
55 unsigned int open_count
;
56 unsigned int req_queue_len
;
57 unsigned int chanq_len
; /* length of chanq */
58 char type
[4]; /* from discipline.name */
59 unsigned int status
; /* current device level */
60 unsigned int label_block
; /* where to find the VOLSER */
61 unsigned int FBA_layout
; /* fixed block size (like AIXVOL) */
62 unsigned int characteristics_size
;
63 unsigned int confdata_size
;
64 char characteristics
[64]; /* from read_device_characteristics */
65 char configuration_data
[256]; /* from read_configuration_data */
69 disk_determine_dasd_type(struct disk_info
*data
,
70 struct dasd_information dasd_info
)
72 if (strncmp(dasd_info
.type
, "FBA ",4) == 0)
73 data
->type
= disk_type_fba
;
74 else if (strncmp(dasd_info
.type
, "DIAG",4) == 0)
75 data
->type
= disk_type_diag
;
76 else if (strncmp(dasd_info
.type
, "ECKD",4) == 0) {
77 if (dasd_info
.FBA_layout
)
78 data
->type
= disk_type_eckd_classic
;
80 data
->type
= disk_type_eckd_compatible
;
82 error_reason("Unknown DASD type");
88 /* Return non-zero for ECKD type. */
90 disk_is_eckd(disk_type_t type
)
92 return (type
== disk_type_eckd_classic
||
93 type
== disk_type_eckd_compatible
);
97 disk_get_info(const char* device
, struct job_target_data
* target
,
98 struct disk_info
** info
)
101 struct stat script_stats
;
102 struct proc_part_entry part_entry
;
103 struct proc_dev_entry dev_entry
;
104 struct dasd_information dasd_info
;
105 struct disk_info
*data
;
109 char *script_pre
= "/lib/s390-tools/zipl_helper.";
110 char script_file
[80];
117 /* Get file information */
118 if (stat(device
, &stats
)) {
119 error_reason(strerror(errno
));
122 /* Open device file */
123 fd
= open(device
, O_RDWR
);
125 error_reason(strerror(errno
));
128 /* Get memory for result */
129 data
= (struct disk_info
*) misc_malloc(sizeof(struct disk_info
));
134 memset((void *) data
, 0, sizeof(struct disk_info
));
135 /* Try to get device driver name */
136 if (proc_dev_get_entry(stats
.st_rdev
, 1, &dev_entry
) == 0) {
137 data
->drv_name
= misc_strdup(dev_entry
.name
);
138 proc_dev_free_entry(&dev_entry
);
140 fprintf(stderr
, "Warning: Could not determine driver name for "
141 "major %d from /proc/devices\n", major(stats
.st_rdev
));
142 fprintf(stderr
, "Warning: Preparing a logical device for boot "
145 data
->source
= source_user
;
146 /* Check if targetbase script is available */
147 strcpy(script_file
, script_pre
);
148 if (data
->drv_name
) {
149 strcat(script_file
, data
->drv_name
);
151 if ((target
->targetbase
== NULL
) &&
152 (!stat(script_file
, &script_stats
))) {
153 data
->source
= source_script
;
154 /* Run targetbase script */
155 strcpy(ppn_cmd
, script_file
);
156 strcat(ppn_cmd
, " ");
157 strcat(ppn_cmd
, target
->bootmap_dir
);
158 printf("Run %s\n", ppn_cmd
);
159 fh
= popen(ppn_cmd
, "r");
161 error_reason("Failed to run popen(%s,\"r\",)");
165 while (fgets(buffer
, 80, fh
) != NULL
) {
166 if (sscanf(buffer
, "targetbase=%s", value
) == 1) {
167 target
->targetbase
= misc_strdup(value
);
170 if (sscanf(buffer
, "targettype=%s", value
) == 1) {
171 type_from_target(value
, &target
->targettype
);
174 if (sscanf(buffer
, "targetgeometry=%s", value
) == 1) {
175 target
->targetcylinders
=
176 atoi(strtok(value
, ","));
177 target
->targetheads
= atoi(strtok(NULL
, ","));
178 target
->targetsectors
= atoi(strtok(NULL
, ","));
181 if (sscanf(buffer
, "targetblocksize=%s", value
) == 1) {
182 target
->targetblocksize
= atoi(value
);
185 if (sscanf(buffer
, "targetoffset=%s", value
) == 1) {
186 target
->targetoffset
= atol(value
);
190 if (pclose(fh
) == -1) {
191 error_reason("Failed to run pclose");
194 if ((!disk_is_eckd(target
->targettype
) && checkparm
< 4) ||
195 (disk_is_eckd(target
->targettype
) && checkparm
!= 5)) {
196 error_reason("Target parameters missing from script");
201 /* Get disk geometry. Note: geo.start contains a sector number
202 * offset measured in physical blocks, not sectors (512 bytes) */
203 if (target
->targetbase
!= NULL
) {
204 data
->geo
.heads
= target
->targetheads
;
205 data
->geo
.sectors
= target
->targetsectors
;
206 data
->geo
.cylinders
= target
->targetcylinders
;
207 data
->geo
.start
= target
->targetoffset
;
209 data
->source
= source_auto
;
210 if (ioctl(fd
, HDIO_GETGEO
, &data
->geo
)) {
211 error_reason("Could not get disk geometry");
215 if ((data
->source
== source_user
) || (data
->source
== source_script
)) {
217 data
->phy_block_size
= target
->targetblocksize
;
219 /* Get DASD information */
220 if (ioctl(fd
, BIODASDINFO
, &dasd_info
))
223 data
->devno
= dasd_info
.devno
;
224 /* Get physical block size */
225 if (ioctl(fd
, BLKSSZGET
, &data
->phy_block_size
)) {
226 error_reason("Could not get blocksize");
230 /* Get size of device in sectors (512 byte) */
231 if (ioctl(fd
, BLKGETSIZE
, &devsize
)) {
232 error_reason("Could not get device size");
235 if ((data
->source
== source_user
) || (data
->source
== source_script
)) {
236 data
->type
= target
->targettype
;
238 /* Get file information */
239 if (sscanf(target
->targetbase
, "%d:%d", &majnum
, &minnum
) == 2)
240 data
->device
= makedev(majnum
, minnum
);
242 if (stat(target
->targetbase
, &stats
)) {
243 error_reason(strerror(errno
));
246 if (!S_ISBLK(stats
.st_mode
)) {
247 error_reason("Target base device '%s' is not "
252 data
->device
= stats
.st_rdev
;
254 goto type_determined
;
256 /* Determine disk type */
257 if (!data
->drv_name
) {
258 /* Driver name cannot be read */
259 if (data
->devno
== -1) {
260 if (data
->geo
.start
) {
262 data
->type
= disk_type_scsi
;
263 data
->partnum
= stats
.st_rdev
& SCSI_PARTN_MASK
;
264 data
->device
= stats
.st_rdev
& ~SCSI_PARTN_MASK
;
267 data
->type
= disk_type_scsi
;
269 data
->device
= stats
.st_rdev
;
273 if (disk_determine_dasd_type(data
, dasd_info
))
275 data
->partnum
= stats
.st_rdev
& DASD_PARTN_MASK
;
276 data
->device
= stats
.st_rdev
& ~DASD_PARTN_MASK
;
278 } else if (strcmp(data
->drv_name
, "dasd") == 0) {
279 /* Driver name is 'dasd' */
280 if (data
->devno
== -1) {
281 error_reason("Could not determine DASD type");
284 if (disk_determine_dasd_type(data
, dasd_info
))
286 data
->partnum
= stats
.st_rdev
& DASD_PARTN_MASK
;
287 data
->device
= stats
.st_rdev
& ~DASD_PARTN_MASK
;
288 } else if (strcmp(data
->drv_name
, "sd") == 0 ||
289 strcmp(data
->drv_name
, "virtblk") == 0) {
290 /* Driver name is 'sd' or 'virtblk' */
291 if (data
->devno
!= -1) {
292 error_reason("Unsupported device driver '%s' "
293 "for disk type DASD", data
->drv_name
);
296 data
->type
= disk_type_scsi
;
297 data
->partnum
= stats
.st_rdev
& SCSI_PARTN_MASK
;
298 data
->device
= stats
.st_rdev
& ~SCSI_PARTN_MASK
;
300 /* Driver name is unknown */
301 error_reason("Unsupported device driver '%s'", data
->drv_name
);
306 /* Check for valid CHS geometry data. */
307 if (disk_is_eckd(data
->type
) && (data
->geo
.cylinders
== 0 ||
308 data
->geo
.heads
== 0 || data
->geo
.sectors
== 0)) {
309 error_reason("Invalid disk geometry (CHS=%d/%d/%d)",
310 data
->geo
.cylinders
, data
->geo
.heads
,
314 /* Convert device size to size in physical blocks */
315 data
->phy_blocks
= devsize
/ (data
->phy_block_size
/ 512);
316 if (data
->partnum
!= 0)
317 data
->partition
= stats
.st_rdev
;
318 /* Try to get device name */
319 if (proc_part_get_entry(data
->device
, &part_entry
) == 0) {
320 data
->name
= misc_strdup(part_entry
.name
);
321 proc_part_free_entry(&part_entry
);
322 if (data
->name
== NULL
)
325 /* There is no easy way to find out whether there is a file system
326 * on this device, so we set the respective block size to an invalid
328 data
->fs_block_size
= -1;
341 disk_get_info_from_file(const char* filename
, struct job_target_data
* target
,
342 struct disk_info
** info
)
350 if (stat(filename
, &stats
)) {
351 error_reason(strerror(errno
));
354 /* Retrieve file system block size */
355 fd
= open(filename
, O_RDONLY
);
357 error_reason(strerror(errno
));
360 rc
= ioctl(fd
, FIGETBSZ
, &blocksize
);
363 error_reason("Could not get file system block size for '%s'",
367 /* Create temporary device file */
368 rc
= misc_temp_dev(stats
.st_dev
, 1, &device
);
371 /* Get device info */
372 rc
= disk_get_info(device
, target
, info
);
374 (*info
)->fs_block_size
= blocksize
;
376 misc_free_temp_dev(device
);
382 disk_free_info(struct disk_info
* info
)
387 free(info
->drv_name
);
392 #ifndef REISERFS_SUPER_MAGIC
393 #define REISERFS_SUPER_MAGIC 0x52654973
394 #endif /* not REISERFS_SUPER_MAGIC */
396 #ifndef REISERFS_IOC_UNPACK
397 #define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
398 #endif /* not REISERFS_IOC_UNPACK */
400 /* Retrieve the physical blocknumber (block on disk) of the specified logical
401 * block (block in file). FD provides the file descriptor, LOGICAL is the
402 * logical block number. Upon success, return 0 and store the physical
403 * blocknumber in the variable pointed to by PHYSICAL. Return non-zero
406 disk_get_blocknum(int fd
, blocknum_t logical
, blocknum_t
* physical
,
407 struct disk_info
* info
)
410 blocknum_t phy_per_fs
;
414 /* Get file system type */
415 if (fstatfs(fd
, &buf
)) {
416 error_reason(strerror(errno
));
419 /* Files on ReiserFS need unpacking */
420 if (buf
.f_type
== REISERFS_SUPER_MAGIC
) {
421 if (ioctl(fd
, REISERFS_IOC_UNPACK
, 1)) {
422 error_reason("Could not unpack ReiserFS file");
426 /* Get mapping in file system blocks */
427 phy_per_fs
= info
->fs_block_size
/ info
->phy_block_size
;
428 mapped
= logical
/ phy_per_fs
;
429 subblock
= logical
% phy_per_fs
;
430 if (ioctl(fd
, FIBMAP
, &mapped
)) {
431 error_reason("Could not get file mapping");
435 /* This is a hole in the file */
438 /* Convert file system block to physical */
439 *physical
= mapped
* phy_per_fs
+ subblock
;
440 /* Add partition start */
441 *physical
+= info
->geo
.start
;
447 /* Return the cylinder on which the block number BLOCKNUM is stored on the
448 * CHS device identified by INFO. */
450 disk_cyl_from_blocknum(blocknum_t blocknum
, struct disk_info
* info
)
452 return blocknum
/ (info
->geo
.heads
* info
->geo
.sectors
);
456 /* Return the head on which the block number BLOCKNUM is stored on the
457 * CHS device identified by INFO. */
459 disk_head_from_blocknum(blocknum_t blocknum
, struct disk_info
* info
)
461 return (blocknum
/ info
->geo
.sectors
) % info
->geo
.heads
;
465 /* Return the sector on which the block number BLOCKNUM is stored on the
466 * CHS device identified by INFO. */
468 disk_sec_from_blocknum(blocknum_t blocknum
, struct disk_info
* info
)
470 return blocknum
% info
->geo
.sectors
+ 1;
474 /* Create a block pointer in memory at location PTR which represents the
475 * given blocknumber BLOCKNUM. INFO provides information about the disk
478 disk_blockptr_from_blocknum(disk_blockptr_t
* ptr
, blocknum_t blocknum
,
479 struct disk_info
* info
)
481 switch (info
->type
) {
485 ptr
->linear
.block
= blocknum
;
486 ptr
->linear
.size
= info
->phy_block_size
;
487 ptr
->linear
.blockct
= 0;
489 case disk_type_eckd_classic
:
490 case disk_type_eckd_compatible
:
492 /* Special case: zero blocknum will be expanded to
493 * size * (blockct+1) bytes of zeroes. */
499 ptr
->chs
.cyl
= disk_cyl_from_blocknum(blocknum
, info
);
500 ptr
->chs
.head
= disk_head_from_blocknum(blocknum
,
502 ptr
->chs
.sec
= disk_sec_from_blocknum(blocknum
, info
);
504 ptr
->chs
.size
= info
->phy_block_size
;
505 ptr
->chs
.blockct
= 0;
511 /* Write BYTECOUNT bytes of data from memory at location DATA as a block to
512 * the file identified by file descriptor FD. Make sure that the data is
513 * aligned on a block size boundary and that at most INFO->PHY_BLOCK_SIZE
514 * bytes are written. INFO provides information about the disk layout. Upon
515 * success, return 0 and store the pointer to the resulting disk block to BLOCK
516 * (if BLOCK is not NULL). Return non-zero otherwise. */
518 disk_write_block_aligned(int fd
, const void* data
, size_t bytecount
,
519 disk_blockptr_t
* block
, struct disk_info
* info
)
521 blocknum_t current_block
;
526 current_pos
= lseek(fd
, 0, SEEK_CUR
);
527 if (current_pos
== -1) {
528 error_text(strerror(errno
));
531 /* Ensure block alignment of current file pos */
532 align
= info
->phy_block_size
;
533 if (current_pos
% align
!= 0) {
534 current_pos
= lseek(fd
, align
- current_pos
% align
, SEEK_CUR
);
535 if (current_pos
== -1) {
536 error_text(strerror(errno
));
540 current_block
= current_pos
/ align
;
541 /* Ensure maximum size */
542 if (bytecount
> (size_t) align
)
544 /* Write data block */
545 if (misc_write(fd
, data
, bytecount
))
548 /* Store block pointer */
549 if (disk_get_blocknum(fd
, current_block
, &blocknum
, info
))
551 disk_blockptr_from_blocknum(block
, blocknum
, info
);
557 /* Write BYTECOUNT bytes from memory at location BUFFER to the file identified
558 * by file descriptor FD and return the list of pointers to the disk blocks
559 * that make up the respective part of the file. Upon success return the number
560 * of blocks and set BLOCKLIST to point to the uncompressed list. Return zero
561 * otherwise. Note that the data is written to a file position which is aligned
562 * on a block size boundary. */
564 disk_write_block_buffer(int fd
, const void* buffer
, size_t bytecount
,
565 disk_blockptr_t
** blocklist
,
566 struct disk_info
* info
)
568 disk_blockptr_t
* list
;
575 count
= (bytecount
+ info
->phy_block_size
- 1) / info
->phy_block_size
;
576 list
= (disk_blockptr_t
*) misc_malloc(sizeof(disk_blockptr_t
) *
582 memset((void *) list
, 0, sizeof(disk_blockptr_t
) * count
);
584 for (i
=0, written
=0; i
< count
; i
++, written
+= chunk_size
) {
585 chunk_size
= bytecount
- written
;
586 if (chunk_size
> (size_t) info
->phy_block_size
)
587 chunk_size
= info
->phy_block_size
;
588 rc
= disk_write_block_aligned(fd
, VOID_ADD(buffer
, written
),
601 /* Print device node. */
603 disk_print_devt(dev_t d
)
605 printf("%02x:%02x", major(d
), minor(d
));
609 /* Return a name for a given disk TYPE. */
611 disk_get_type_name(disk_type_t type
)
615 return "SCSI disk layout";
617 return "FBA disk layout";
619 return "DIAG disk layout";
620 case disk_type_eckd_classic
:
621 return "ECKD/linux disk layout";
622 case disk_type_eckd_compatible
:
623 return "ECKD/compatible disk layout";
625 return "Unknown disk type";
630 /* Return non-zero for ECKD large volumes. */
632 disk_is_large_volume(struct disk_info
* info
)
634 return (info
->type
== disk_type_eckd_classic
||
635 info
->type
== disk_type_eckd_compatible
) &&
636 info
->geo
.cylinders
== 0xfffe;
640 /* Print textual representation of INFO contents. */
642 disk_print_info(struct disk_info
* info
)
644 char footnote
[4] = "";
645 if ((info
->source
== source_user
) || (info
->source
== source_script
))
646 strcpy(footnote
, " *)");
648 printf(" Device..........................: ");
649 disk_print_devt(info
->device
);
651 if (info
->partnum
!= 0) {
652 printf(" Partition.......................: ");
653 disk_print_devt(info
->partition
);
657 printf(" Device name.....................: %s%s\n",
658 info
->name
, footnote
);
660 if (info
->drv_name
) {
661 printf(" Device driver name..............: %s\n",
664 if (((info
->type
== disk_type_fba
) ||
665 (info
->type
== disk_type_diag
) ||
666 (info
->type
== disk_type_eckd_classic
) ||
667 (info
->type
== disk_type_eckd_compatible
)) &&
668 (info
->source
== source_auto
)) {
669 printf(" DASD device number..............: %04x\n",
672 printf(" Type............................: disk %s\n",
673 (info
->partnum
!= 0) ? "partition" : "device");
674 printf(" Disk layout.....................: %s%s\n",
675 disk_get_type_name(info
->type
), footnote
);
676 printf(" Geometry - heads................: %d%s\n",
677 info
->geo
.heads
, footnote
);
678 printf(" Geometry - sectors..............: %d%s\n",
679 info
->geo
.sectors
, footnote
);
680 if (disk_is_large_volume(info
)) {
681 /* ECKD large volume. There is not enough information
682 * available in INFO to calculate disk cylinder size. */
683 printf(" Geometry - cylinders............: > 65534\n");
685 printf(" Geometry - cylinders............: %d%s\n",
686 info
->geo
.cylinders
, footnote
);
688 printf(" Geometry - start................: %ld%s\n",
689 info
->geo
.start
, footnote
);
690 if (info
->fs_block_size
>= 0)
691 printf(" File system block size..........: %d\n",
692 info
->fs_block_size
);
693 printf(" Physical block size.............: %d%s\n",
694 info
->phy_block_size
, footnote
);
695 printf(" Device size in physical blocks..: %ld\n",
696 (long) info
->phy_blocks
);
697 if (info
->source
== source_user
)
698 printf(" *) Data provided by user.\n");
699 if (info
->source
== source_script
)
700 printf(" *) Data provided by script.\n");
704 /* Check whether a block is a zero block which identifies a hole in a file.
705 * Return non-zero if BLOCK is a zero block, 0 otherwise. */
707 disk_is_zero_block(disk_blockptr_t
* block
, struct disk_info
* info
)
709 switch (info
->type
) {
712 return block
->linear
.block
== 0;
713 case disk_type_eckd_classic
:
714 case disk_type_eckd_compatible
:
715 return (block
->chs
.cyl
== 0) && (block
->chs
.head
== 0) &&
716 (block
->chs
.sec
== 0);
724 #define DASD_MAX_LINK_COUNT 255
725 #define SCSI_MAX_LINK_COUNT 65535
727 /* Check whether two block pointers FIRST and SECOND can be merged into
728 * one block pointer by increasing the block count field of the first
729 * pointer. INFO provides information about the disk type. Return non-zero if
730 * blocks can be merged, 0 otherwise. */
732 can_merge_blocks(disk_blockptr_t
* first
, disk_blockptr_t
* second
,
733 struct disk_info
* info
)
737 /* Zero blocks can never be merged */
738 if (disk_is_zero_block(first
, info
) || disk_is_zero_block(second
, info
))
740 if (info
->type
== disk_type_scsi
)
741 max_count
= SCSI_MAX_LINK_COUNT
;
743 max_count
= DASD_MAX_LINK_COUNT
;
744 switch (info
->type
) {
747 /* Check link count limits */
748 if (((int) first
->linear
.blockct
) +
749 ((int) second
->linear
.blockct
) + 1 > max_count
)
751 if (first
->linear
.block
+ first
->linear
.blockct
+ 1 ==
752 second
->linear
.block
)
755 case disk_type_eckd_classic
:
756 case disk_type_eckd_compatible
:
757 /* Check link count limits */
758 if (((int) first
->chs
.blockct
) +
759 ((int) second
->chs
.blockct
) + 1 > max_count
)
761 if ((first
->chs
.cyl
== second
->chs
.cyl
) &&
762 (first
->chs
.head
== second
->chs
.head
) &&
763 (first
->chs
.sec
+ first
->chs
.blockct
+ 1 ==
774 /* Merge two block pointers FIRST and SECOND into one pointer. The resulting
775 * pointer is stored in FIRST. INFO provides information about the disk
778 merge_blocks(disk_blockptr_t
* first
, disk_blockptr_t
* second
,
779 struct disk_info
* info
)
781 switch (info
->type
) {
784 first
->linear
.blockct
+= second
->linear
.blockct
+ 1;
786 case disk_type_eckd_classic
:
787 case disk_type_eckd_compatible
:
788 first
->chs
.blockct
+= second
->chs
.blockct
+ 1;
791 /* Should not happen */
797 /* Analyze COUNT elements in LIST and try to merge pointers to adjacent
798 * blocks. INFO provides information about the disk type. Return the new
799 * number of elements in the list. */
801 disk_compact_blocklist(disk_blockptr_t
* list
, blocknum_t count
,
802 struct disk_info
* info
)
809 for (i
=1, last
=0; i
< count
; i
++) {
810 if (can_merge_blocks(&list
[last
], &list
[i
], info
)) {
811 merge_blocks(&list
[last
], &list
[i
], info
);
813 list
[++last
] = list
[i
];
820 /* Retrieve a list of pointers to the disk blocks that make up the file
821 * specified by FILENAME. Upon success, return the number of blocks and set
822 * BLOCKLIST to point to the uncompacted list. INFO provides information
823 * about the device which contains the file. Return zero otherwise. */
825 disk_get_blocklist_from_file(const char* filename
, disk_blockptr_t
** blocklist
,
826 struct disk_info
* info
)
828 disk_blockptr_t
* list
;
835 fd
= open(filename
, O_RDONLY
);
837 error_reason(strerror(errno
));
838 error_text("Could not open file '%s'", filename
);
841 if (fstat(fd
, &stats
)) {
842 error_reason(strerror(errno
));
843 error_text("Could not get information for file '%s'",
848 /* Get number of blocks */
849 count
= ((blocknum_t
) stats
.st_size
+
850 info
->phy_block_size
- 1) / info
->phy_block_size
;
852 error_reason("Could not read empty file '%s'", filename
);
856 list
= (disk_blockptr_t
*) misc_malloc(sizeof(disk_blockptr_t
) *
862 memset((void *) list
, 0, sizeof(disk_blockptr_t
) * count
);
864 for (i
=0; i
< count
; i
++) {
865 if (disk_get_blocknum(fd
, i
, &blocknum
, info
)) {
870 disk_blockptr_from_blocknum(&list
[i
], blocknum
, info
);
877 /* Check whether input device is in subchannel set 0.
878 * Path to "dev" attribute containing the major/minor number depends on
879 * whether option CONFIG_SYSFS_DEPRECATED is set or not */
881 int disk_check_subchannel_set(int devno
, dev_t device
, char* dev_name
)
883 struct dirent
*direntp
;
885 static const char sys_bus_ccw_dev_filename
[] = "/sys/bus/ccw/devices";
886 char dev_file
[PATH_MAX
];
890 snprintf(dev_file
, PATH_MAX
, "%s/0.0.%04x", sys_bus_ccw_dev_filename
,
892 fdd
= opendir(dev_file
);
894 goto out_with_warning
;
895 while ((direntp
= readdir(fdd
)))
896 if (strncmp(direntp
->d_name
, "block:", 6) == 0)
899 snprintf(dev_file
, PATH_MAX
, "%s/0.0.%04x/%s/dev",
900 sys_bus_ccw_dev_filename
, devno
, direntp
->d_name
);
903 snprintf(dev_file
, PATH_MAX
, "%s/0.0.%04x/block",
904 sys_bus_ccw_dev_filename
, devno
);
905 fdd
= opendir(dev_file
);
907 goto out_with_warning
;
908 while ((direntp
= readdir(fdd
)))
909 if (strncmp(direntp
->d_name
, "dasd", 4) == 0)
912 goto out_with_warning
;
913 snprintf(dev_file
, PATH_MAX
, "%s/0.0.%04x/block/%s/dev",
914 sys_bus_ccw_dev_filename
, devno
, direntp
->d_name
);
917 if (misc_read_special_file(dev_file
, &buffer
, NULL
, 1))
918 goto out_with_warning
;
919 if (sscanf(buffer
, "%i:%i", &major
, &minor
) != 2) {
921 goto out_with_warning
;
924 if (makedev(major
, minor
) != device
) {
925 error_reason("Dump target '%s' must belong to "
926 "subchannel set 0.", dev_name
);
931 fprintf(stderr
, "Warning: Could not determine whether dump target %s "
932 "belongs to subchannel set 0.\n", dev_name
);