errno, strerror and Linux system calls - c

I can use strerror() to get text representation of errno value after using CRT functions, like fopen(). If I use open() Linux system call instead of CRT function, it also sets errno value when it fails. Is this correct to apply strerror() to this errno value? If not, is there some Linux system call, which does the same as strerror()?

Yes, and your code might be something like (untested) this:
#include <stdio.h>
#include <errno.h>
#include <string.h> // declares: char *strerror(int errnum);
FILE *
my_fopen ( char *path_to_file, char *mode ) {
FILE *fp;
char *errmsg;
if ( fp = fopen( path_to_file, mode )) {
errmsg = strerror( errno ); // fopen( ) failed, fp is set to NULL
printf( "%s %s\n", errmsg, path_to_file );
}
else { // fopen( ) succeeded
...
}
return fp; // return NULL (failed) or open file * on success
}

Yes
Yes
In there is perror
if (-1 == open(....))
{
perror("Could not open input file");
exit(255)
}

Most of the Linux system calls are encapsulated by C library routines. open() system call is actually a function defined in the C library which calls the actual open() system call of the kernel.
errno is a variable defined and managed by the C library, not by the kernel. It is set upon the return of the system call with the error code returned by the kernel.
As an example, in the GNU C library, open() is defined in sysdeps/unix/sysv/linux/open.c as:
int
__libc_open (const char *file, int oflag, ...)
{
int mode = 0;
if (__OPEN_NEEDS_MODE (oflag))
{
va_list arg;
va_start (arg, oflag);
mode = va_arg (arg, int);
va_end (arg);
}
return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag, mode);
}
libc_hidden_def (__libc_open)
weak_alias (__libc_open, __open)
libc_hidden_weak (__open)
weak_alias (__libc_open, open)
The bottom macros establish a equivalence between __libc_open() and open().
The SYSCALL_CANCEL() macros invokes the actual system call (which is openat()) and sets errno with the error code if any error condition occured.

Related

Can I use read from unistd.h to read from file into a struct?

I am trying to do two things: read from a file descriptor into a struct and then I need to read into a memory location. For the first, I am using fread. For the second I am using read from unistd.h.
Is there anyway I can do both without needing to fopen, fclose, open, close and repeating like this? Am I able to use "read" to read into a struct?
After calling fopen(), you may get the file descriptor of a file pointer via fileno(), like this:
int fd;
fd = fileno (fp);
Then you may use read directly. Indeed, both fopen() and open() opens a file for a process, the former returns a pointer to the file while the latter returns the file descriptor. The FILE type is just a struct which has a field that records the underlying file descriptor.
In other words, on unix-like systems, fopen() is implemented using open(), so there must be a way to use both calls simultaneously.
As a note, on my system (wsl2), the definition of FILE can be found under the path /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h, which looks something like this:
struct _IO_FILE
{
/* ... */
int _fileno;
/* ... */
};
Yes, of course you can read data (here a string) into a struct:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define DATA_LEN 1024
struct s {
char data[DATA_LEN];
};
int main() {
int fd = open("1.c", O_RDONLY);
if(fd == -1) {
perror("file");
return 1;
}
struct s s;
ssize_t n = read(fd, s.data, DATA_LEN);
printf("%.*s\n", (int) n, s.data);
close(fd);
}
Re: Is there anyway I can do both without needing to fopen, fclose,
open, close and repeating like this?
Yes. You can obtain a file descriptor corresponding to the FILE * with fileno(). From the man page:
The function fileno() examines the argument stream and returns
the integer file descriptor used to implement this stream. The
file descriptor is still owned by stream and will be closed when
fclose(3) is called.
As an example:
/**
* #brief Opens the file whose name is the string pointed to
* by file_name and associates a stream with it.
* #return A file descriptor corresponding to the stream on success,
* -1 elsewise.
*/
static int open_sesame (FILE *stream, const char *file_name)
{
stream = fopen (file_name, "r");
if (!stream) {
perror ("fopen()");
/* Handle error here */
return -1;
}
/* On failure, -1 is returned and errno is set to indicate
* the error.
*/
int fd = fileno (stream);
if (fd == -1) {
perror ("fileno()");
/* Handle error here */
return -1;
}
return fd;
}
This too will do:
/* read() will return -1 and set errno to EBADF¹
* if fileno() fails.
*/
if (read (fileno (fp), ..., ..., ...) == -1) {
perror ("read()");
/* Handle error here */
}
On the other hand, if you want to open a stream for a corresponding file descriptor, then there's fdopen(). From the man page:
The fdopen() function shall associate a stream with a file
descriptor.
A sample call:
/* Upon successful completion, fdopen() shall return
* a pointer to a stream; otherwise, a null pointer
* shall be returned and errno set to indicate the
* error.
*/
FILE *stream = fdopen (fd, "r");
if (!stream) {
perror ("fdopen()");
/* Handle error here */
}
Alternatively, as #Fe203 suggested, if you require two copies of the data, you can use the standard memcpy() instead of reading from the file twice. Or as you're already using POSIX system calls, it might be more efficient to map the file into memory with mmap() and work with it.
[1] — EBADF: fd is not a valid file descriptor or is not open for reading.

