How to find the value of kernel.shmmax from C code - c

I want to get the value of kernel.shmmax in C code (which I query on centos5.0, centos6.0 and ubuntu10.04 using the shell command "$ sysctl -q kernel.shmmax").
I used the following code to find it:
#include <sys/sysctl.h>
const int SHM_ERROR=1;
main(){
int name[] = {KERN_SHMMAX};
int namelen = 1;
int oldval[1];
size_t oldlen = sizeof(oldval);
int rv = sysctl(name, namelen, (void*) oldval, &oldlen, NULL, 0);
if (rv!=0) {
fprintf(stderr, "while quering for shared memory size, sysctl returned error: %s\n", strerror(errno));
return SHM_ERROR;
}
else{
return 0;
}
}
After running the code above I get the following error:
while quering for shared memory size, sysctl returned error: Not a directory
I am clueless about why I am getting this error. I googled for it and found there is some issue with the paths into which library tries to look into.
I tried running the above code with GDB but the code doesn't steps into the function sysctl, otherwise I could have provided you more information.
Data point:
I am easily able to set and get kernel.shmmax from command line on all the operating systems mentioned using the following commands:
$ sysctl -q kernel.shmmax
$ sysctl -w kernel.shmmax=1000000000
Thanks

You shouldn't be calling sysctl from userspace code. From the man page:
Glibc does not provide a wrapper for this system call; call it using
syscall(2).
Or rather... don't call it: use of this system call has long been
discouraged, and it is so unloved that it is likely to disappear in a
future kernel version. Remove it from your programs now; use the
/proc/sys interface instead.
So give this a shot instead:
#include <stdio.h>
#define SHMMAX_SYS_FILE "/proc/sys/kernel/shmmax"
int main(int argc, char **argv)
{
unsigned int shmmax;
FILE *f = fopen(SHMMAX_SYS_FILE, "r");
if (!f) {
fprintf(stderr, "Failed to open file: `%s'\n", SHMMAX_SYS_FILE);
return 1;
}
if (fscanf(f, "%u", &shmmax) != 1) {
fprintf(stderr, "Failed to read shmmax from file: `%s'\n", SHMMAX_SYS_FILE);
fclose(f);
return 1;
}
fclose(f);
printf("shmmax: %u\n", shmmax);
return 0;
}

I install strace and see that sysctl looks at /proc/sys/kernel/shmmax with open() call instead of _sysctl() call or syscall() call.

Related

Is there a simple way to find the owner of a Process in Unix using C?

I want to be able to check the owner of a process of which I got the ID from using C on a Unix system. It also needs to work on cygwin. Additionally it would be nice to get the date the process was created, too.
I've seen there are ways through looking up the generated files in /proc/<process-id>/. But unfortunately on cygwin you would need the right permissions to read those files.
If possible I am searching for a way without using those files or system commands. I had also found this threat:
How to programatically get uid from pid in osx using c++?
But it won't work due to missing definitions of KERN_PROC, KERN_PROC_PID and some more.
(Have not found the librarys for those in C)
So in short:
Does anyone know how I could get the informations on a specific process using c without needing system calls or reading the files in /proc/?
here under a simple implementation using ps command.
It's certainly not the most elegant but it should work for Unix and Cygwin:
#include <stdio.h>
#include <string.h>
int get_proc_uid(int pid, char *uid, int uid_size)
{
FILE *fp;
int pid_l, ret = -1;
char uid_l[16];
char cmd[64], line[128];
snprintf(cmd, sizeof(cmd), "ps | grep %d", pid);
fp = popen(cmd, "r");
if(fp == NULL)
return ret;
while(fgets(line, sizeof(line), fp) != NULL)
{
if(strstr(line, "grep") == NULL)//filter grep dummy result
{
sscanf(line, "%d %s", &pid_l, uid_l);
if(pid_l == pid)
{
strncpy(uid, uid_l, uid_size);
ret = 0;
break;
}
}
}
pclose(fp);
return ret;
}

Output of the Linux System Call in C program

I want to manipulate the output of the ls -al command in my C program.
Is there a way to do it ?
int main()
{
int return_value;
return_value = system("ls -al ");
return return_value;
}
You need a pipe to the process.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char output[1024];
fp = popen("/bin/ls -al", "r");
if (fp == NULL)
exit(1);
while (fgets(output, 1023, fp) != NULL)
printf("%s", output);
pclose(fp);
return 0;
}
You could use popen(3) on /bin/ls as answered by Baris Demiray.
But in your particular case (getting the files in a directory), you don't really need to start some external process running ls, you could simply use opendir(3) & readdir(3) to read the directory entries, and use stat(2) on each of them (you'll build the path using snprintf(3)). See also glob(7), nftw(3) and read Advanced Linux Programming
Notice that the system(3) is a very poorly named standard C library function. It is not a direct system call (they are listed in syscalls(2)...), but uses fork(2), execve(2), waitpid(2), etc...

how to get the responding result of executing shell command in C?

Update: I tried to print the return value of system(). If ssh failed, it will return 65280, if it succeed ,it returns 0.
I want to ssh to another machine from my laptop,I write a C program, it access to that machine and touch a file on that machine. But sometimes the network is not stable or maybe that machine is down. Therefore, ssh will failed. How could I know the ssh failed in that program ? Sometime ssh to that machine succeed, but touch that file failed, how to distinguish them in the C program? How could I know that shell command failed is because of ssh failed not touch ? I don't want to stare at the screen, I want the program to check that automatically.
here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(int argc,const char *argv[])
{
while(1)
{
system("ssh liulyix#localhost -p 22210 'touch script/rebooter.sh'");
sleep(5);
}
}
Read the man page for system.
The proto type is
int system (constant char *command)
The return values are
-1 system was unable to execute the command because of say a fork failure. Look at the man page for execve and look at the error number which may raised. All these errnos are reasons why system will return -1.
All other returns ed values are the exit code of the command. 0 implies success, all other values imply the command crashed with EXIT_FAILURE.
Using function popen() will be more easy:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(int argc,const char *argv[])
{
FILE *fp;
fp = popen("ssh liulyix#localhost -p 22210 'touch script/rebooter.sh'", "r");
while(1)
{
char *line; char buf[1024];
line = fgets(buf, 1024, fp);
if (line == NULL) break;
printf("%s", line);
}
pclose(fp);
return 0;
}

perror generating unexpected errno value

I am experiencing an unexpected value of errno when using perror with glibc. When an non-existent file is specified as arg[1] it prints Error: 2 ( which isENOENT) as expected. However when the perror line below is uncommented it throws error 22 (EINVAL) no matter what I pass it. Can anyone please explain why this is getting set?
EDIT: Looks like this is some sort of Eclipse bug. The IDE seems to be causing perror to throw some sort of error, the program works perfectly on the command line, and works perfectly when a correct file is specified in the argument list in Eclipse. It fails incorrectly when run inside of Eclipse.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[]) {
FILE *input_file;
input_file = fopen(argv[argc - 1], "r");
if (!input_file) {
// perror(argv[argc-1]);
fprintf(stderr, "Error: %d\n", errno);
return (EXIT_FAILURE);
}
else {
fclose(input_file);
}
return (EXIT_SUCCESS);
}
You can't rely on the value of errno after calling into other library functions, in other words your call to perror() itself may be modifying the value of errno You need to save it in a temporary variable if you want to be able to use it after calls into other library procedures.
if (!input_file) {
int err = errno;
perror(argv[argc-1]);
fprintf(stderr, "Error: %d\n", err);
return (EXIT_FAILURE);
}
Your program works as expected for me here:
$ ./app fkjhsf
Error: 2
and with the perror() call uncommented:
$ ./app asdkfljh
asdkfljh: No such file or directory
Error: 2
Maybe the perror() call is changing your errno for some reason? What operating system/compiler/library versions are you using?
He's likely running the program without any arguments.
If so, "argv[argc - 1]" will evaluate to garbage.
There should be code to make sure that "argc-1" is within a valid range.

