How to get PID_MAX macro? - c

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;
}

Related

Getting random junk output from my simple syscall test

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.

Is SCHED_DEADLINE officially supported in Ubuntu 16.04?

Currently I'm running Ubuntu 16.04 with linux kernel version to be 4.16. I wrote a dummy program that changes its scheduler to SCHED_DEADLINE. But when I tried to compile it, it cannot find definition of structs and macros needed for SCHED_DEADLINE. Most of the code snippet was taken from here (page 24). Below is the test program:
#define _GNU_SOURCE
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
int main(int argc, char* argv[]) {
struct sched_attr attr;
attr.size = sizeof(attr);
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 30000000;
attr.sched_period = 100000000;
attr.sched_deadline = attr.sched_period;
if (sched_setattr(gettid(), &attr, 0))
perror("sched_setattr()");
return 0;
}
Here's the output of the compilation:
sched_deadline.c: In function ‘main’:
sched_deadline.c:11:20: error: storage size of ‘attr’ isn’t known
struct sched_attr attr;
^
sched_deadline.c:12:21: error: invalid application of ‘sizeof’ to incomplete type ‘struct attr’
attr.size = sizeof(struct attr);
^
sched_deadline.c:13:22: error: ‘SCHED_DEADLINE’ undeclared (first use in this function)
attr.sched_policy = SCHED_DEADLINE;
My gcc version:
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
However, the sample code posted in the official website works for me, but the sample code manually defines all the needed macros and system calls in the program. My goal was to compile the application without adding those definitions, which should already be included in the newest kernel version. I have seen various places saying that SCHED_DEADLINE is officially supported after Linux 3.14.10, and upgrading the kernel would automatically solve this issue.
Things I've tried:
Recompiling 4.16 kernel. Previously I thought I need to turn on a switch in config file, but I was not able to find it.
Look into /usr/include/linux/sched.h. Clearly the macros are defined in this header file, but somehow my compiler cannot find it.
I also looked into other posts in the community, but all those questions are for older linux (pre 3.14.10).
You need to include #include <linux/sched.h>
But for the definition of sched_setattr() and gettid(), see the link posted by #CraigEstey
The reason about that, it that glibc will not add function wrappers of linux specific syscall.
For example for gettid(), in the manual we can read this:
Note: There is no glibc wrapper for this system call; see NOTES.
Glibc does not provide a wrapper for this system call; call it using
syscall(2).
The thread ID returned by this call is not the same thing as a POSIX thread ID
Have a look at this article: https://lwn.net/Articles/711058/
#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sched.h>
#include <linux/sched.h>
#include <sys/types.h>
struct sched_attr {
uint32_t size;
uint32_t sched_policy;
uint64_t sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
int32_t sched_nice;
/* SCHED_FIFO, SCHED_RR */
uint32_t sched_priority;
/* SCHED_DEADLINE (nsec) */
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
};
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int main(int argc, char* argv[]) {
struct sched_attr attr = {
.size = sizeof(attr),
.sched_policy = SCHED_DEADLINE,
.sched_runtime = 30000000,
.sched_period = 100000000,
.sched_deadline = 100000000
};
pid_t tid = syscall(SYS_gettid);
if (sched_setattr(tid, &attr, 0))
perror("sched_setattr()");
return 0;
}
Or a more shorter code, without the redefinition of struct sched_attr
#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/sched/types.h>
#include <linux/sched.h>
#include <sys/types.h>
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int main(int argc, char* argv[]) {
struct sched_attr attr = {
.size = sizeof(attr),
.sched_policy = SCHED_DEADLINE,
.sched_runtime = 30000000,
.sched_period = 100000000,
.sched_deadline = 100000000
};
pid_t tid = syscall(SYS_gettid);
if (sched_setattr(tid, &attr, 0))
perror("sched_setattr()");
return 0;
}
But this needs to be executed as root, otherwise I got sched_setattr(): Operation not permitted
Or the application needs to have the right linux capabilities.

Build against newer linux headers than libc is built using

