Files
s390-tools/cmsfs-fuse/dasd.c
Michael Holzheu b627b8d8e1 Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-08-21 10:55:40 +02:00

181 lines
4.0 KiB
C

/*
* cmsfs-fuse - CMS EDF filesystem support for Linux
*
* DASD specific functions
*
* Copyright IBM Corp. 2010, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "cmsfs-fuse.h"
#include "edf.h"
#include "helper.h"
#define BLKSSZGET _IO(0x12, 104)
/* CMS disk label starts with ASCII string "CMS1" */
#define VOL_LABEL_EBCDIC 0xc3d4e2f1
static int disk_supported(int fd, struct cmsfs *cmsfs)
{
unsigned int cms_id = VOL_LABEL_EBCDIC;
struct cms_label label;
int rc;
rc = lseek(fd, cmsfs->label, SEEK_SET);
if (rc < 0) {
perror(COMP "lseek failed");
return 0;
}
rc = read(fd, &label, sizeof(label));
if (rc < 0) {
perror(COMP "read failed");
return 0;
}
/* check that the label contains the CMS1 string */
if (memcmp(label.id, &cms_id, sizeof(cms_id)) != 0)
return 0;
/* label sanity checks */
if (label.blocksize != 4096 &&
label.blocksize != 2048 &&
label.blocksize != 1024 &&
label.blocksize != 512) {
fprintf(stderr, COMP "Invalid disk block size!\n");
return 0;
}
if (label.dop != 4 && label.dop != 5) {
fprintf(stderr, COMP "Invalid disk origin pointer!\n");
return 0;
}
if (label.fst_entry_size != sizeof(struct fst_entry)) {
fprintf(stderr, COMP "Invalid FST entry size!\n");
return 0;
}
if (label.fst_per_block != label.blocksize / label.fst_entry_size) {
fprintf(stderr, COMP "Invalid FST per block value!\n");
return 0;
}
/* set the blocksize to the formatted one */
cmsfs->blksize = label.blocksize;
DEBUG(" DOP: %d", label.dop);
/* block number 5 means 0x4000... */
cmsfs->fdir = (label.dop - 1) * cmsfs->blksize;
DEBUG(" fdir: %lx", cmsfs->fdir);
/* get disk usage for statfs */
cmsfs->total_blocks = label.total_blocks;
cmsfs->used_blocks = label.used_blocks;
DEBUG(" Total blocks: %d Used blocks: %d",
cmsfs->total_blocks, cmsfs->used_blocks);
return 1;
}
static void get_device_info_ioctl(int fd, struct cmsfs *cmsfs)
{
if (ioctl(fd, BLKSSZGET, &cmsfs->blksize) != 0)
DIE("ioctl error get blocksize\n");
}
static int label_offsets[] = { 4096, 512, 2048, 1024, 8192 };
static void get_device_info_file(int fd, struct cmsfs *cmsfs)
{
unsigned int cms_id = VOL_LABEL_EBCDIC;
unsigned int i;
char label[4];
off_t offset;
int rc;
cmsfs->label = 0;
/*
* Read the blocksize from label. Unfortunately the blocksize
* position depends on the blocksize... time for some heuristics.
*/
for (i = 0; i < ARRAY_SIZE(label_offsets); i++) {
offset = label_offsets[i];
rc = lseek(fd, offset, SEEK_SET);
if (rc < 0)
DIE_PERROR("lseek failed");
rc = read(fd, &label, 4);
if (rc < 0)
DIE_PERROR("read failed");
/* check if the label contains the CMS1 string */
if (memcmp(label, &cms_id, sizeof(cms_id)) == 0) {
cmsfs->label = offset;
break;
}
}
if (!cmsfs->label)
DIE("Error CMS1 label not found!\n");
}
int get_device_info(struct cmsfs *cmsfs)
{
struct stat stat;
int fd;
/*
* Open writable, if write access is not granted fall back to
* read only.
*/
fd = open(cmsfs->device, O_RDWR);
if (fd < 0) {
if (errno == EROFS || errno == EACCES) {
cmsfs->readonly = 1;
fd = open(cmsfs->device, O_RDONLY);
if (fd < 0)
DIE_PERROR("open failed");
} else
DIE_PERROR("open failed");
}
if (fstat(fd, &stat) < 0)
DIE_PERROR("fstat failed");
if (S_ISBLK(stat.st_mode)) {
get_device_info_ioctl(fd, cmsfs);
cmsfs->label = 2 * cmsfs->blksize;
/* FBA disks have a different label location */
if (!disk_supported(fd, cmsfs)) {
cmsfs->label = cmsfs->blksize;
if (!disk_supported(fd, cmsfs))
goto error;
}
} else if (S_ISREG(stat.st_mode))
get_device_info_file(fd, cmsfs);
else
goto error;
if (!disk_supported(fd, cmsfs))
goto error;
return fd;
error:
DIE("Unsupported disk\n");
}