614 lines
12 KiB
C
614 lines
12 KiB
C
/*
|
|
* Copyright 1996, 1997, 1998 Hans Reiser
|
|
*/
|
|
/*#define _GNU_SOURCE*/
|
|
/*#define _FILE_OFFSET_BITS 64*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <asm/types.h>
|
|
#include <stdlib.h>
|
|
#include <mntent.h>
|
|
#include <sys/vfs.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "io.h"
|
|
|
|
/*
|
|
* These have been stolen somewhere from linux
|
|
*/
|
|
int set_bit (int 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;
|
|
}
|
|
|
|
|
|
int clear_bit (int 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;
|
|
}
|
|
|
|
int test_bit(int nr, const void * addr)
|
|
{
|
|
__u8 * p, mask;
|
|
|
|
p = (__u8 *)addr;
|
|
p += nr >> 3;
|
|
mask = 1 << (nr & 0x7);
|
|
return ((mask & *p) != 0);
|
|
}
|
|
|
|
int find_first_zero_bit (const void *vaddr, unsigned size)
|
|
{
|
|
const __u8 *p = vaddr, *addr = vaddr;
|
|
int res;
|
|
|
|
if (!size)
|
|
return 0;
|
|
|
|
size = (size >> 3) + ((size & 0x7) > 0);
|
|
while (*p++ == 255) {
|
|
if (--size == 0)
|
|
return (p - addr) << 3;
|
|
}
|
|
|
|
--p;
|
|
for (res = 0; res < 8; res++)
|
|
if (!test_bit (res, p))
|
|
break;
|
|
return (p - addr) * 8 + res;
|
|
}
|
|
|
|
|
|
int find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
|
|
{
|
|
const __u8 *addr = vaddr;
|
|
const __u8 *p = addr + (offset >> 3);
|
|
int bit = offset & 7, res;
|
|
|
|
if (offset >= size)
|
|
return size;
|
|
|
|
if (bit) {
|
|
/* Look for zero in first char */
|
|
for (res = bit; res < 8; res++)
|
|
if (!test_bit (res, p))
|
|
return (p - addr) * 8 + res;
|
|
p++;
|
|
}
|
|
/* No zero yet, search remaining full bytes for a zero */
|
|
res = find_first_zero_bit (p, size - 8 * (p - addr));
|
|
return (p - addr) * 8 + res;
|
|
}
|
|
|
|
|
|
/*int test_and_set_bit (int nr, void * addr)
|
|
{
|
|
int oldbit = test_bit (nr, addr);
|
|
set_bit (nr, addr);
|
|
return oldbit;
|
|
}
|
|
|
|
|
|
int test_and_clear_bit (int nr, void * addr)
|
|
{
|
|
int oldbit = test_bit (nr, addr);
|
|
clear_bit (nr, addr);
|
|
return oldbit;
|
|
}*/
|
|
|
|
|
|
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\n\n", buf);
|
|
exit (-1);
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
|
static 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 * p;
|
|
char * mem;
|
|
|
|
p = (char *)malloc (CONTROL_SIZE + size);
|
|
if (!p)
|
|
die ("getmem: no more memory (%d)", size);
|
|
|
|
strcpy (p, MEM_BEGIN);
|
|
p += strlen (MEM_BEGIN) + 1;
|
|
*(int *)p = size;
|
|
p += sizeof (int);
|
|
mem = p;
|
|
memset (mem, 0, size);
|
|
p += size;
|
|
strcpy (p, MEM_END);
|
|
|
|
checkmem (mem, size);
|
|
|
|
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 *);
|
|
|
|
static int is_readonly_dir (char * dir)
|
|
{
|
|
char * name;
|
|
FILE * f;
|
|
|
|
name = tempnam (dir, 0);
|
|
if (!name) {
|
|
fprintf (stderr, "is_readonly: tempnam failed, think fs is not readonly\n");
|
|
return 0;
|
|
}
|
|
|
|
f = fopen (name, "w");
|
|
if (f) {
|
|
unlink (name);
|
|
free (name);
|
|
return 0;
|
|
}
|
|
free (name);
|
|
return (errno == EROFS) ? 1 : 0;
|
|
}
|
|
|
|
int user_confirmed (char * q, char * yes)
|
|
{
|
|
char * answer = 0;
|
|
size_t n = 0;
|
|
|
|
fprintf (stderr, "%s", q);
|
|
if (getline (&answer, &n, stdin) != strlen (yes) || strcmp (yes, answer))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
#include <unistd.h>
|
|
#include <linux/unistd.h>
|
|
|
|
#define __NR_stat64 195
|
|
_syscall2(long, stat64, char *, filename, struct stat *, statbuf);
|
|
|
|
|
|
static int _is_mounted (char * device_name, func_t f)
|
|
{
|
|
int retval;
|
|
FILE *fp;
|
|
struct mntent *mnt;
|
|
struct statfs stfs;
|
|
struct stat root_st;
|
|
struct stat device_st;
|
|
/* struct stat64 device_st64;*/
|
|
int used_stat64 = 1;
|
|
|
|
if (stat ("/", &root_st) == -1)
|
|
die ("is_mounted: could not stat \"/\": %m\n");
|
|
|
|
if (stat64 (device_name, &device_st) == -1) {
|
|
used_stat64 = 0;
|
|
if (stat (device_name, &device_st) == -1)
|
|
die ("is_mounted: could not stat file \"%s\": %m",
|
|
device_name);
|
|
}
|
|
|
|
if ((used_stat64 && !S_ISBLK (device_st.st_mode)) || !S_ISBLK (device_st.st_mode))
|
|
/* not block device file could not be mounted */
|
|
return 0;
|
|
|
|
if ((used_stat64 && root_st.st_dev == device_st.st_rdev) ||
|
|
root_st.st_dev == device_st.st_rdev) {
|
|
/* device is mounted as root */
|
|
return (f ? f ("/") : 1);
|
|
}
|
|
|
|
/* if proc filesystem is mounted */
|
|
if (statfs ("/proc", &stfs) == -1 || stfs.f_type != 0x9fa0/*procfs magic*/ ||
|
|
(fp = setmntent ("/proc/mounts", "r")) == NULL) {
|
|
/* proc filesystem is not mounted, or /proc/mounts does not
|
|
exist */
|
|
if (f)
|
|
return (user_confirmed (" (could not figure out) Is filesystem mounted read-only? (Yes)",
|
|
"Yes\n"));
|
|
else
|
|
return (user_confirmed (" (could not figure out) Is filesystem mounted? (Yes)",
|
|
"Yes\n"));
|
|
}
|
|
|
|
retval = 0;
|
|
while ((mnt = getmntent (fp)) != NULL)
|
|
if (strcmp (device_name, mnt->mnt_fsname) == 0) {
|
|
retval = (f ? f (mnt->mnt_dir) : 1);
|
|
break;
|
|
}
|
|
endmntent (fp);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
int is_mounted_read_only (char * device_name)
|
|
{
|
|
return _is_mounted (device_name, is_readonly_dir);
|
|
}
|
|
|
|
|
|
int is_mounted (char * device_name)
|
|
{
|
|
return _is_mounted (device_name, 0);
|
|
}
|
|
|
|
|
|
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, t1;
|
|
int speed;
|
|
int indent;
|
|
|
|
if (reset_time)
|
|
time (&t0);
|
|
|
|
time (&t1);
|
|
if (t1 != t0)
|
|
speed = passed / (t1 - t0);
|
|
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 (unsigned long * passed, unsigned long total,
|
|
int inc, int quiet)
|
|
{
|
|
int percent;
|
|
|
|
if (*passed == 0)
|
|
current_progress[0] = 0;
|
|
|
|
(*passed) += inc;
|
|
if (*passed > total) {
|
|
fprintf (stderr, "\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 (stderr, "%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 (stderr);
|
|
}
|
|
|
|
|
|
|
|
#define ENDIANESS_NOT_DEFINED 0
|
|
#define LITTLE_ENDIAN_ARCH 1
|
|
#define BIG_ENDIAN_ARCH 2
|
|
|
|
static int endianess = ENDIANESS_NOT_DEFINED;
|
|
|
|
|
|
static void find_endianess (void)
|
|
{
|
|
__u32 x = 0x0f0d0b09;
|
|
char * s;
|
|
|
|
s = (char *)&x;
|
|
|
|
// little-endian is 1234
|
|
if (s[0] == '\11' && s[1] == '\13' && s[2] == '\15' && s[3] == '\17')
|
|
endianess = LITTLE_ENDIAN_ARCH;
|
|
|
|
// big-endian is 4321
|
|
if (s[0] == '\17' && s[1] == '\15' && s[2] == '\13' && s[3] == '\11')
|
|
die ("big-endian archs are not supported");
|
|
|
|
// nuxi/pdp-endian is 3412
|
|
if (s[0] == '\15' && s[1] == '\17' && s[2] == '\11' && s[3] == '\13')
|
|
die ("nuxi/pdp-endian archs are not supported");
|
|
}
|
|
|
|
|
|
// we used to use such function in the kernel stuff of reiserfs. Lets
|
|
// have them in utils as well
|
|
inline __u32 cpu_to_le32 (__u32 val)
|
|
{
|
|
if (endianess == ENDIANESS_NOT_DEFINED)
|
|
find_endianess ();
|
|
|
|
if (endianess == LITTLE_ENDIAN_ARCH)
|
|
return val;
|
|
|
|
die ("neither big- nor any other endian archs are supported yet ");
|
|
|
|
return ((val>>24) | ((val>>8)&0xFF00) |
|
|
((val<<8)&0xFF0000) | (val<<24));
|
|
}
|
|
|
|
|
|
inline __u32 le32_to_cpu (__u32 val)
|
|
{
|
|
return cpu_to_le32 (val);
|
|
}
|
|
|
|
|
|
inline __u16 cpu_to_le16 (__u16 val)
|
|
{
|
|
return val;
|
|
|
|
if (endianess == ENDIANESS_NOT_DEFINED)
|
|
find_endianess ();
|
|
|
|
if (endianess == LITTLE_ENDIAN_ARCH)
|
|
return val;
|
|
die ("neither big- nor pdp- endian arch are supported yet ");
|
|
|
|
return (val >> 8) | (val << 8);
|
|
}
|
|
|
|
|
|
inline __u16 le16_to_cpu (__u16 val)
|
|
{
|
|
/*printf ("%s:%u %p %p %p\n", __FILE__, __LINE__,
|
|
__builtin_return_address (0),
|
|
__builtin_return_address (1),
|
|
__builtin_return_address (2));*/
|
|
return val;
|
|
return cpu_to_le16 (val);
|
|
}
|
|
|
|
|
|
inline __u64 cpu_to_le64 (__u64 val)
|
|
{
|
|
if (endianess == ENDIANESS_NOT_DEFINED)
|
|
find_endianess ();
|
|
|
|
if (endianess == LITTLE_ENDIAN_ARCH)
|
|
return val;
|
|
die ("neither big- nor pdp- endian arch are supported yet ");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
inline __u64 le64_to_cpu (__u64 val)
|
|
{
|
|
return cpu_to_le64 (val);
|
|
}
|
|
|
|
|
|
/* Given a file descriptor and an offset, check whether the offset is
|
|
a valid offset for the file - return 0 if it isn't valid or 1 if it
|
|
is */
|
|
loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin);
|
|
#if 0
|
|
static int valid_offset( int fd, loff_t offset )
|
|
{
|
|
char ch;
|
|
loff_t res;
|
|
|
|
/*res = reiserfs_llseek (fd, offset, 0);*/
|
|
res = lseek64 (fd, offset, 0);
|
|
if (res < 0)
|
|
return 0;
|
|
|
|
if (read (fd, &ch, 1) < 1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
/* calculates number of blocks on device */
|
|
unsigned long count_blocks (char * filename, int blocksize, int fd)
|
|
{
|
|
loff_t high, low;
|
|
int opened_here = 0;
|
|
|
|
if (fd < 0) {
|
|
fd = open (filename, O_RDONLY);
|
|
opened_here = 1;
|
|
}
|
|
if (fd < 0)
|
|
die ("count_blocks: open failed (%s)", strerror (errno));
|
|
|
|
#ifdef BLKGETSIZE
|
|
{
|
|
long size;
|
|
|
|
if (ioctl (fd, BLKGETSIZE, &size) >= 0) {
|
|
if (opened_here)
|
|
close (fd);
|
|
return size / (blocksize / 512);
|
|
}
|
|
}
|
|
#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);
|
|
if (opened_here)
|
|
close (fd);
|
|
|
|
return (low + 1) / (blocksize);
|
|
}
|
|
|
|
|
|
|