I want to write a program using the new SCHED_DEADLINE scheduling policy available since Linux 3.14.
I start out with a simple program trying to use the sched_setattr function.
#include <sched.h>
int main(void)
{
// struct sched_attr attr;
// attr.size = sizeof(struct sched_attr);
// attr.sched_policy = SCHED_DEADLINE;
sched_setattr(0, (void*)0, 0);
return 0;
}
However when compiling I get the following error:
$gcc dead.c
dead.c: In function ‘main’:
dead.c:8:2: warning: implicit declaration of function ‘sched_setattr’ [-Wimplicit-function-declaration]
sched_setattr(0, (void*)0, 0);
^~~~~~~~~~~~~
/tmp/ccGxWxZE.o: In function `main':
dead.c:(.text+0x19): undefined reference to `sched_setattr'
collect2: error: ld returned 1 exit status
My system is running Ubuntu 16.10 Yakkety, with kernel 4.8.0-59-generic. The sched.h file included is found in /usr/include/sched.h and is provided by the package libc6-dev. This headerfile does not contain the function sched_setattr and friends that I am trying to use.
However the kernel (and kernel headers) I have installed comes with a sched.h header file containing the definitions I need. It is located at /usr/src/linux-headers-4.8.0-58/include/linux/sched.h, on my system.
So I naively think lets just build against the newer linux headers instead of the libc6-dev provided headers. My program will only run on this or newer kernels, but that is just fine.
I modify the first line to be: #include <linux/sched.h> and execute:
gcc -I/usr/src/linux-headers-$(uname -r)/include -I/usr/src/linux-headers-$(unam -r)/arch/x86/include dead.c
Now I am getting page after page of errors and warning. This does not seem the way to go.
What is the correct way to build a userspace program against a newer Linux headers than those that are provided by libc?
And subsequently how do I build the program above?
sched_setattr() is a syscall and doesn't seem to have one-to-one libc wrapper. You could do the wrapper yourself, something like this:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <linux/sched.h>
#include <sys/syscall.h>
#include <sys/types.h>
struct sched_attr {
uint32_t size; /* Size of this structure */
uint32_t sched_policy; /* Policy (SCHED_*) */
uint64_t sched_flags; /* Flags */
int32_t sched_nice; /* Nice value (SCHED_OTHER, SCHED_BATCH) */
uint32_t sched_priority; /* Static priority (SCHED_FIFO, SCHED_RR) */
/* Remaining fields are for SCHED_DEADLINE */
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
};
static int sched_setattr (pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
return syscall (SYS_sched_setattr, pid, attr, flags);
}
int main (int argc, char *argv[])
{
struct sched_attr attr;
int res;
memset (&attr, 0, sizeof (struct sched_attr));
attr.size = sizeof (struct sched_attr);
res = sched_setattr (getpid (), &attr, 0);
if (res < 0) {
perror ("sched_setattr");
return 1;
}
return 0;
}
Looking at the errors reported when trying to include kernel header files required to get the definition of struct sched_attr and reading the comments found by Googling "kernel headers in user space", I really can't suggest trying to include kernel header files just for this.

Problems calling syscall function in C