detecting loops in symbolic links (c programming)

I'm looking to detect loops in symbolic links in a C program:
$ ln -s self self
$ ln -s a b
$ ln -s b a
Here's what I've got so far:
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct stat buffer;
int status;
if (argc != 2) {
fprintf(stderr, "error: file name required\n");
return 0;
}
errno = 0;
status = lstat(argv[1], &buffer);
if (errno == ELOOP) {
fprintf(stderr, "loop found");
}
return 1;
}
I'm running my program like this:
$ findloops self
$ findloops a
Any idea what I'm doing wrong?
This is NOT homework.
This is where I got the idea from.
The trouble is that 'lstat()' looks at the symlink and its properties, and the symlinks actually exist.
If you replace the call with 'stat()', then you will get the ELOOP error. This tries to get the information at the far end of the symlink, and that cannot be found because of the ELOOP condition.
You should only test errno after you have verified that status indicates a failure. With a genuine system call, it is unlikely that errno would be set when the call succeeds, but with library functions, you can find errno is set even though the call succeeds. For example, with some standard I/O library implementations, you can have errno == ENOTTY even after a successful function call; the code checks whether the file descriptor represents a terminal and errno is set to indicate that it isn't, but since the function succeeded, it is not legitimate to check errno.
I would take a look at the buffer returned. According to the documentation of lstat the buffer contains two items that would be relevant:
st_ino - The inode for the file (note that this number is unique to each distinct file and all directories on a Linux file system, but the same inode number can appear in different file systems).
st_dev - The device that the file currently resides on.
If you create a list containing these two items per element+the directory where the link is located as the previously visited elements, you could detect loops. Also don't forget to pop them off when you leave the directory that they were created in.
I'm not convinced that ELOOP is the value that you think it is. According to this, it identifies the maximum links tolerated in the class path, but it won't tell you which link looped first.
The documentation on the page claimed this: "ELOOP: Too many symbolic links were encountered in translating the pathname. "
ELOOP doesn't have to mean that there is a loop. It can also mean that there are too many symbolic links from source to target, as in
a -> b -> c -> d -> e ... -> z
do this enough times and the OS kernel (particularily for some cases on linux) will give up trying to follow the links, even if they are all valid and non-cyclic.
You may also be interested in man 2 readlink.
After some playing with code, it looks like you've found either a feature or a bug with lstat(2). According to the man page on lstat, which is also stat and fstat, the difference between stat and lstat is:
stat() stats the file pointed to by
path and fills in buf.
lstat() is identical to stat(), except
that if path is a symbolic link, then
the link itself is stat-ed, not the
file that it refers to
I took your program and played with it a little. I used lstat, stat, and fopen to check the link. Code is below. The bottom line is that both stat and fopen detected the link properly, while lstat failed. I have no explanation for this.
The program below, executed on file bar created as 'ln -s bar bar', gave the following output:
./foo ./bar
Errno as returned from lstat = 0
Errno as returned from stat = 92
loop found
Errno as returned from fopen = 92
loop found
Code:
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct stat buffer;
int status;
int savedErrno1;
int savedErrno2;
int savedErrno3;
FILE *theFile;
if (argc != 2) {
printf("error: file name required\n");
return 0;
}
errno = 0;
status = lstat(argv[1], &buffer);
savedErrno1 = errno;
printf("Errno as returned from lstat = %d\n", savedErrno1);
if (savedErrno1 == ELOOP) {
printf("loop found\n");
}
errno = 0;
status = stat(argv[1], &buffer);
savedErrno2 = errno;
printf("Errno as returned from stat = %d\n", savedErrno2);
if (savedErrno2 == ELOOP) {
printf("loop found\n");
}
errno = 0;
theFile = fopen(argv[1], "w");
savedErrno3 = errno;
printf("Errno as returned from fopen = %d\n", savedErrno3);
if (savedErrno3 == ELOOP) {
printf("loop found\n");
}
return 1;
}

Resources