How to write a program for input and output redirection wc < f1.txt > f2.txt in c

I was trying something like this but got stuck and don't know in which direction to proceed. I even tried using fork() and then assigning the task separately to child and parent but the redirection in that case in not working as intended.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
execlp("cat","<","f1.txt",">","f2.txt",NULL);
return 0;
}
In Linux and other POSIXy operating systems, standard input corresponds to file descriptor 0 (STDIN_FILENO), standard output to file descriptor 1 (STDOUT_FILENO), and standard error to file descriptor 2 (STDERR_FILENO).
Standard file handles stdin, stdout, and stderr are the standard C abstraction, and in Linux are implemented on top of those file descriptors.
To redirect standard input, output, or error, first you need to get an open file descriptor to whatever you want to redirect from/to. In the case of files, you do this via the open() function, which returns the file descriptor number. Then, you use the dup2() function to duplicate (copy) that to the descriptor you want.
Consider the following example.c:
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
/* Duplicate oldfd to newfd, and close oldfd.
In error cases, tries to close both descriptors.
Returns 0 if success, error code (with errno set) otherwise.
*/
static inline int move_descriptor(int oldfd, int newfd)
{
if (oldfd == -1 || newfd == -1) {
if (oldfd != -1)
close(oldfd);
if (newfd != -1)
close(newfd);
return errno = EBADF;
}
if (oldfd == newfd)
return 0;
if (dup2(oldfd, newfd) == -1) {
const int saved_errno = errno;
close(oldfd);
close(newfd);
return errno = saved_errno;
}
if (close(oldfd) == -1) {
const int saved_errno = errno;
close(newfd);
return errno = saved_errno;
}
return 0;
}
/* Write a message to standard error, keeping errno unchanged.
This is async-signal safe.
Returns 0 if success, error code otherwise.
*/
static inline int wrerr(const char *msg)
{
const char *end = (msg) ? msg + strlen(msg) : msg;
if (end == msg)
return 0;
const int saved_errno = errno;
while (msg < end) {
ssize_t n = write(STDERR_FILENO, msg, (size_t)(end - msg));
if (n > 0) {
msg += n;
} else
if (n != -1) {
errno = saved_errno;
return EIO;
} else
if (errno != EINTR) {
const int retval = errno;
errno = saved_errno;
return retval;
}
}
errno = saved_errno;
return 0;
}
static inline void errormessage(const char *name, const char *cause)
{
wrerr(name);
wrerr(": ");
wrerr(cause);
wrerr(".\n");
}
int main(int argc, char *argv[])
{
int fd;
if (argc < 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
wrerr("\n");
wrerr("Usage: "); wrerr(arg0); wrerr(" [ -h | --help ]\n");
wrerr(" "); wrerr(arg0); wrerr(" INPUT OUTPUT COMMAND [ ARGUMENTS ... ]\n");
wrerr("\n");
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY | O_NOCTTY);
if (fd == -1) {
errormessage(argv[1], strerror(errno));
return EXIT_FAILURE;
}
if (move_descriptor(fd, STDIN_FILENO)) {
errormessage(argv[1], strerror(errno));
return EXIT_FAILURE;
}
fd = open(argv[2], O_WRONLY | O_CREAT, 0666);
if (fd == -1) {
errormessage(argv[2], strerror(errno));
return EXIT_FAILURE;
}
if (move_descriptor(fd, STDOUT_FILENO)) {
errormessage(argv[2], strerror(errno));
return EXIT_FAILURE;
}
if (strchr(argv[3], '/'))
execv(argv[3], (char *const *)(argv + 3));
else
execvp(argv[3], (char *const *)(argv + 3));
errormessage(argv[3], strerror(errno));
return EXIT_FAILURE;
}
The move_descriptor() is just a wrapper around dup2() and close(). I included it to show how to do the descriptor moving (copying and closing the old one) safely; with sufficient error checking.
The wrerr(msg) function is analogous to fputs(msg, stderr), except that it uses the file descriptor interface (write()) directly, bypassing the C stderr stream abstraction completely. It is also async-signal safe*, meaning you can use it inside signal handlers.
*: Technically, one could argue whether strlen() is async-signal safe or not. In Linux using glibc, newlibc, or avr-libc, it is.
Many Linux/Unix/POSIXy error messages use format "filename: Error message." Since the wrerr() function takes only one parameter, I included the errormessage(filename, message) helper function to print such error messages. This kind of splitting commonly used tasks to helper functions makes the code easier to read, and easier to maintain too.
The program itself takes at least four command-line arguments. (The first argument, argv[0], is the command itself. The first parameter is argv[1]. For example, if you compile and ran this as ./example arg1 arg2 arg3, then argv[0]=="./example", argv[1]=="arg1", argv[2]=="arg2", and argv[3]=="arg3". In Linux and POSIXy systems, argv[argc] == NULL, so we can use the argv array directly in execv() and execvp() and related functions.
If there are fewer than four command-line parameters, or if argv[1] matches "-h" or "--h", we print usage and exit.
Otherwise, the first parameter (argv[1]) names the file we redirect input from (and it must exist), and the second parameter (argv[2]) the file we redirect output to (which we'll create if it does not exist yet).
The O_NOCTTY flag may look confusing at first, but I included it, because it is so common when redirecting input from file-like objects. It basically means that even if the pathname refers to a terminal, don't do any terminal and session related magic when opening it: "if it is a terminal, and we don't happen to have a controlling terminal, don't make it our controlling terminal". (It only affects programs run in a new session (via setsid) or by services like cron, udev, et cetera, since programs you normally run from a terminal have that terminal as their controlling terminal. The main thing about terminals and sessions is that if the controlling terminal gets closed, each process having that terminal as their controlling terminal will receive a hangup (SIGHUP) signal.)
When opening the file we redirect output to, we use O_CREAT flag, and add an extra parameter, the file access mode. The leading zero means that 0666 is an octal constant, i.e. base-8, and refers to decimal value 6·82 + 6·81 + 6·80 = 438. It is the standard value that you see most often used. It is modified (by the kernel) by the current umask (whose value you can see in the shell by running umask). It is written in octal because then the third digit from right specifies the owner (user) rights, second from right the group rights, and the rightmost the rights for everyone else; 1 being read access, 2 being write access, and 4 being execute (for files) or pass through/work in (for directories). (Each file has an owner (user) and group in Linux, as they do in all Unix and POSIXy systems.)
Whenever open() flags include O_CREAT, the additional access mode value must be supplied. It will almost always be 0666, except for some rare cases where you want to use a more restrictive value; but the general rule is to use 0666 and let the user make it more restrictive if they want by modifying their umask: that is what just about all utilities do anyway.
The third command line parameter (fourth argument, argv[3]), contains the name or path to the executable we'll run. If it contains a slash (/), we assume it is a pathname reference, and use execv(). If it does not contain a slash, we assume it is a name, and use execvp(), which uses the PATH environment variable to look for an executable with that name.
If the exec succeeds, the process is replaced with the new program; the execution ends at the exec.
If the exec fails for any reason, both execv() and execvp() will set errno. It makes sense to print the command (without any arguments, if there were any), and the error message, and exit with failure in that case.
AFAIK, redirection is a shell feature.
I don't see what you are trying to do. But to achieve what you are trying, you need to run
sh -c 'cat < f1.txt > f2.txt'
in the exec format. (I am not familiar with the exec format in C)
You can use bash instead of sh. The -c flag takes a string argument — called command string, and executes it.
My guess of the exec format would be:
execlp( "sh", "-c", " 'cat < f1.txt > f2.txt' ", NULL);
Note the third argument to the function is enclosed in two sets of quotes " '...' ". This is a requirement. Else the shell's space splitting will break it and pass only cat as the command string.

getting undefined behavior in counting characters of text file program?

I wrote a c program meant to count the characters in a certain file.
int main(void) {
FILE *fp;
fp = fopen("txt.txt", "r");
char text;
int count;
while (fscanf(fp, "%c", &text) != EOF) {
count++;
}
printf("%d", count);
return 0;
}
I want to add a char array into it but for some reason it changes the value of my int type (count).
for example, if I run this program I get an output of 3549. Now, lets say I declare "char potato[5000]" alongside my other char type. For some reason I get a completely different output of 159062601. Why is this and how do I prevent that?
The following proposed code:
initializes variables before using them (your compiler should have told you about this problem.
properly checks and handles I/O errors for fopen() and for fscanf()
properly closes the open file before exiting. I.E. it cleans up after itself
properly terminates printed text, so it is immediately passed to the terminal
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("txt.txt", "r");
if( ! fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
char text;
int count = 0;
while ( fscanf( fp, "%c", &text ) == 1 )
{
count++;
}
fclose( fp );
printf( "%d\n", count );
return 0;
}
You have several problems in your code. i will list them below:
In c programming we declare variables in the scope begin. and initialize them if we need so. you have a mixture of declerations and code.
count variable non initialized!! you have entered the while loop with garbage value in count. UB (Undefined behavior) - in each run you will get different values.
you didnt check the return value of fopen !! you must check if the operating system succed in opening the file you have requested to manipulate.
regarding asking a question in stackoverflow, your code is not complete and you didnt post all of it.
Now lets try to learn new topics regarding working with IO streams.
return value of function fscanf
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and errno
is set indicate the error.
This is how check if errors ocured while working with the file we are reading:
int ferror(FILE *stream);
The function ferror() tests the error indicator for the stream pointed
to by stream, returning nonzero if it is set. The error indicator can
only be reset by the clearerr() function.
And in this function bellow we get a human readble error, not just an errnor number!
explain_ferror
const char *explain_ferror(FILE *fp);
The explain_ferror function is used to obtain an explanation of an
error returned by the ferror(3) system call. The least the message
will contain is the value of strerror(errno), but usually it will do
much better, and indicate the underlying cause in more detail.
The errno global variable will be used to obtain the error value to be
decoded.
#include <stdlib.h>
#include <stdio.h>
#include <libexplain/ferror.h> /* for the non standard const char* explain_ferror(FILE* fp); */
int main(void)
{
FILE *fp;
char text;
int count = 0;
fp = fopen("txt.txt", "r");
if(fp == NULL)
{
perror("fopen failed"); /*write to standard error*/
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", explain_ferror(fp));
exit(EXIT_FAILURE);
}
printf("%d", count);
return 0;
}
Since the const char *explain_ferror(FILE *fp); is not GNU standard function, i am posting a GNU standard functions in the code snippet below:
char *strerror(int errnum);
strerror is standard library c function which returns a pointer to a string that describes the error code passed in the argument errnum. Be aware that this function is not Thread safe. for thread safe function use The strerror_r().
Return Value
The strerror(), function return the appropriate error description string, or an "Unknown error nnn" message if the error number is unknown.
Since POSIX.1-2001 and POSIX.1-2008 requires that a successful call to strerror() shall leave errno unchanged, and note that, since no function return value is reserved to indicate an error, if we wishe to check for errors we should initialize errno to zero before the call (by calling void clearerr(FILE *stream);, and then check errno after the call.
#include <string.h>
#include <errno.h>
#include <stdio.h>
...
clearerr(fp); /* clear previous seted errno */
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
...
Finally:
man pages (or man7) or typing man <enter_string_here> in terminal on linux shall clear all the q.marks.
for further reading go to:
explain_ferror
ferror
fscanf

Error handling in file opening

[Question 1]
When I open a file into a function, generally I do something like this:
int read_file (char *filename)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
return 1;
/* ... */
return fclose(fin);
}
int main ()
{
char filename[100];
if ( read_file(filename) )
{
perror(filename);
exit(1);
}
return 0;
}
Generally 0 return value is for errors (right?) then I can change the previous code into:
int read_file (char *filename)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
return 0;
/* ... */
return !fclose(fin);
}
int main ()
{
char filename[100];
if ( !read_file(filename) )
{
perror(filename);
exit(1);
}
return 0;
}
But I think that the first code is more clean.
Another option is only change return 1; into return -1; (in the first code that I wrote).
What's the best version?
[Question 2]
If I must handle more errors, is it correct a code like this?
int read_file (char *filename, int **vet)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
{
perror(filename);
return 1;
}
* vet = malloc (10 * sizeof(int));
if ( *vet == NULL )
{
perror("Memory allocation error.\n");
return 1;
}
/* ... */
return fclose(fin);
}
int main ()
{
char filename[100];
int *vet;
if ( read_file(filename, &vet) )
exit(1);
return 0;
}
Re Q1:
a) Most POSIX functions actually return -1 (or <0) for errors, not 0. Look at (for instance) open(), close(), read(), write() and so forth. The exception is the POSIX calls that return pointers, e.g. fopen(), which returns a FILE *. These return NULL on error.
b) I code my code to work like POSIX functions, which is similar the innards of many linux programs. I would call this 'the UNIX C standard'. However, many C++ programs and Java programs use true for success and false for failure. When these programmers move to C, they use 1 for success, and 0 for failure. This isn't wrong, but does cause confusion (well, causes me confusion). The worst result is when both standards are used in the same program. Picking a standard and sticking to it is more important than which standard you choose.
c) My own choice (in relation to Q1), would be to return -1 on error (i.e. as per your 'another choice' line).
Re Q2: mostly right, yes.
a) If your program is successful, better to exit(0) than return 0 I believe.
b) Quite where you perror is up to you. Perhaps you want to print the error in main().
c) Using perror immediately followed by exit(1) (or perhaps a different exit code depending on the error) is reasonable normal if you have no clean up to do or clean up within atexit.
d) If you are returning the result of fclose() on error, then the return if fopen fails should be -1 (or EOF) not 1 as if fclose() fails it returns EOF (otherwise known as -1).
e) Nit: your main function should have parameters (e.g. int main(char **argv, int argc))
in respect of negative numbers for errors - cppcheck gives warnings for that. Choosing a standard within a program suite is a good idea - programmers have enough internal logic to deal with without duplicating ... So after trying to fix a few FOSS programs I am likely to go with cppcheck recommendations then at least I can have something check my adopted standard.

