blob: f14fa6a17325999364a46e7ba9a525f14e1e6862 [file] [log] [blame]
/*
* 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);
}