This patch just removes trailing whitespace. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
963 lines
20 KiB
C
963 lines
20 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include "misc.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <mntent.h>
|
|
#include <sys/vfs.h>
|
|
#include <time.h>
|
|
#include <utime.h>
|
|
#include <ctype.h>
|
|
#include <linux/hdreg.h>
|
|
#include <dirent.h>
|
|
#include <assert.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <signal.h>
|
|
|
|
/* Debian modifications by Ed Boraas <ed@debian.org> */
|
|
#include <sys/mount.h>
|
|
/* End Debian mods */
|
|
|
|
#define STAT_FIELD(Field, Type) \
|
|
inline Type misc_device_##Field(char *device) { \
|
|
struct stat st; \
|
|
\
|
|
if (stat(device, &st) == 0) \
|
|
return st.st_##Field; \
|
|
\
|
|
fprintf(stderr, "Stat of the device '%s' failed.", device); \
|
|
exit(8); \
|
|
}
|
|
|
|
STAT_FIELD(mode, mode_t);
|
|
STAT_FIELD(rdev, dev_t);
|
|
STAT_FIELD(size, off_t);
|
|
STAT_FIELD(blocks, blkcnt_t);
|
|
|
|
void die(char *fmt, ...)
|
|
{
|
|
static char buf[1024];
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vsprintf(buf, fmt, args);
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n%s\n", buf);
|
|
abort();
|
|
}
|
|
|
|
#define MEM_BEGIN "_mem_begin_"
|
|
#define MEM_END "mem_end"
|
|
#define MEM_FREED "__free_"
|
|
#define CONTROL_SIZE (strlen (MEM_BEGIN) + 1 + sizeof (int) + strlen (MEM_END) + 1)
|
|
|
|
unsigned int get_mem_size(char *p)
|
|
{
|
|
char *begin;
|
|
|
|
begin = p - strlen(MEM_BEGIN) - 1 - sizeof(int);
|
|
return *(int *)(begin + strlen(MEM_BEGIN) + 1);
|
|
}
|
|
|
|
void checkmem(char *p, int size)
|
|
{
|
|
char *begin;
|
|
char *end;
|
|
|
|
begin = p - strlen(MEM_BEGIN) - 1 - sizeof(int);
|
|
if (strcmp(begin, MEM_BEGIN))
|
|
die("checkmem: memory corrupted - invalid head sign");
|
|
|
|
if (*(int *)(begin + strlen(MEM_BEGIN) + 1) != size)
|
|
die("checkmem: memory corrupted - invalid size");
|
|
|
|
end = begin + size + CONTROL_SIZE - strlen(MEM_END) - 1;
|
|
if (strcmp(end, MEM_END))
|
|
die("checkmem: memory corrupted - invalid end sign");
|
|
}
|
|
|
|
void *getmem(int size)
|
|
{
|
|
char *mem;
|
|
|
|
if ((mem = mem_alloc(size)) == NULL)
|
|
die("getmem: no more memory (%d)", size);
|
|
|
|
memset(mem, 0, size);
|
|
// checkmem (mem, size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
void *mem_alloc(int size)
|
|
{
|
|
char *p;
|
|
char *mem;
|
|
|
|
p = (char *)malloc(CONTROL_SIZE + size);
|
|
if (!p)
|
|
die("getmem: no more memory (%d)", size);
|
|
|
|
/* Write the MEM_BEGIN magic in the beginning of allocated memory. */
|
|
strcpy(p, MEM_BEGIN);
|
|
p += strlen(MEM_BEGIN) + 1;
|
|
/* Write the size after the magic. */
|
|
*(int *)p = size;
|
|
p += sizeof(int);
|
|
mem = p;
|
|
p += size;
|
|
strcpy(p, MEM_END);
|
|
|
|
return mem;
|
|
}
|
|
|
|
void *expandmem(void *vp, int size, int by)
|
|
{
|
|
int allocated;
|
|
char *mem, *p = vp;
|
|
int expand_by = by;
|
|
|
|
if (p) {
|
|
checkmem(p, size);
|
|
allocated = CONTROL_SIZE + size;
|
|
p -= (strlen(MEM_BEGIN) + 1 + sizeof(int));
|
|
} else {
|
|
allocated = 0;
|
|
/* add control bytes to the new allocated area */
|
|
expand_by += CONTROL_SIZE;
|
|
}
|
|
p = realloc(p, allocated + expand_by);
|
|
if (!p)
|
|
die("expandmem: no more memory (%d)", size);
|
|
if (!vp) {
|
|
strcpy(p, MEM_BEGIN);
|
|
}
|
|
mem = p + strlen(MEM_BEGIN) + 1 + sizeof(int);
|
|
|
|
*(int *)(p + strlen(MEM_BEGIN) + 1) = size + by;
|
|
/* fill new allocated area by 0s */
|
|
if (by > 0)
|
|
memset(mem + size, 0, by);
|
|
strcpy(mem + size + by, MEM_END);
|
|
// checkmem (mem, size + by);
|
|
|
|
return mem;
|
|
}
|
|
|
|
void freemem(void *vp)
|
|
{
|
|
char *p = vp;
|
|
int size;
|
|
|
|
if (!p)
|
|
return;
|
|
size = get_mem_size(vp);
|
|
checkmem(p, size);
|
|
|
|
p -= (strlen(MEM_BEGIN) + 1 + sizeof(int));
|
|
strcpy(p, MEM_FREED);
|
|
strcpy(p + size + CONTROL_SIZE - strlen(MEM_END) - 1, MEM_FREED);
|
|
free(p);
|
|
}
|
|
|
|
typedef int (*func_t) (char *);
|
|
|
|
/* Lookup the @file in the @mntfile. @file is mntent.mnt_fsname if @fsname
|
|
is set; mntent.mnt_dir otherwise. Return the mnt entry from the @mntfile.
|
|
|
|
Warning: if the root fs is mounted RO, the content of /etc/mtab may be
|
|
not correct. */
|
|
static struct mntent *misc_mntent_lookup(char *mntfile, char *file, int path)
|
|
{
|
|
struct mntent *mnt;
|
|
int name_match = 0;
|
|
struct stat st;
|
|
dev_t rdev = 0;
|
|
dev_t dev = 0;
|
|
ino_t ino = 0;
|
|
char *name;
|
|
FILE *fp;
|
|
|
|
assert(mntfile != NULL);
|
|
assert(file != NULL);
|
|
|
|
if (stat(file, &st) == 0) {
|
|
/* Devices is stated. */
|
|
if (S_ISBLK(st.st_mode)) {
|
|
rdev = st.st_rdev;
|
|
} else {
|
|
dev = st.st_dev;
|
|
ino = st.st_ino;
|
|
}
|
|
}
|
|
|
|
if ((fp = setmntent(mntfile, "r")) == NULL)
|
|
return INVAL_PTR;
|
|
|
|
while ((mnt = getmntent(fp)) != NULL) {
|
|
/* Check if names match. */
|
|
name = path ? mnt->mnt_dir : mnt->mnt_fsname;
|
|
|
|
if (strcmp(file, name) == 0)
|
|
name_match = 1;
|
|
|
|
if (stat(name, &st))
|
|
continue;
|
|
|
|
/* If names do not match, check if stats match. */
|
|
if (!name_match) {
|
|
if (rdev && S_ISBLK(st.st_mode)) {
|
|
if (rdev != st.st_rdev)
|
|
continue;
|
|
} else if (dev && !S_ISBLK(st.st_mode)) {
|
|
if (dev != st.st_dev || ino != st.st_ino)
|
|
continue;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* If not path and not block device do not check anything more. */
|
|
if (!path && !rdev)
|
|
break;
|
|
|
|
if (path) {
|
|
/* Either names or stats match. Make sure the st_dev of
|
|
the path is same as @mnt_fsname device rdev. */
|
|
if (stat(mnt->mnt_fsname, &st) == 0 &&
|
|
dev == st.st_rdev)
|
|
break;
|
|
} else {
|
|
/* Either names or stats match. Make sure the st_dev of
|
|
the mount entry is same as the given device rdev. */
|
|
if (stat(mnt->mnt_dir, &st) == 0 && rdev == st.st_dev)
|
|
break;
|
|
}
|
|
}
|
|
|
|
endmntent(fp);
|
|
return mnt;
|
|
}
|
|
|
|
static int misc_root_mounted(char *device)
|
|
{
|
|
struct stat rootst, devst;
|
|
|
|
assert(device != NULL);
|
|
|
|
if (stat("/", &rootst) != 0)
|
|
return -1;
|
|
|
|
if (stat(device, &devst) != 0)
|
|
return -1;
|
|
|
|
if (!S_ISBLK(devst.st_mode) || devst.st_rdev != rootst.st_dev)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int misc_file_ro(char *file)
|
|
{
|
|
if (utime(file, 0) == -1) {
|
|
if (errno == EROFS)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct mntent *misc_mntent(char *device)
|
|
{
|
|
int proc = 0, path = 0, root = 0;
|
|
|
|
struct mntent *mnt;
|
|
struct statfs stfs;
|
|
|
|
assert(device != NULL);
|
|
|
|
/* Check if the root. */
|
|
if (misc_root_mounted(device) == 1)
|
|
root = 1;
|
|
|
|
#ifdef __linux__
|
|
/* Check if /proc is procfs. */
|
|
if (statfs("/proc", &stfs) == 0 && stfs.f_type == 0x9fa0) {
|
|
proc = 1;
|
|
|
|
if (root) {
|
|
/* Lookup the "/" entry in /proc/mounts. Special
|
|
case as root entry can present as:
|
|
rootfs / rootfs rw 0 0
|
|
Look up the mount point in this case. */
|
|
mnt = misc_mntent_lookup("/proc/mounts", "/", 1);
|
|
} else {
|
|
/* Lookup the @device /proc/mounts */
|
|
mnt = misc_mntent_lookup("/proc/mounts", device, 0);
|
|
}
|
|
|
|
if (mnt == INVAL_PTR)
|
|
proc = 0;
|
|
else if (mnt)
|
|
return mnt;
|
|
}
|
|
#endif /* __linux__ */
|
|
|
|
#if defined(MOUNTED) || defined(_PATH_MOUNTED)
|
|
|
|
#ifndef MOUNTED
|
|
#define MOUNTED _PATH_MOUNTED
|
|
#endif
|
|
/* Check in MOUNTED (/etc/mtab) if RW. */
|
|
if (!misc_file_ro(MOUNTED)) {
|
|
path = 1;
|
|
|
|
if (root) {
|
|
mnt = misc_mntent_lookup(MOUNTED, "/", 1);
|
|
} else {
|
|
mnt = misc_mntent_lookup(MOUNTED, device, 0);
|
|
}
|
|
|
|
if (mnt == INVAL_PTR)
|
|
path = 0;
|
|
else if (mnt)
|
|
return mnt;
|
|
}
|
|
#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
|
|
|
|
/* If has not been checked in neither /proc/mounts nor /etc/mtab (or
|
|
errors have occured), return INVAL_PTR, NULL otherwise. */
|
|
return (!proc && !path) ? INVAL_PTR : NULL;
|
|
}
|
|
|
|
int misc_device_mounted(char *device)
|
|
{
|
|
struct mntent *mnt;
|
|
|
|
/* Check for the "/" first to avoid any possible problem with
|
|
reflecting the root fs info in mtab files. */
|
|
if (misc_root_mounted(device) == 1) {
|
|
return misc_file_ro("/") ? MF_RO : MF_RW;
|
|
}
|
|
|
|
/* Lookup the mount entry. */
|
|
if ((mnt = misc_mntent(device)) == NULL) {
|
|
return MF_NOT_MOUNTED;
|
|
} else if (mnt == INVAL_PTR) {
|
|
return 0;
|
|
}
|
|
|
|
return hasmntopt(mnt, MNTOPT_RO) ? MF_RO : MF_RW;
|
|
}
|
|
|
|
char buf1[100];
|
|
char buf2[100];
|
|
|
|
void print_how_fast(unsigned long passed, unsigned long total,
|
|
int cursor_pos, int reset_time)
|
|
{
|
|
static time_t t0 = 0, t1 = 0, t2 = 0;
|
|
int speed;
|
|
int indent;
|
|
|
|
if (reset_time)
|
|
time(&t0);
|
|
|
|
time(&t1);
|
|
if (t1 != t0) {
|
|
speed = passed / (t1 - t0);
|
|
if (total - passed) {
|
|
if (t1 - t2 < 1)
|
|
return;
|
|
t2 = t1;
|
|
}
|
|
} else
|
|
speed = 0;
|
|
|
|
/* what has to be written */
|
|
if (total)
|
|
sprintf(buf1, "left %lu, %d /sec", total - passed, speed);
|
|
else {
|
|
/*(*passed) ++; */
|
|
sprintf(buf1, "done %lu, %d /sec", passed, speed);
|
|
}
|
|
|
|
/* make indent */
|
|
indent = 79 - cursor_pos - strlen(buf1);
|
|
memset(buf2, ' ', indent);
|
|
buf2[indent] = 0;
|
|
fprintf(stderr, "%s%s", buf2, buf1);
|
|
|
|
memset(buf2, '\b', indent + strlen(buf1));
|
|
buf2[indent + strlen(buf1)] = 0;
|
|
fprintf(stderr, "%s", buf2);
|
|
fflush(stderr);
|
|
}
|
|
|
|
static char *strs[] =
|
|
{ "0%", ".", ".", ".", ".", "20%", ".", ".", ".", ".", "40%", ".", ".", ".",
|
|
".", "60%", ".", ".", ".", ".", "80%", ".", ".", ".", ".", "100%" };
|
|
|
|
static char progress_to_be[1024];
|
|
static char current_progress[1024];
|
|
|
|
static void str_to_be(char *buf, int prosents)
|
|
{
|
|
int i;
|
|
prosents -= prosents % 4;
|
|
buf[0] = 0;
|
|
for (i = 0; i <= prosents / 4; i++)
|
|
strcat(buf, strs[i]);
|
|
}
|
|
|
|
void print_how_far(FILE * fp,
|
|
unsigned long *passed, unsigned long total,
|
|
unsigned int inc, int quiet)
|
|
{
|
|
int percent;
|
|
|
|
if (*passed == 0)
|
|
current_progress[0] = 0;
|
|
|
|
(*passed) += inc;
|
|
if (*passed > total) {
|
|
/* fprintf (fp, "\nprint_how_far: total %lu has been reached already. cur=%lu\n",
|
|
total, *passed);*/
|
|
return;
|
|
}
|
|
|
|
percent = ((*passed) * 100) / total;
|
|
|
|
str_to_be(progress_to_be, percent);
|
|
|
|
if (strlen(current_progress) != strlen(progress_to_be)) {
|
|
fprintf(fp, "%s", progress_to_be + strlen(current_progress));
|
|
}
|
|
|
|
strcat(current_progress, progress_to_be + strlen(current_progress));
|
|
|
|
if (!quiet) {
|
|
print_how_fast(*passed /* - inc */ , total,
|
|
strlen(progress_to_be),
|
|
(*passed == inc) ? 1 : 0);
|
|
}
|
|
|
|
fflush(fp);
|
|
}
|
|
|
|
#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
|
|
/* Note! Despite this call being called with *64, it must be encoded to
|
|
* return only sizeof(size_t), since in earlier kernel versions it was
|
|
* declared _IOR(0x12, 114, sizeof(u64)), making it use sizeof(sizeof(u64)).
|
|
*
|
|
* However, the call itself does always return 64bit!
|
|
*/
|
|
# define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
|
#endif
|
|
|
|
/* To not have problem with last sectors on the block device when switching
|
|
to smaller one. */
|
|
#define MAX_BS (64 * 1024)
|
|
|
|
int valid_offset(int fd, loff_t offset)
|
|
{
|
|
char ch;
|
|
loff_t res;
|
|
|
|
/*res = reiserfs_llseek (fd, offset, 0); */
|
|
res = lseek(fd, offset, SEEK_SET);
|
|
if (res < 0)
|
|
return 0;
|
|
|
|
/* if (read (fd, &ch, 1) < 0) does not wirk on files */
|
|
if (read(fd, &ch, 1) < 1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* calculates number of blocks in a file. Returns 0 for "sparse"
|
|
regular files and files other than regular files and block devices */
|
|
unsigned long count_blocks(char *filename, int blocksize)
|
|
{
|
|
loff_t high, low;
|
|
unsigned long sz;
|
|
__u64 size;
|
|
int fd;
|
|
|
|
if (!S_ISBLK(misc_device_mode(filename)) &&
|
|
!S_ISREG(misc_device_mode(filename)))
|
|
return 0;
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
if (fd == -1) {
|
|
fprintf(stderr, "Failed to open '%s': %s.\n", filename,
|
|
strerror(errno));
|
|
return 0;
|
|
}
|
|
#ifdef BLKGETSIZE64
|
|
{
|
|
if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
|
|
size = (size / MAX_BS) * MAX_BS / blocksize;
|
|
sz = size;
|
|
if ((__u64) sz != size)
|
|
die("count_blocks: block device too large");
|
|
|
|
close(fd);
|
|
return sz;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef BLKGETSIZE
|
|
{
|
|
if (ioctl(fd, BLKGETSIZE, &sz) >= 0) {
|
|
size = sz;
|
|
|
|
close(fd);
|
|
return (size * 512 / MAX_BS) * MAX_BS / blocksize;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
low = 0;
|
|
for (high = 1; valid_offset(fd, high); high *= 2)
|
|
low = high;
|
|
while (low < high - 1) {
|
|
const loff_t mid = (low + high) / 2;
|
|
|
|
if (valid_offset(fd, mid))
|
|
low = mid;
|
|
else
|
|
high = mid;
|
|
}
|
|
|
|
valid_offset(fd, 0);
|
|
|
|
close(fd);
|
|
return (low + 1) * MAX_BS / MAX_BS / blocksize;
|
|
}
|
|
|
|
/* there are masks for certain bits */
|
|
__u16 mask16(int from, int count)
|
|
{
|
|
__u16 mask;
|
|
|
|
mask = (0xffff >> from);
|
|
mask <<= from;
|
|
mask <<= (16 - from - count);
|
|
mask >>= (16 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
__u32 mask32(int from, int count)
|
|
{
|
|
__u32 mask;
|
|
|
|
mask = (0xffffffff >> from);
|
|
mask <<= from;
|
|
mask <<= (32 - from - count);
|
|
mask >>= (32 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
__u64 mask64(int from, int count)
|
|
{
|
|
__u64 mask;
|
|
|
|
mask = (0xffffffffffffffffLL >> from);
|
|
mask <<= from;
|
|
mask <<= (64 - from - count);
|
|
mask >>= (64 - from - count);
|
|
return mask;
|
|
}
|
|
|
|
__u32 get_random(void)
|
|
{
|
|
srandom(time(0));
|
|
return random();
|
|
}
|
|
|
|
/* this implements binary search in the array 'base' among 'num' elements each
|
|
of those is 'width' bytes long. 'comp_func' is used to compare keys */
|
|
int reiserfs_bin_search(void *key, void *base, __u32 num, int width,
|
|
__u32 * ppos, comparison_fn_t comp_func)
|
|
{
|
|
__u32 rbound, lbound, j;
|
|
int ret;
|
|
|
|
if (num == 0 || base == NULL) {
|
|
/* objectid map may be 0 elements long */
|
|
*ppos = 0;
|
|
return POSITION_NOT_FOUND;
|
|
}
|
|
|
|
lbound = 0;
|
|
rbound = num - 1;
|
|
|
|
for (j = (rbound + lbound) / 2; lbound <= rbound;
|
|
j = (rbound + lbound) / 2) {
|
|
ret = comp_func((void *)((char *)base + j * width), key);
|
|
if (ret < 0) { /* second is greater */
|
|
lbound = j + 1;
|
|
continue;
|
|
|
|
} else if (ret > 0) { /* first is greater */
|
|
if (j == 0)
|
|
break;
|
|
rbound = j - 1;
|
|
continue;
|
|
} else { /* equal */
|
|
*ppos = j;
|
|
return POSITION_FOUND;
|
|
}
|
|
}
|
|
|
|
*ppos = lbound;
|
|
return POSITION_NOT_FOUND;
|
|
}
|
|
|
|
#define BLOCKLIST__ELEMENT_NUMBER 10
|
|
|
|
/*element is block number and device*/
|
|
int blockdev_list_compare(const void *block1, const void *block2)
|
|
{
|
|
if (*(__u32 *) block1 < *(__u32 *) block2)
|
|
return -1;
|
|
if (*(__u32 *) block1 > *(__u32 *) block2)
|
|
return 1;
|
|
|
|
if (*((__u32 *) block1 + 1) < *((__u32 *) block2 + 1))
|
|
return -1;
|
|
if (*((__u32 *) block1 + 1) > *((__u32 *) block2 + 1))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void blocklist__insert_in_position(void *elem, void **base, __u32 * count,
|
|
int elem_size, __u32 * position)
|
|
{
|
|
if (elem_size == 0)
|
|
return;
|
|
|
|
if (*base == NULL)
|
|
*base = getmem(BLOCKLIST__ELEMENT_NUMBER * elem_size);
|
|
|
|
if (*count == get_mem_size((void *)*base) / elem_size)
|
|
*base = expandmem(*base, get_mem_size((void *)*base),
|
|
BLOCKLIST__ELEMENT_NUMBER * elem_size);
|
|
|
|
if (*position < *count) {
|
|
memmove(*base + (*position + 1),
|
|
*base + (*position), (*count - *position) * elem_size);
|
|
}
|
|
|
|
memcpy(*base + (char)*position * elem_size, elem, elem_size);
|
|
*count += 1;
|
|
}
|
|
|
|
/* 0 - dma is not supported, scsi or regular file */
|
|
/* 1 - xt drive */
|
|
/* 2 - ide drive */
|
|
static void get_dma_support(dma_info_t *dma_info)
|
|
{
|
|
if (S_ISREG(dma_info->st.st_mode))
|
|
dma_info->st.st_rdev = dma_info->st.st_dev;
|
|
|
|
if (IDE_DISK_MAJOR(major(dma_info->st.st_rdev))) {
|
|
dma_info->support_type = 2;
|
|
return;
|
|
}
|
|
#ifdef XT_DISK_MAJOR
|
|
if (major(dma_info->st.st_rdev) == XT_DISK_MAJOR) {
|
|
dma_info->support_type = 1;
|
|
return;
|
|
}
|
|
#endif
|
|
dma_info->support_type = 0;
|
|
}
|
|
|
|
/*
|
|
* Return values:
|
|
* 0 - ok;
|
|
* 1 - preparation cannot be done
|
|
* -1 - preparation failed
|
|
*/
|
|
|
|
int prepare_dma_check(dma_info_t *dma_info)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *dirent;
|
|
struct stat st;
|
|
dev_t rdev;
|
|
int rem;
|
|
char buf[256];
|
|
|
|
#ifndef HDIO_GET_DMA
|
|
return -1;
|
|
#endif
|
|
|
|
if (fstat(dma_info->fd, &dma_info->st))
|
|
die("stat on device failed\n");
|
|
|
|
get_dma_support(dma_info);
|
|
|
|
/* dma should be supported */
|
|
if (dma_info->support_type == 0)
|
|
return 1;
|
|
|
|
if (dma_info->support_type == 2) {
|
|
rdev = dma_info->st.st_rdev;
|
|
|
|
if ((rem = (minor(rdev) % 64)) != 0) {
|
|
rdev -= rem;
|
|
if (!(dir = opendir("/dev/"))) {
|
|
dma_info->support_type = 1;
|
|
return 0;
|
|
}
|
|
|
|
while ((dirent = readdir(dir)) != NULL) {
|
|
if (strncmp(dirent->d_name, ".", 1) == 0
|
|
|| strncmp(dirent->d_name, "..", 2) == 0)
|
|
continue;
|
|
memset(buf, 0, 256);
|
|
strncat(buf, "/dev/", 5);
|
|
strncat(buf, dirent->d_name,
|
|
strlen(dirent->d_name));
|
|
|
|
if (stat(buf, &st))
|
|
break;
|
|
|
|
if (S_ISBLK(st.st_mode) && st.st_rdev == rdev) {
|
|
dma_info->st = st;
|
|
dma_info->fd = open(buf, O_RDONLY
|
|
#if defined(O_LARGEFILE)
|
|
| O_LARGEFILE
|
|
#endif
|
|
);
|
|
closedir(dir);
|
|
return 0;
|
|
}
|
|
}
|
|
closedir(dir);
|
|
dma_info->support_type = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int is_dma_on(int fd)
|
|
{
|
|
#ifdef HDIO_GET_DMA
|
|
static long parm;
|
|
if (ioctl(fd, HDIO_GET_DMA, &parm))
|
|
return -1;
|
|
else
|
|
return parm;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static __u64 dma_speed(int fd, int support_type)
|
|
{
|
|
static struct hd_driveid id;
|
|
__u64 speed = 0;
|
|
|
|
if (support_type != 2)
|
|
return 0;
|
|
|
|
#ifdef HDIO_OBSOLETE_IDENTITY
|
|
if (!ioctl(fd, HDIO_GET_IDENTITY, &id) ||
|
|
!ioctl(fd, HDIO_OBSOLETE_IDENTITY)) {
|
|
#else
|
|
if (!ioctl(fd, HDIO_GET_IDENTITY, &id)) {
|
|
#endif
|
|
speed |= (__u64) id.dma_1word & ~(__u64) 0xff;
|
|
speed |= ((__u64) id.dma_mword & ~(__u64) 0xff) << 16;
|
|
speed |= ((__u64) id.dma_ultra & ~(__u64) 0xff) << 32;
|
|
} else if (errno == -ENOMSG)
|
|
return -1;
|
|
else
|
|
return -1;
|
|
|
|
return speed;
|
|
}
|
|
|
|
int get_dma_info(dma_info_t *dma_info)
|
|
{
|
|
if ((dma_info->dma = is_dma_on(dma_info->fd)) == -1)
|
|
return -1;
|
|
if ((dma_info->speed =
|
|
dma_speed(dma_info->fd, dma_info->support_type)) == (__u64) - 1)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void clean_after_dma_check(int fd, dma_info_t *dma_info)
|
|
{
|
|
signal(SIGALRM, SIG_IGN);
|
|
if (dma_info->fd && fd != dma_info->fd)
|
|
close(dma_info->fd);
|
|
}
|
|
|
|
/* Only le bitops operations are used. */
|
|
|
|
inline int misc_set_bit(unsigned long long nr, void *addr)
|
|
{
|
|
__u8 *p, mask;
|
|
int retval;
|
|
|
|
p = (__u8 *) addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
/*cli(); */
|
|
retval = (mask & *p) != 0;
|
|
*p |= mask;
|
|
/*sti(); */
|
|
return retval;
|
|
}
|
|
|
|
inline int misc_clear_bit(unsigned long long nr, void *addr)
|
|
{
|
|
__u8 *p, mask;
|
|
int retval;
|
|
|
|
p = (__u8 *) addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
/*cli(); */
|
|
retval = (mask & *p) != 0;
|
|
*p &= ~mask;
|
|
/*sti(); */
|
|
return retval;
|
|
}
|
|
|
|
inline int misc_test_bit(unsigned long long nr, const void *addr)
|
|
{
|
|
__u8 *p, mask;
|
|
|
|
p = (__u8 *) addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
return ((mask & *p) != 0);
|
|
}
|
|
|
|
inline unsigned long long misc_find_first_zero_bit(const void *vaddr,
|
|
unsigned long long size)
|
|
{
|
|
const __u8 *p = vaddr, *addr = vaddr;
|
|
unsigned long long res;
|
|
|
|
if (!size)
|
|
return 0;
|
|
|
|
size = (size >> 3) + ((size & 0x7) > 0);
|
|
while (*p++ == 255) {
|
|
if (--size == 0)
|
|
return (unsigned long long)(p - addr) << 3;
|
|
}
|
|
|
|
--p;
|
|
for (res = 0; res < 8; res++)
|
|
if (!misc_test_bit(res, p))
|
|
break;
|
|
return res + (p - addr) * 8;
|
|
}
|
|
|
|
inline unsigned long long misc_find_next_zero_bit(const void *vaddr,
|
|
unsigned long long size,
|
|
unsigned long long offset)
|
|
{
|
|
const __u8 *addr = vaddr;
|
|
const __u8 *p = addr + (offset >> 3);
|
|
int bit = offset & 7;
|
|
unsigned long long res;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
|
|
if (bit) {
|
|
/* Look for zero in first char */
|
|
for (res = bit; res < 8; res++)
|
|
if (!misc_test_bit(res, p))
|
|
return res + (p - addr) * 8;
|
|
p++;
|
|
}
|
|
/* No zero yet, search remaining full bytes for a zero */
|
|
res = misc_find_first_zero_bit(p, size - 8 * (p - addr));
|
|
return res + (p - addr) * 8;
|
|
}
|
|
|
|
inline unsigned long long misc_find_first_set_bit(const void *vaddr,
|
|
unsigned long long size)
|
|
{
|
|
const __u8 *p = vaddr, *addr = vaddr;
|
|
unsigned long long res;
|
|
|
|
if (!size)
|
|
return 0;
|
|
|
|
size = (size >> 3) + ((size & 0x7) > 0);
|
|
while (*p++ == 0) {
|
|
if (--size == 0)
|
|
return (unsigned long long)(p - addr) << 3;
|
|
}
|
|
|
|
--p;
|
|
for (res = 0; res < 8; res++)
|
|
if (misc_test_bit(res, p))
|
|
break;
|
|
|
|
return res + (p - addr) * 8;
|
|
}
|
|
|
|
inline unsigned long long misc_find_next_set_bit(const void *vaddr,
|
|
unsigned long long size,
|
|
unsigned long long offset)
|
|
{
|
|
const __u8 *addr = vaddr;
|
|
const __u8 *p = addr + (offset >> 3);
|
|
int bit = offset & 7;
|
|
unsigned long long res;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
|
|
if (bit) {
|
|
/* Look for zero in first char */
|
|
for (res = bit; res < 8; res++)
|
|
if (misc_test_bit(res, p))
|
|
return res + (p - addr) * 8;
|
|
p++;
|
|
}
|
|
/* No set bit yet, search remaining full bytes for a 1 */
|
|
res = misc_find_first_set_bit(p, size - 8 * (p - addr));
|
|
return res + (p - addr) * 8;
|
|
}
|
|
|
|
int user_confirmed(FILE * fp, char *q, char *yes)
|
|
{
|
|
char *answer = 0;
|
|
size_t n = 0;
|
|
|
|
fprintf(fp, "%s", q);
|
|
if (getline(&answer, &n, stdin) != (ssize_t) strlen(yes)
|
|
|| strcmp(yes, answer))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|