For a homework assignment, I have to modify the linux kernel.
I am working on a virtual machine, and I added a system call to the kernel, which I called get_unique_id. Here is the code for get_unique_id.c :
#include <linux/linkage.h>
#include <asm/uaccess.h>
asmlinkage long sys_get_unique_id(int * uuid)
{
// static because we want its state to persist between calls
static int uid = 0;
++uid;
// assign new uid value to user-provided mem location
// returns non-zero if success or -EFAULT otherwise
int ret = put_user(uid, uuid);
return ret;
}
I also added this line to syscalls.h :
asmlinkage long sys_get_unique_id(int * uuid);
This line to syscall_32.tbl :
383 i386 get_unique_id sys_get_unique_id
And finally this line to syscall_64.tbl :
548 common get_unique_id sys_get_unique_id
After recompiling and reloading the kernel, I wrote a little C program to test my system call, here is the code for the C test file :
// get_unique_id_test.c
#include <stdio.h>
#include <limits.h>
#include "syscalls_test.h"
int main(void)
{
// initialize the ints we want
int id1;
int id2;
// check the id's are unique and that no error occured
for (int i = INT_MIN; i < INT_MAX - 1; i += 2) {
long ret1 = get_unique_id(&id1);
long ret2 = get_unique_id(&id2);
if (ret1 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret1);
if (ret2 != 0)
printf("ERROR: get_unique_id returned: %ld\n", ret2);
if (id2 != id1 + 1)
printf("ERROR: successive id's did not increment properly: id1 = %d, id2 = %d\n", id1, id2);
}
return 0;
}
And its header file :
// syscalls_test.h
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#define __NR_get_unique_id 383
inline long get_unique_id(int * uuid)
{
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
}
Unfortunately, while trying to compile the C test file with the following command : gcc -std=c99 get_unique_id_test.c -o get_unique_id_test, I get the following error :
In file included from get_unique_id_test.c:4:0:
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
syscalls_test.h: In function ‘get_unique_id’:
syscalls_test.h:10:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration]
return syscall(__NR_get_unique_id, uuid) ? errno : 0;
^
/tmp/cc1euZ3r.o: In function `main':
get_unique_id_test.c:(.text+0x22): undefined reference to `get_unique_id'
get_unique_id_test.c:(.text+0x34): undefined reference to `get_unique_id'
collect2: error: ld returned 1 exit status
It appears gcc cannot find the function get_unique_id(int * uuid), which is declared in syscalls_test.h, and the syscall function, which should be declared, I believe, in syscall.h, right ?
I don't understand why this happens. Does anybody have an idea ?
EDIT : my problems were solved using a3f's solution (see below) PLUS moving the #include "syscalls_test.h" at the very top of the file, as he said in the comments. Thank you very much.
#define _GNU_SOURCE before including unistd.h or any other header as syscall(2) is not POSIX.
Use static inline instead of plain inline. Plain inline supplies an inline definition, but the compiler is free to ignore it and use the external definition instead, which you aren't providing.
Try the following one:
#include <unistd.h>

write() returns -1 when writing to I2C_SLAVE device

I've read through the Linux kernel documents on i2c and written a code to try to replicate the command i2cset -y 0 0x60 0x05 0xff
The code that I've written is here:
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <string.h>
int main(){
int file;
file = open("/dev/i2c-0", O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x60;
if(ioctl(file, I2C_SLAVE, addr) < 0){
exit(1);
}
__u8 reg = 0x05;
__u8 res;
__u8 data = 0xff;
int written = write(file, &reg, 1);
printf("write returned %d\n", written);
written = write(file, &data, 1);
printf("write returned %d\n", written);
}
When I compile and run this code I get:
write returned -1
write returned -1
I've tried to follow exactly what the docs tell me, my understanding is that the address is set first with the call to ioctl, then I need to write() the register and then the data that I want sent to the register.
I've also tried to use use SMbus, but I can't get my code to compile using this, it complains at the linking stage that it can't find the functions.
Have I made any mistakes in this code? I'm a beginner to i2c and don't have a lot of experience with c either.
EDIT: errno give the following message: Operation not supported. I am logged in as root on this machine though, so I don't think it can be a permissions thing, although I may be wrong.
The way I got around this problem was to use SMBus, in particular the functions i2c_smbus_write_byte_data and i2c_smbus_read_byte_data. I was able to use these functions to successfully read and write to the device.
I did have a little trouble finding these functions, I kept trying to download libraries using apt-get to install the appropriate header files. In the end I simply downloaded the files smbus.c and smbus.h.
Then the code I needed was:
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "smbus.h"
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
int main(){
int file;
file = open("/dev/i2c-0", O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x60;
if(ioctl(file, I2C_SLAVE, addr) < 0){
exit(1);
}
__u8 reg = 0x05; /* Device register to access */
__s32 res;
res = i2c_smbus_write_byte_data(file, reg, 0xff);
close(file);
}
Then if I compile the smbus.c file: gcc -c smbus.c and myfile: gcc -c myfile.c, then link them: gcc smbus.o myfile.o -o myexe I get a working executable that runs my I2C command. Ofcourse, I have smbus.c and smbus.h in the same directory as myfile.c.
In C, you can check the content of the errno variable to get more details into what went wrong. It is automatically declared when including errno.h and you can get a more descriptive text by calling strerror(errno).
Have you checked that you had write access to /dev/i2c-0 ?

Resources