How can I put a bit mask on /dev/zero so that I can get bytes other than zero?
You cannot easily do that.
You might consider writing your own kernel module providing such a device. I don't recommend that.
You could write a tiny C program writing an infinite stream of same bytes on some pipe (or on stdout
) or FIFO.
You could use tr(1) to read from /dev/zero
and translate every 0 byte to somethng else.
You could use perhaps yes(1), at least if you can afford having newlines (or else pipe it into tr -d '\n'
...)
The following bash
code is set to work with the byte being representred in binary. However you can easily change it to handle ocatal, decimal or hex by simply changing the radix r
value of 2
to 8
, 10
or 16
respectively and setting b=
accordingly.
r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"
EDIT - It does handle the full range of byte values: hex 00-FF (when I wrote 00-7F below, I was considering only single-byte UTF-8 characters).
If, for example, you only want 4 bytes (characters in the UTF-8 'ASCII'-only hex 00-7F range), you can pipe it into head: ... | head -c4
Output (4 chars):
~~~~
To see the output in 8-bit format, pipe it into xxd
(or any other 1's and 0's byte dump*):
eg. b=10000000
and piping to: ... | head -c4 | xxd -b
0000000: 10000000 10000000 10000000 10000000 ....
Well, if you literally want to achieve this, you can use a LD_PRELOAD hook. The basic idea is to rewrite a function from the C library and use it instead of the normal one.
Here is a simple example where we override the read() function to XOR the output buffer with 0x42.
#define _GNU_SOURCE
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <unistd.h>
static int dev_zero_fd = -1;
int open64(const char *pathname, int flags)
{
static int (*true_open64)(const char*, int) = NULL;
if (true_open64 == NULL) {
if ((true_open64 = dlsym(RTLD_NEXT, "open64")) == NULL) {
perror("dlsym");
return -1;
}
}
int ret = true_open64(pathname, flags);
if (strcmp(pathname, "/dev/zero") == 0) {
dev_zero_fd = ret;
}
return ret;
}
ssize_t read(int fd, void *buf, size_t count)
{
static ssize_t (*true_read)(int, void*, size_t) = NULL;
if (true_read == NULL) {
if ((true_read = dlsym(RTLD_NEXT, "read")) == NULL) {
perror("dlsym");
return -1;
}
}
if (fd == dev_zero_fd) {
int i;
ssize_t ret = true_read(fd, buf, count);
for (i = 0; i < ret; i++) {
*((char*)buf + i) ^= 0x42;
}
return ret;
}
return true_read(fd, buf, count);
}
A naive implementation would XOR 0x42 on every file we read, which would have undesirable consequences. In order to solve this problem, I also hooked the open() function, making it fetch the file descriptor associated with /dev/zero. Then, we only perform the XOR in on our read() function if fd == dev_zero_fd
.
Usage:
$ gcc hook.c -ldl -shared -o hook.so
$ LD_PRELOAD=$(pwd)/hook.so bash #this spawns a hooked shell
$ cat /dev/zero
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB