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
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.
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?
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.
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)
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.