how to use settimeofday(2)? - c

What am I doing wrong here? I expect settimeofday() to change the system time, not return EINVAL.
$ uname -a
Linux io 4.3.5-300.fc23.x86_64 #1 SMP Mon Feb 1 03:18:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
$ cat settimeofday.c
#include <sys/time.h>
#include <stdio.h>
int main()
{
struct timeval tv = {0, 0};
if (settimeofday(&tv, 0) == -1)
perror("settimeofday");
}
$ gcc settimeofday.c
$ sudo ./a.out
settimeofday: Invalid argument
The error is coming from a Thinkpad T450 running Fedora 23. The same code runs fine on OS X.
EDIT
To clarify, the command is being executed as root:
# whoami
root
# sudo ./a.out
settimeofday: Invalid argument
As expected, I get EPERM not EINVAL if I run the program as a regular user:
$ ./a.out
settimeofday: Operation not permitted

Commit e1d7ba was introduced to the Linux kernel in mid-2015 and restricts the value of the tv_sec field. The restriction is influenced by system uptime -- see the commit message and related LKML discussion for details.
That's what was causing the settimeofday call to return EINVAL and explains why the code runs on OS X and older Linux machines.

As shown in the manpage of settimeofday().
If either tv or tz is NULL, the corresponding structure is not set or returned.

Related

uname Syscall Missing Operating System String Present in uname -a Output

