I'm learning the mount namespace, a isolating mechanism provided by Linux kernel. I wrote a simple C program to test it.
#define _GNU_SOURCE
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <sys/mount.h>
#include <errno.h>
#include <string.h>
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];
char* const container_args[] = {
"/bin/bash",
NULL
};
void mounts(void)
{
syscall(__NR_mount, "proc", "/home/aaa/nstest/", "proc", 0, NULL);
}
int container_main(void* arg)
{
printf("Container - inside the container!\n");
errno = 0;
mounts();
perror("mount");
execv(container_args[0], container_args);
printf("Something's wrong!\n");
return 1;
}
int main()
{
printf("Parent - start a container!\n");
int pid = syscall(__NR_clone, CLONE_NEWNS | SIGCHLD, NULL, NULL, NULL, NULL);
if (pid < 0) {
perror("clone failed");
exit(-1);
} else if (pid == 0) {
container_main(NULL);
exit(0);
}
waitpid(pid, NULL, 0);
printf("Parent - container stopped!\n");
return 0;
}
And this code working well on my Ubuntu. The directory "/home/aaa/nstest/" is empty in the root mount namespace after it been mounted in new mount namespace.
However, it doesn't work on the Android emulater. The mount propagate to the root mount namespace. Firstly I thought it may caused by the kernel do not support namespace. So I compile the goldfish with all relative CONFIG switch such as CONFIG_NAMESPACE. And it doesn't work either.
i have the same problem, even after recompile the kernel with all CONFIG_NAMESPACE. I have tried the unshare -m /bin/bash command, it works on my archlinux x86_64 box,
so I look deep into the strace unshare -m /bin/bash of the command.
...
unshare(CLONE_NEWNS) = 0
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) = 0
execve("/bin/bash", ["/bin/bash"], [/* 19 vars */]) = 0
...
seams there is a extra call to mount(...). adding the call to my code, it works !
int main(int argc, const char* argv[]) {
const char * source=argv[1];
const char * target=argv[2];
if (unshare(CLONE_NEWNS) == -1) {
printf("Failed to unshare(): %s\n", strerror(errno));
return -1;
}
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL);
if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
printf("Failed to mount %s to %s: %s\n", source, target, strerror(errno));
return -1;
}
sleep(50);
return 0;
}
Related
I am trying to read touchscreen event, in my device /dev/input/event4 is used for touchscreen, while in some other phone, event7 is used for touchscreen.
I am looking for a c function that can help me
to find that touchscreen event.
Each input event device has a corresponding entry in the /sys/class/input/ pseudo-file hierarchy. (See Linux Input Subsystem userspace API in the Linux kernel documentation for further details.) For example, the name of the device corresponding to event7 is in /sys/class/input/event7/device/name.
When you open the event character device (/dev/input/event7), you can use the EVIOCGBIT(type, bits) ioctl to check which kind of events the device can produce. Touchpads will produce EV_ABS events ABS_X and ABS_Y, and EV_KEY event BTN_TOUCH.
Therefore, if you glob /dev/input/event*, open each device in turn, and check if they report the abovementioned three events, you are likely to find the device you look for. For example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/input.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <glob.h>
#include <errno.h>
#include <stdio.h>
#ifndef ULONG_BITS
#define ULONG_BITS (CHAR_BIT * sizeof (unsigned long))
#endif
static inline int has_bit(const unsigned long data[], const size_t bit)
{
return !!(data[bit / ULONG_BITS] & (1uL << (bit % ULONG_BITS)));
}
char *touchscreen_event_device(size_t skip)
{
glob_t files;
int result;
result = glob("/dev/input/event*", 0, NULL, &files);
if (result) {
if (result == GLOB_NOSPACE) {
errno = ENOMEM;
return NULL;
} else
if (result == GLOB_NOMATCH) {
errno = ENOENT;
return NULL;
} else {
errno = EACCES;
return NULL;
}
}
for (size_t i = 0; i < files.gl_pathc; i++) {
int fd = open(files.gl_pathv[i], O_RDONLY);
if (fd != -1) {
unsigned long absbits[1 + ABS_MAX / ULONG_BITS] = { 0 };
unsigned long keybits[1 + KEY_MAX / ULONG_BITS] = { 0 };
if (ioctl(fd, EVIOCGBIT(EV_ABS, ABS_MAX+1), &absbits) != -1 &&
ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX+1), &keybits) != -1) {
if (has_bit(absbits, ABS_X) &&
has_bit(absbits, ABS_Y) &&
has_bit(keybits, BTN_TOUCH)) {
/* Device reports ABS_X, ABS_Y and BTN_TOUCH,
and therefore is a touchpad device. */
if (!skip) {
char *devpath = strdup(files.gl_pathv[i]);
close(fd);
globfree(&files);
if (!devpath)
errno = ENOMEM;
return devpath;
} else {
skip--;
}
}
}
close(fd);
}
}
globfree(&files);
errno = ENOENT;
return NULL;
}
int main(void)
{
size_t i = 0;
while (1) {
char *devpath = touchscreen_event_device(i);
if (!devpath) {
if (i)
break;
fprintf(stderr, "No touchscreen input event devices found: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("Found touchscreen input event device '%s'\n", devpath);
free(devpath);
i++;
}
return EXIT_SUCCESS;
}
Compile using e.g. gcc -Wall -Wextra -O2 example.c -o example, and run with root privileges, and it will list the paths to the input event devices it believes are touch screens.
An answer for a complete code could be difficult because it's a long/heavy work.
I'll point you in right directions:
read "Input Event Codes": https://www.kernel.org/doc/html/v4.14/input/event-codes.html
then you have to list all /dev/input/* files
open each of them using "fd = open("/dev/input/xxxxx", O_RDONLY);"
call "ioctl(fd, EVIOCGBIT(EV_REL, sizeof(maskbit)), maskbit)" (calling this changing "EV_REL" with others "Input Event Codes"
analize "maskbit" by searching for some specific Values that only Touchscreen has
A possibile example could find here: https://android.googlesource.com/device/generic/brillo/+/d1917142dc905d808519023d80a664c066104600/examples/keyboard/keyboard_example.cpp in which the author looking for an Input that supports "KEY_B" Event Code.
Touchscreens should have:
for EV_ABS:
ABS_X
ABS_Y
ABS_MT_SLOT
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_TRACKING_ID
If the Input has all these Bit it is a Touchscreen (reference: https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt)
adb shell dumpsys input - this will show the list of all event nodes with the details that you are looking for
I have a problem with this:
C code
#define CREATE_HTML_FILE_SCRIPT "/bin/curl https://coinmarketcap.com/it/currencies/bytecoin-bcn/ > /data/data/com.example.bytecoin/bcn.html"
#define CREATE_TEMP_FILE_SCRIPT "/data/local/lynx /data/data/com.example.bytecoin/bcn.html -dump > /data/data/com.example.bytecoin/bcn.txt"
system(CREATE_HTML_FILE_SCRIPT);
system(CREATE_TEMP_FILE_SCRIPT);
If I run from adb shell these commands all works well but when these command are executed from the app, file.html and file.txt are empty... I don't understand why and how I can solve it.
Well, lynx is an interactive program, so I think you'll run in trouble when using it from a system() call. But not with curl:
/* pru_curl-1.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
system(cmd); /* you will get the output of curl on stdout */
exit(EXIT_SUCCESS);
}
This is with curl redirecting its output in the shell call with the > operator:
/* pru_curl-2.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/ >output_file-2";
/* you will get the output of curl on output_file-2 */
system(cmd);
exit(EXIT_SUCCESS);
}
Curl, on the other side, allows you to specify -o output_file.txt and you'll be able to read the file, once the program has finished.
/* pru_curl-3.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/ -o output_file-3";
/* you will get the output of curl on output_file-3 */
system(cmd);
exit(EXIT_SUCCESS);
}
You have a third alternative, which is using popen(3), that allows you to start the program as a subcommand, and read the output of that program from the FILE * descriptor you get from popen(3). You could use it like this (processing character by character):
/* pru_curl-4.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
int c;
while((c = fgetc(f)) != EOF) {
printf("[%d]", c); /* you will get the downloaded file as
* sequences of numbers (the character
* values) embedded in square brackets on
* stdout */
}
pclose(f);
exit(EXIT_SUCCESS);
}
or (processing line by line):
/* pru_curl-5.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
char line[256];
while (fgets(line, sizeof line, f)) {
/* you'll get your output in chunks of one line, or 256 bytes
* ---if longer---, encapsulated by a pair of square brackets
* drawn in a different color (gren, by the escape sequences
* used) */
fprintf(stderr,
"\033[1;33m[\033[m%s\033[32m]\033[m",
line);
}
pclose(f);
exit(EXIT_SUCCESS);
}
or (by blocks):
/* pru_curl-6.c */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 8 /* blocks in buffer */
#define CPB 11 /* chars per block */
int main()
{
char *cmd = "curl https://www.google.com/";
FILE *f = popen(cmd, "r");
if (!f) {
fprintf(stderr, "%s: %s\n",
cmd, strerror(errno));
exit(EXIT_FAILURE);
}
char block[N][CPB];
int n;
char *sep = "";
do {
/* print a blanck line between groups */
printf("%s", sep);
sep = "\n";
/* we read as many CPB byte blocks as possible to fill the
* N registers in buffer.
* Then we start again until we don't fill completely the
* buffer. */
n = fread(block, sizeof block[0], N, f);
int i;
for (i = 0; i < n; i++) {
printf("[%.*s]\n", (int)sizeof block[i], block[i]);
}
printf("finished one loop of %d blocks of %d chars, each.\n",
N, (int) sizeof block[0]);
} while (n == N);
/* n < N, so we are finished, check that probably the last register is
* not printed because it was not complete. */
pclose(f);
exit(EXIT_SUCCESS);
}
(All these examples are complete and have been tested before posting)
Edit
I have completed the code for the six programs and now all of them are executables with just building with:
$ cc pru_curl-<i>.c -o pru_curl-<i> # <i> is the program number
$ _
In each case, you can execute the program by just running:
$ pru_curl-<i>
.... <-- a lot of output (or to a file) about the contents of the root page of google.
$ _
I am trying to run a simple IOCTL example on Android. I am using kernel 2.6 and ICS. The module is properly registered/unregistered (insmod/rmmod). However, every time a try to execute ./user_app on the emulator, I always get
error: first ioctl: Not a typewriter
error: second ioctl: Not a typewriter
message: `�
This is clearly a ENOTTY. I debugged the application, and no fops procedure (device_ioctl, read_ioctl and write_ioctl) is being executed.
I would like to know if there is any restriction with the usage/implementation of IOCTL on Android. Thank you very much in advance.
--Raul
Here is the code:
module.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define MY_MACIG 'G'
#define READ_IOCTL _IOR(MY_MACIG, 0, int)
#define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
int main(){
char buf[200];
int fd = -1;
if ((fd = open("/data/local/afile.txt", O_RDWR)) < 0) {
perror("open");
return -1;
}
if(ioctl(fd, WRITE_IOCTL, "hello world") < 0)
perror("first ioctl");
if(ioctl(fd, READ_IOCTL, buf) < 0)
perror("second ioctl");
printf("message: %s\n", buf);
return 0;
}
user_app.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define MY_MACIG 'G'
#define READ_IOCTL _IOR(MY_MACIG, 0, int)
#define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
static char msg[200];
static ssize_t device_read(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
...
}
static ssize_t device_write(struct file *filp, const char __user *buff, size_t len, loff_t *off)
{
...
}
char buf[200];
int device_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) {
int len = 200;
switch(cmd) {
case READ_IOCTL:
...
break;
case WRITE_IOCTL:
...
break;
default:
return -ENOTTY;
}
return len;
}
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.unlocked_ioctl = device_ioctl,
};
static int __init example_module_init(void)
{
printk("registering module");
return 0;
}
static void __exit example_module_exit(void)
{
printk("unregistering module");
}
module_init(example_module_init);
module_exit(example_module_exit);
MODULE_LICENSE("GPL");
It this the whole code that you've posted? You don't register a char device when initializing a module, so this can't work.
Also, be carefull when assigning IOCTLS numbers. When using reserved IOCTL on a wrong file, you will get ENOTTY. Consult this to make sure you don't have conflicts.
Read more about char drivers here.
Im trying to compile reboot.c binary for android but i keep getting following error:
/home/pedja/android-ndk-r8d/toolchains/x86-4.6/prebuilt/linux-x86/bin/../lib/gcc/i686- linux-android/4.6/../../../../i686-linux-android/bin/ld: ./obj/local/x86/objs/reboot /reboot.o: in function main:jni/reboot.c:49: error: undefined reference to 'android_reboot'
/home/pedja/android-ndk-r8d/toolchains/x86-4.6/prebuilt/linux-x86/bin/../lib/gcc/i686-linux-android/4.6/../../../../i686-linux-android/bin/ld: ./obj/local/x86/objs/reboot /reboot.o: in function main:jni/reboot.c:51: error: undefined reference to 'android_reboot'
/home/pedja/android-ndk-r8d/toolchains/x86-4.6/prebuilt/linux-x86/bin/../lib/gcc/i686-linux-android/4.6/../../../../i686-linux-android/bin/ld: ./obj/local/x86/objs/reboot/reboot.o: in function main:jni/reboot.c:47: error: undefined reference to 'android_reboot'
collect2: ld returned 1 exit status
make: *** [obj/local/x86/reboot] Error 1
reboot.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "android_reboot.h"
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret;
int nosync = 0;
int poweroff = 0;
int flags = 0;
opterr = 0;
do {
int c;
c = getopt(argc, argv, "np");
if (c == EOF) {
break;
}
switch (c) {
case 'n':
nosync = 1;
break;
case 'p':
poweroff = 1;
break;
case '?':
fprintf(stderr, "usage: %s [-n] [-p] [rebootcommand]\n", argv[0]);
exit(EXIT_FAILURE);
}
} while (1);
if(argc > optind + 1) {
fprintf(stderr, "%s: too many arguments\n", argv[0]);
exit(EXIT_FAILURE);
}
if(nosync)
/* also set NO_REMOUNT_RO as remount ro includes an implicit sync */
flags = ANDROID_RB_FLAG_NO_SYNC | ANDROID_RB_FLAG_NO_REMOUNT_RO;
if(poweroff)
ret = android_reboot(ANDROID_RB_POWEROFF, flags, 0);
else if(argc > optind)
ret = android_reboot(ANDROID_RB_RESTART2, flags, argv[optind]);
else
ret = android_reboot(ANDROID_RB_RESTART, flags, 0);
if(ret < 0) {
perror("reboot");
exit(EXIT_FAILURE);
}
fprintf(stderr, "reboot returned\n");
return 0;
}
android_reboot.h
#ifndef __ANDROID_REBOOT_H__
#define __ANDROID_REBOOT_H__
__BEGIN_DECLS
/* Commands */
#define ANDROID_RB_RESTART 0xDEAD0001
#define ANDROID_RB_POWEROFF 0xDEAD0002
#define ANDROID_RB_RESTART2 0xDEAD0003
/* Flags */
#define ANDROID_RB_FLAG_NO_SYNC 0x1
#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
int android_reboot(int cmd, int flags, char *arg);
__END_DECLS
#endif
You're showing that you've declared android_reboot however your link fails because the implementation of that function cannot be found. Declaration is not the same as definition... declaration satisfies the compiler, but only implementation satisfies the linker. Where is this function implemented?
I want to use the syscall of __NR_perf_event_open for my Android app.
The code runs normally on linux but does not work on Android.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <perf_event.h>
#include <asm/unistd.h>
long perf_event_open( struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags )
{
int ret;
ret = syscall( __NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags );
return ret;
}
int main() {
//In the main function, I call perf_event_open:
struct perf_event_attr pe;
int fd;
fd = perf_event_open(&pe, 0, -1, -1, 0);
...
}
However, the fd always return the value -1. When I use "errno.h", it gave the error informaiton of:EBADF:bad file descriptor.
you have not configured "struct perf_event_attr pe;" yet
because pid == -1 and cpu == -1 is not valid. you can check it in http://web.eece.maine.edu/~vweaver/projects/perf_events/perf_event_open.html