open system call - Linux - c

Trying to open tty port using open system call. HOw do i know if this port is being used by another application in case the open system call returns -1?
DO not find error codes for the same.

a call to open() won't give you an error if the file is already open.
Howerver, you can try to analyze the output of the linux lsofcommand:
lsof /dev/ttyS0
It will return information about the processes that opened the given file (in this case: /dev/ttyS0).
(I've tested this a few times so I'm not sure about it, but lsof seems to return 0 if the file is opened by a process and return 1 if no process has opened it. This could be an indication, however I would suggest you really analyze the output of the command itself)

#include <errno.h>
#include <stdio.h>
#include <strcing.h>
int main()
{
if(open("/dev/ttyS0", O_RDWR))
printf("errno = %s\n", strerror(errno));
return errno;
}
see this link in order to figure out what the error code is.

Related

check if fclose() fails and return specific error

So, I tried to find an answer to this question unsuccessfully.
I know what to do and how to manage such a case - by using fluss/NULL etc. afterward. But checking it is tricky to me.
So, basically:
open some file(successfully) - let's call the pointer: file.
after some code running...
fclose(file);
Now, how can I check after(before it's also an option) closing the file - that it really happened?
What is the condition? By demand, I need to handle this case by printing some specific errors.
You can use the following snippet:
#include <errno.h>
if(fclose(file) != 0)
{
fprintf(stderr, "Error closing file: %s", strerror(errno));
}
From the man pages, we see that an error in closing a file using fclose() sets the global variable errno to a value indicating what error occurred. The function strerror() takes this value of errno and outputs a string to help indicate what the error actually was.

Exec function in c is not returning -1 when it should

I am using an execv function to run a program called code.x.
code.x has a part where it guarantees its failure by Assertion.
My code that runs execl is:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
int main()
{
pid_t pid;
char *args[] = { "./code.x",NULL };
pid = fork();
if (pid > 0) {
wait(NULL);
printf("%s\n", strerror(errno));
printf("done\n");
}
else if (pid == 0) {
printf("%s\n", strerror(errno));
execv(args[0], args);
printf("should fail");
}
else {
printf("forkfail");
}
return 1;
}
the code prints
Success
code.x: code.c:15: main: Assertion '0 == 1' failed.
Success
done
"should fail" is never printed and WEXITSTATUS(status) shows that the exit status is 0.
The exec family of functions replace the calling process with a new program in its initial state loaded from an executable file. They can only fail if this replacement fails, e.g. due to the requested file not existing or the invoking user not having permissions to access/execute it.
If an assertion failure in the program ./code.x you're invoking happens, this is long past the point where execv could have failed; at this point, the original program state where execv was performed no longer exists, because it was already replaced. The parent process will see it exit via a wait-family function, and can inspect the status reported by the wait-family function to determine why it exited.
exec* functions succeed if the program starts running. Your program did start running.
An assertion failure causes the program to abort, exit with a signal. The Linux manual page wait(2) explains that:
WEXITSTATUS(wstatus)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as
the argument for a return statement in main(). This macro should be employed only if WIFEXITED returned true.
If you didn't check that WIFEXITED(status) is true, then WEXITSTATUS(status) is garbage.
Instead, check WIFSIGNALED(status) and if true, get the signal - WTERMSIG(status), which should equal to SIGABRT.
execv successfully did its job. The process ./code.x executed, then exited because of an assertiong.
The exec family of functions don't care about the process's return value. Once the process starts, the calling process is effectively terminated and gone.
Exec will only return if for some reason the process couldn't be started at all. Specifically, only these errors (taken from the man page) will cause exec to return and set errno to one of these values:
E2BIG The total number of bytes in the environment (envp) and argument list (argv) is too large.
EACCES Search permission is denied on a component of the path prefix of filename or the name of a script interpreter. (See also path_resolution(7).)
EACCES The file or a script interpreter is not a regular file.
EACCES Execute permission is denied for the file or a script or ELF interpreter.
EACCES The filesystem is mounted noexec.
EAGAIN (since Linux 3.1)
Having changed its real UID using one of the set*uid() calls, the caller was—and is now still—above its RLIMIT_NPROC resource limit (see
setrlimit(2)). For a more detailed explanation of this error, see NOTES.
EFAULT filename or one of the pointers in the vectors argv or envp points outside your accessible address space.
EINVAL An ELF executable had more than one PT_INTERP segment (i.e., tried to name more than one interpreter).
EIO An I/O error occurred.
EISDIR An ELF interpreter was a directory.
ELIBBAD An ELF interpreter was not in a recognized format.
ELOOP Too many symbolic links were encountered in resolving filename or the name of a script or ELF interpreter.
ELOOP The maximum recursion limit was reached during recursive script interpretation (see "Interpreter scripts", above). Before Linux 3.8, the
error produced for this case was ENOEXEC.
EMFILE The per-process limit on the number of open file descriptors has been reached.
ENAMETOOLONG filename is too long.
ENFILE The system-wide limit on the total number of open files has been reached.
ENOENT The file filename or a script or ELF interpreter does not exist, or a shared library needed for the file or interpreter cannot be found.
ENOEXEC An executable is not in a recognized format, is for the wrong architecture, or has some other format error that means it cannot be executed.
ENOMEM Insufficient kernel memory was available.
ENOTDIR A component of the path prefix of filename or a script or ELF interpreter is not a directory.
EPERM The filesystem is mounted nosuid, the user is not the superuser, and the file has the set-user-ID or set-group-ID bit set.
EPERM The process is being traced, the user is not the superuser and the file has the set-user-ID or set-group-ID bit set.
EPERM A "capability-dumb" applications would not obtain the full set of permitted capabilities granted by the executable file. See capabilities(7).
ETXTBSY The specified executable was open for writing by one or more processes.
The Exec function family replaces the existing process image with a new process image. This is why it is required to fork before spawning another process, because the currently running process is completely replaced, this includes the program counter, which keeps track of the next instruction to execute.
printf("should fail");
is never excecuted because the instant you called execv(args[0], args), the program counter was moved to execute args[0], thus leaving behind the execution path that would have resulted in that print statement.
Exec returns -1 on the condition that it encountered an error while replacing the image, and has absolutely no relation to the return value of the program being executed. This is because the two processes, after Exec is called, are not coordinating with each other at all. Remember: the fork() command created a new address space, which means that these processes are now running in separate domains on separate executables.
Some documentation may be of help:
http://man7.org/linux/man-pages/man3/exec.3.html
Hope this helped.

My open() command is not creating a new file

I am supposed to write a program that creates new files using the open() command, which, everything I read says that it's supposed to do if a file doesn't already exist.
My code is like this:
char startroom[] = "laruee.rooms/startroom.txt";
//...
int file_descriptor;
//...
file_descriptor = open(startroom, O_WRONLY | O_CREAT );
{
fprintf(stderr, "Could not open %s\n", startroom);
perror("in main");
exit(1);
}
However, despite everything I've googled about this command indicating that the file should get created if it doesn't already exist, the file is not getting created. (And also from everything I googled, it appears that I am the only programmer in the universe having this problem.)
What gives?
Your question could be operating-system (and even file-system) specific. I guess you are running on Linux on some usual file-system like Ext4 or BTRFS.
Read open(2) & path_resolution(7). There are several reasons why an open could fail (and we cannot guess which is relevant for your computer).
It might happen that your code is not running in the conditions you want it to (working directory, user id...)
Then, improve your code as:
char startroom[] = "laruee.rooms/startroom.txt";
//...
int file_descriptor = open(startroom, O_WRONLY | O_CREAT );
if (file_descriptor < 0) {
fprintf(stderr, "Could not open %s : %s\n",
startroom, strerror(errno));
char wdbuf[256];
if (getcwd(wdbuf, sizeof(wdbuf))
fprintf(stderr, "in %s\n", wdbuf);
exit(EXIT_FAILURE);
}
When using perror or strerror on errno you don't want any function which might change errno to be called after the failing syscall. On Linux with glibc the fprintf(3) function knows about %m ....
BTW, you could also strace(1) your program
Perhaps look also in your /var/log/syslog or /var/log/messages. Be sure your disk is not full (use df -h and df -i). If you have disk quotas, be sure to not overflow them. Be sure that your program is running in the directory you want it to and that current directory contains a laruee.rooms/ sub-directory; you might get it with getcwd(2) like I did above.
Particularly for server-like programs, you might want to use syslog(3).
You should read Advanced Linux Programming
BTW your open is not a command (that would be xdg-open) but a system call or at least a POSIX function

Start a process in the background in Linux with C

I am trying to do something a little weird here. I need to start a process, logcat, from a deamon that will run in the background and print to the terminal without taking control of stdin. It is for logging so ideally logcat will print log messages while still allowing the user to input standard commands and initialize programs from the shell. Here is the code for the daemon I have so far. The program, logcat, starts and shows log messages but I cannot enter any commands into stdin as it appears that the program has taken control of stdin.
int main ( int argc, char** argv, char** env )
{
int fd;
if ((fd = open("/dev/console", O_RDWR)) < 0) {
fd = open("/dev/null", O_RDWR);
}
printf("THIS IS A TEST\n");
dup2(1, fd);
dup2(2, fd);
pid_t childpid = fork();
if(childpid == -1) {
perror("Failed to fork, logcat not starting");
return 1;
}
if(childpid == 0) {
//this is the child, exec logcat
setsid();
int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
} else {
//this is the parent do nothing
close(fd);
return 0;
}
close(fd);
return 0;
}
Thanks
The 'logcat' command seems to be for Android development - that might explain the odd location of the command.
The key operation that you must fix is to ensure that you close your current standard input (the terminal) and open /dev/null/ for the input device:
close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
...error - failed to open /dev/null!
This means that your daemonized child process will not read anything from the terminal.
What I think you want to do is:
Run your launcher program from a command line, which will have standard input, standard output and standard error connected to 'the terminal'.
Inside your program, you want to replace the standard input so it comes from /dev/null.
You want to leave standard output alone - you want logcat to write to the current standard output.
You probably want to leave standard error alone too.
At some point in the proceedings, you do your daemonization properly (borrowing the link from #bstpierre's answer), making sure that the terminal you are connected to is not your controlling terminal, so that interrupts and hangups sent to the terminal don't affect your daemon. The plumbing is simpler than what you have set up - you should deal with standard input and leave standard output and standard error unchanged (instead of changing the outputs and leaving the input unchanged).
Now, you might want the output to go to /dev/console; if so, then it is reasonable to revise the code to open /dev/console. However, it is not reasonable to fall back on /dev/null if you can't open /dev/console; your program should report an error and fail (because there is no point in having logcat writing to /dev/null!). Make sure you open the console with the O_NOCTTY flag so it does not become the controlling terminal for the daemon.
The final comment I'd make is:
Are you sure you want random text appearing over your terminal or console when it is in use for other things?
I don't much like it when that happens.
See also: SO 958249
How to Daemonize in Linux [dead link]
How to Daemonize in Linux [wayback machine archive of the above]
gist on github -- code taken from link above
Executive summary:
One of the things I keep running across is Linux daemons that don’t properly daemonize themselves. To properly daemonize, the following steps must be followed.
The fork() call is used to create a separate process.
The setsid() call is used to detach the process from the parent (normally a shell).
The file mask should be reset.
The current directory should be changed to something benign.
The standard files (stdin,stdout and stderr) need to be reopened.
Failure to do any of these steps will lead to a daemon process that can misbehave. The typical symptoms are as follows.
Starting the daemon and then logging out will cause the terminal to hang. This is particularly nasty with ssh.
The directory from which the daemon was launched remains locked.
Spurious output appears in the shell from which the daemon was started.
There is special purposed function for this in glibc:
#include <unistd.h>
...
/* We are in the parent, yet */
daemon(0,0);
/* Now we are in the child */
...
More details here http://linux.die.net/man/3/daemon

practical examples use dup or dup2

I know what dup / dup2 does, but I have no idea when it would be used.
Any practical examples?
Thanks.
One example use would be I/O redirection. For this you fork a child process and close the stdin or stdout file descriptors (0 and 1) and then you do a dup() on another filedescriptor of your choice which will now be mapped to the lowest available file descriptor, which is in this case 0 or 1.
Using this you can now exec any child process which is possibly unaware of your application and whenever the child writes on the stdout (or reads from stdin, whatever you configured) the data gets written on the provided filedescriptor instead.
Shells use this to implement commands with pipes, e.g. /bin/ls | more by connecting the stdout of one process to the stdin of the other.
The best scenario to understand dup and dup2 is redirection.
First thing we need to know is that the system has 3 default file ids(or variables indicating output or input sources) that deals with the input and output. They are stdin, stdout, stderr, in integers they are 0,1,2. Most of the functions like fprintf or cout are directly output to stdout.
If we want to redirect the output, one way is give, for example, fprintf function more arguments indicating in and out.
However, there is a more elegant way: we can overwrite the default file ids to make them pointing to the file we want to receive the output. dup and dup2 exactly work in this situation.
Let's start with one simple example now: suppose we want to redirect the output of fprintf to a txt file named "chinaisbetter.txt". First of all we need to open this file
int fw=open("chinaisbetter.txt", O_APPEND|O_WRONLY);
Then we want stdout to point to "chinaisbetter.txt" by using dup function:
dup2(fw,1);
Now stdout(1) points to the descriptor of "chinaisbetter.txt" even though it's still 1, but the output is redirected now.
Then you can use printf as normal, but the results will be in the txt file instead of showing directly on the screen:
printf("Are you kidding me? \n");
PS:
This just gives a intuitive explanation, you may need to check the manpage or detailed information. Actually, we say "copy" here, they are not copying everything.
The file id here is referring to the handler of the file. The file descriptor mentioned above is a struct the records file's information.
When you are curious about POSIX functions, especially those that seem to duplicate themselves, it's generally good to check the standard itself. At the bottom you will usually see examples, as well as reasoning behind the implementation (and existence) of both.
In this case:
The following sections are informative.
Examples
Redirecting Standard Output to a File
The following example closes standard output for the current processes, re-assigns standard output to go to the file referenced by pfd, and closes the original file descriptor to clean up.
#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...
Redirecting Error Messages
The following example redirects messages from stderr to stdout.
#include <unistd.h>
...
dup2(2, 1); // 2-stderr; 1-stdout
...
Application Usage
None.
Rationale
The dup() and dup2() functions are redundant. Their services are also provided by the fcntl() function. They have been included in this volume of IEEE Std 1003.1-2001 primarily for historical reasons, since many existing applications use them.
While the brief code segment shown is very similar in behavior to dup2(), a conforming implementation based on other functions defined in this volume of IEEE Std 1003.1-2001 is significantly more complex. Least obvious is the possible effect of a signal-catching function that could be invoked between steps and allocate or deallocate file descriptors. This could be avoided by blocking signals.
The dup2() function is not marked obsolescent because it presents a type-safe version of functionality provided in a type-unsafe version by fcntl(). It is used in the POSIX Ada binding.
The dup2() function is not intended for use in critical regions as a synchronization mechanism.
In the description of [EBADF], the case of fildes being out of range is covered by the given case of fildes not being valid. The descriptions for fildes and fildes2 are different because the only kind of invalidity that is relevant for fildes2 is whether it is out of range; that is, it does not matter whether fildes2 refers to an open file when the dup2() call is made.
Future Directions
None.
See also
close(), fcntl(), open(), the Base Definitions volume of IEEE Std 1003.1-2001, <unistd.h>
Change History
First released in Issue 1. Derived from Issue 1 of the SVID.
One practical example is redirecting output messages to some other stream like some log file. Here is a sample code for I/O redirection.
Please refer to original post here
#include <stdio.h>
main()
{
int fd;
fpos_t pos;
printf("stdout, ");
fflush(stdout);
fgetpos(stdout, &pos);
fd = dup(fileno(stdout));
freopen("stdout.out", "w", stdout);
f();
fflush(stdout);
dup2(fd, fileno(stdout));
close(fd);
clearerr(stdout);
fsetpos(stdout, &pos); /* for C9X */
printf("stdout again\n");
}
f()
{
printf("stdout in f()");
}
I/O redirection in the shell would most likely be implemented using dup2/fcnlt system calls.
We can easily emulate the $program 2>&1 > logfile.log type of redirection using the dup2 function.
The program below redirects both stdout and stderr .i.e emulates behavior of $program 2>&1 > output using the dup2.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int
main(void){
int close_this_fd;
dup2(close_this_fd = open("output", O_WRONLY), 1);
dup2(1,2);
close(close_this_fd);
fprintf(stdout, "standard output\n");
fprintf(stderr, "standard error\n");
fflush(stdout);
sleep(100); //sleep to examine the filedes in /proc/pid/fd level.
return;
}
vagrant#precise64:/vagrant/advC$ ./a.out
^Z
[2]+ Stopped ./a.out
vagrant#precise64:/vagrant/advC$ cat output
standard error
standard output
vagrant#precise64:/vagrant/advC$ ll /proc/2761/fd
total 0
dr-x------ 2 vagrant vagrant 0 Jun 20 22:07 ./
dr-xr-xr-x 8 vagrant vagrant 0 Jun 20 22:07 ../
lrwx------ 1 vagrant vagrant 64 Jun 20 22:07 0 -> /dev/pts/0
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 1 -> /vagrant/advC/output
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 2 -> /vagrant/advC/output

Resources