| /* |
| * 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); |
| } |
| |
| |
| |