Using Ubuntu 18.04.3 LTS (GNU/Linux 5.0.21+ x86_64)
I created a simple syscall and am trying to pass input (the integer 5) through it by calling it in a c program and then see if I can get the input back out. I keep getting random junk as my output rather than my input.
Simple system call:
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/syscalls.h>
#include<linux/signal.h>
#include "tags.h"
asmlinkage int sys_get_tag(int pid)
{
return pid;
}
my userspace test code:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
int pid = syscall(335, 5); // 335 is the syscall number, 5 is the input to the syscall that I am trying to return
printf("return: %d \n", pid);
return 0;
}
my output:
return: 4980568
I get it to work when I return some integer in my syscall, like return 5; for example; so I know the syscall is being used.
Related
I'm trying to mmap a page-size-rounded file to an area larger than the file size and ftruncate it when one of the traling pages causes a SIGBUS so that the SIGBUS no longer happens.
This works great on Linux and MacOS, but on Cygwin I keep getting a SIGBUS even after a successful growing ftruncate.
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void perrorAndExit(char const *Ctx){ perror(Ctx); _exit(1); }
int main(){
long pgsz = sysconf(_SC_PAGESIZE);
int fd = open("TMPFILE", O_RDWR|O_CREAT,0640);
if(0>fd) perrorAndExit("open");
if(ftruncate(fd,pgsz*1)) perrorAndExit("truncate 1 pgsz");
char *m;
if(MAP_FAILED==(m = mmap(0,pgsz*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))) perrorAndExit("mmap");
memset(m,'=',pgsz);
strcpy(m,"hello, world\n");
if(ftruncate(fd,pgsz*2)) perrorAndExit("truncate 2 pgsz");
strcpy(m+pgsz,"what is up?\n"); //still SIGBUSes on Cygwin
}
Are there any workarounds for this other than starting with a larger file or creating a new mapping after the second truncate?
I would like to get the value of the PID_MAX macro present in the file /sys/sys/proc.h.
My current code (main.c) :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* type pid_t */
#include <sys/proc.h> /* macro PID_MAX */
#include <sys/unistd.h> /* function getpid, getppid */
/*
gcc -Wall -Wextra main.c -o main
./main
*/
int main ()
{
pid_t pidmax = PID_MAX;
printf ( "Value = %d\n", pidmax );
return 0;
}
Return the following error :
error: 'PID_MAX' undeclared (first use in this function); did you mean 'UID_MAX'?
How is it possible?
Another method to recover the PID_MAX?
There is no platform-independent method for retrieving the maximum pid value.
Under Linux, for example, you can determine the value through the /proc/sys interface
$ sysctl kernel/pid_max
32768
Under FreeBSD, the value is 99999. If you look closely in sys/proc.h, you will notice that the macro PID_MAX is guarded by
#ifdef _KERNEL
...
#define PID_MAX 99999
...
#endif
This is, why you cannot (and should not) use it in userspace programs.
The PID_MAX macro defines the hard limit of PID values by BSD kernels (such as kFreeBSD); it shouldn't be used by user space programs because the actual maximum PID value could be further lowered in the runtime, controlled by kern.pid_max sysctl.
To get such runtime limitation in an user space program, use sysctlbyname(3); for example:
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
int main() {
int pid_max;
size_t len = sizeof pid_max;
if(sysctlbyname("kern.pid_max", &pid_max, &len, NULL, 0) < 0) {
perror("sysctlbyname: kern.pid_max");
return 1;
}
printf("kern.pid_max=%d\n", pid_max);
return 0;
}
I have added a hello world system call to Linux kernel 3.16, then I compile and ran it. I called my system call by syscall function but it did not print any thing and output of syscall function was not -1.
This is my system call code:
#include <linux/kernel.h>
asmlinkage long sys_hello(void){
printk("hello world\n");
return 0;
}
and this my c program code to call my system call:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <errno.h>
int main(void){
printf("function\n");
if(syscall(317)==-1){
printf("no\n");
}
else{
printf("yes\n");
}
return 0;
}
The output of c program is:
function
yes
How can I find my system call is added to kernel correctly?
printk wouldn't necessarily print to your current tty; to see your message use the dmesg command in your shell. See also this one if it does not show up on dmesg
Hello i wrote my c program which will be run on linux.
I am trying to make my own shell for linux.
I have the following code below...
#include <limits.h>
#include <libgen.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
int main(void){
int i = 0;
int k = 0;
int argsCount = 0;
char inputBuffer[MAX_LINE]; /*buffer to hold command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2 + 1]; /*command line arguments */
pid_t tpid ;
pid_t child_pid;
int child_status;
char path[PATH_MAX+1];
char *progpath = strdup(args[0]);
char *prog = basename(progpath);
char temp[MAX_LINE];
}
It'is compiling well but when i try to run the code it gives me segmentation fault error
How can i fix it and why i take this error?
Your main has a wrong signature. You want
int main(int argsCount, char**args) {
and of course you should remove the internal declaration of argCount & args inside your main.
Perhaps you want instead your args & argCount to contain the parsed arguments of your own shell (but you still have to give a good signature to your main, conventionally and very often int main(int argc, char**argv).... you probably want your shell to accept the -c argument as most shells do, this would ease debugging with simplistic test cases). Then you should initialize them, and you should read some line (probably with getline) in a loop.
As I commented, you should compile with all warnings & debug info:
gcc -Wall -Wextra -g yoursource.c -o yourprog
Then use gdb ./yourprog to debug your program (see GDB documentation). valgrind should also be helpful. Of course, be sure to develop on a Linux system!
BTW, your program is not a convincing start for a shell. Use strace on some existing shell to understand what a shell needs to do. Study the source code of some existing free software shell (e.g. sash, fish, GNU bash ...). Read Advanced Linux Programming
I want to use a pair of Unix FIFOs in such manner that:
a client sends to a server a file name and
the server returns to the client: the number of words, lines and bytes from the given file.
Could you please help?
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
c2s=open("fifo1",O_WRONLY);
s2c=open("fifo2",O_RDONLY);
printf("give file name \n");
scanf("%s",a);
nr=strlen(a);
write(c2s,&nr,sizeof(int));
write(c2s,&a,sizeof(nr));
read(s2c,&c,sizeof(int));
read(s2c,&d,sizeof(int));
read(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
return 0;
}
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
FILE* f;
c2s=open("fifo1",O_RDONLY);
s2c=open("fifo2",O_WRONLY);
read(c2s,&nr,sizeof(int));
read(c2s,&a,sizeof(nr));
f=fopen(a,"r");
if(fork()==0)
{
printf("result is: \n");
execl("/usr/bin/wc","wc",c,d,e,NULL);
}
wait(0);
write(s2c,&c,sizeof(int));
write(s2c,&d,sizeof(int));
write(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
printf("\n FINISH \n");
return 0;
}
I have done some improvements but still it doesn't work properly.
In the fork'ed part of the server, redirect the standard input and output of wc with
dup2(c2s, STDIN_FILENO);
dup2(s2c, STDOUT_FILENO);
Then exec it with
execl("/usr/bin/wc", "wc", NULL);
Don't pass the file descriptors as arguments to execl. It expects strings (char const*), not int.
See dup2 in the POSIX standard to understand how this works.
Note that wc writes strings of characters to its output. You are trying to read them as if they are binary numbers. This will lead to confusion - especially as you do not check that the read calls worked correctly.
Actually, general comment - you should check many more of your system calls.
You also have to ensure that your processes do not block when opening the FIFOs. You should be OK; you have the processes open 'fifo1' for reading and writing, and then 'fifo2'. I think that forces a correct order on things.
You only write 4-letter file names correctly on the pipe.