What is "complete error trapping"?

Write a program in C using only low-level I/O..
The program must have complete error trapping. In particular the
program should use perror() to report system errors...
In my program...
test("checked argument count");
if((input_file1 = open(argv[1], O_RDONLY)) < 0)
{
test("couldn't open file1");
perror(argv[1]);
close(input_file1);
exit(1);
}
test("opened file1");
Would this be considered "complete error trapping" if I implement such code for every read/write attempt?
Note: test() is just for debugging and will be deleted later:
void test(const char * message)
{
printf("\ttesting: %s \n", message);
}
You shouldn't close the file descriptor that you failed to open.
Other than that, yes, you've done sufficient error checking on the open() call. Now repeat for the other open() calls, and the read() calls, and the write() calls, and presumably the close() calls that are part of the main-line processing — close() calls in the error paths are a best-effort and don't need to be error checked in the same way.
Your error reporting is not very helpful, though. You say 'file1' but that isn't the name of the file. Using perror() isn't going to help much there, either; I never use it because it doesn't give me enough control over the message format. You are passing the file name as the string; that's considerably better than people often do, but you can't also express which operation the program was attempting that failed. I'd use fprintf(stderr, ...) in conjunction with errno and strerror(). Be careful not to clobber errno by calling a function that itself sets errno (is your test() function safe?). If you aren't sure, capture errno and (if necessary) reset it to the captured value:
int errnum = errno;
test("couldn't open file", argv[1]);
errno = errnum;
perror(argv[1]);
exit(1);
The revised test() function might be:
#include <stdarg.h>
extern void test(char const *fmt, ...);
void test(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
putc('\n', stderr);
}
That's the core of it; you'd need to adapt that to work with your current internals of the test() function. The declaration of test() with the ellipsis does not require the <stdarg.h> header; the implementation of test() does require the header.

Resources