When I run uname -a on the command line, I get the following output:
Linux raspberrypi 5.10.63-v7l+ #1459 SMP Wed Oct 6 16:41:57 BST 2021 armv7l GNU/Linux
This is achieved by the -a parameter which is equivalent to using these parameters (there are 6) -snrvmo.
I am trying to replicate this using the uname() syscall in C. The manpage says the following about my uname() struct that is returned:
DESCRIPTION
uname() returns system information in the structure pointed to by buf. The utsname struct is de‐
fined in <sys/utsname.h>:
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined
network" */
char release[]; /* Operating system release (e.g., "2.6.28") */
char version[]; /* Operating system version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
You'll notice there is no operating system string corresponding to the the command line uname -o option. uname --help shows there is a -o parameter to display the OS and that doesn't seem to be available in the struct returned by the uname() syscall.
-o, --operating-system
print the operating system
So the best I can seem to do is get the following information using the syscall noting that "GNU/Linux" isn't at the end like what is given by uname -a:
Linux raspberrypi 5.10.63-v7l+ #1459 SMP Wed Oct 6 16:41:57 BST 2021 armv7l
Is there a way I can get the OS name (in this case, "GNU/Linux") in my C program like I can using uname -o?
My source code is essentially this
You can read the uname code here: https://github.com/MaiZure/coreutils-8.3/blob/master/src/uname.c
In that code, is written:
if (toprint
& (PRINT_KERNEL_NAME | PRINT_NODENAME | PRINT_KERNEL_RELEASE
| PRINT_KERNEL_VERSION | PRINT_MACHINE))
{
struct utsname name;
if (uname (&name) == -1)
die (EXIT_FAILURE, errno, _("cannot get system name"));
if (toprint & PRINT_KERNEL_NAME)
print_element (name.sysname);
if (toprint & PRINT_NODENAME)
print_element (name.nodename);
if (toprint & PRINT_KERNEL_RELEASE)
print_element (name.release);
if (toprint & PRINT_KERNEL_VERSION)
print_element (name.version);
if (toprint & PRINT_MACHINE)
print_element (name.machine);
}
We can understand that in that word: "If have to print kernel info, or node or machine, use uname syscall".
The Operating system is printed latter:
if (toprint & PRINT_OPERATING_SYSTEM)
print_element (HOST_OPERATING_SYSTEM);
The HOST_OPERATING_SYSTEM is defined in gnulib
Is there a way I can get the OS name (in this case, "GNU/Linux") in my C program like I can using uname -o?
Since one compiled software can only be used by one OS, you can imagine to set it at build time.

Why can't I read /proc/pid/mem when I have read permission?

I would like to read the content of the memory file associated to one of my process (with PID 2614). I started to write a very small C program to check I can open it:
#include <stdio.h>
#include <errno.h>
int main() {
FILE* f = fopen("/proc/2614/mem", "rb");
if(!f) {
printf("Error %d\n", errno);
return -1;
}
fclose(f);
return 0;
}
When I run it I get a permission denied error:
$ gcc -o read read.c && ./read
Error 13
However, I have read permission:
$ whoami
pierre
$ ll /proc/2614/mem
-rw------- 1 pierre pierre 0 août 18 19:44 /proc/2614/mem
What's going on?
I know it is possible to read the file because I am able to do it on another system (and some other SO answers already did that). Here is information about my system:
$ uname -a
Linux pierre-computer 4.15.0-112-generic #113~16.04.1-Ubuntu SMP Fri Jul 10 04:37:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
And the information for the system on which I can read it:
$ uname -a
Linux not-pierre-computer 3.2.0-4-686-pae #1 SMP Debian 3.2.89-2 i686 GNU/Linux
Are there restrictions on some systems?

Why does calling the timeout program from a bash script cause tcsetattr to hang?

For some reason calling the timeout program, giving the program which has tcsetattr inside as an argument, from a bash script causes tcsetattr to hang. Calling it outside of the bash script directly in the terminal doesn't cause it to hang. Why does this happen? Looking at https://github.com/coreutils/coreutils/blob/master/src/timeout.c, it doesn't seem like timeout messes with any file descriptors. It looks like it is set up to ignore two signals but that shouldn't be relevant here.
The following is a minimal test case:
short.c
#include <stdio.h>
#include <termios.h>
#include <string.h>
int main() {
struct termios tty;
tcgetattr(0, &tty);
fprintf(stderr, "Before tcsetattr");
tcsetattr(0, TCSANOW, &tty);
fprintf(stderr, "After tcsetattr");
}
simple_check.sh
#!/bin/bash
timeout 5 ./a.out < /dev/tty
echo $?
Bash output
$ gcc short.c
$ bash simple_check.sh
Before tcsetattr
124 # Note this should output `After tcsetattr` if it was 'working'
$ timeout 5 ./a.out < /dev/tty
Before tcsetattr
After tcsetattr
Potentially useful information
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.1 LTS
Release: 16.04
Codename: xenial
The --foreground option to timeout might avoid this issue?
That stops putting the timeout (and children) into their own program group.

Why unshare(CLONE_NEWUSER) return error? (linux)

This is my fairly simple code:
#define _GNU_SOURCE
#include <sched.h>
#include <errno.h>
#include <stdio.h>
int main(){
int res= unshare(CLONE_NEWUSER);
printf("res:%d\n",res);
perror("error");
return 0;
}
Why does the code always fail (return -1)?
I'm on Ubunto 13.04 this is my kernel version and other details:
Linux ubuntu 3.10.37-031037-generic #201404141035 SMP Mon Apr 14 14:55:40 UTC 2014 i686 i686 i686 GNU/Linux
errno returns Invalid argument
this is the output of the program :
res:-1
error: Invalid argument
Most likely because your kernel is not configured to support CONFIG_USER_NS.
I reckon running the command:
unshare -U
also produces the same error on your machine.
You can verify that with the command:
grep CONFIG_USER_NS /boot/config-$(uname -r)

How can I know the bit count of a cpu/os in C

I know how to get the bit count of a cpu or an operation system with shell.
cat /proc/cpuinfo | grep lm #-> get bit count of a cpu
uname -a #-> get bit count of an operation system
However, how can we get the bit count of those in a C program.
This is an interview question and my solution is as follow:
int *ptr;
printf("%d\n", sizeof(ptr)*8);
But the interviewer said that was wrong. So, what is the correct answer?
POSIX provides a C function uname as well. You can get similar result like the shell command uname:
#include <stdio.h>
#include <sys/utsname.h>
int main(){
struct utsname buf;
uname(&buf);
printf("sysname: %s\nversion: %s\nmachine: %s\n ", buf.sysname, buf.version, buf.machine);
return 0;
}
Output on my machine:
sysname: Linux
version: #1 SMP Tue Oct 2 22:01:37 EDT 2012
machine: i686
On Linux, a simple way is to do e.g. popen with the uname -m command and parse the output.
Another way is to look at the source for the uname command (as it's readily available) and implement something based on that directly.

Resources