Program doesn't write on the standard output and gets stuck instead - c

I'm writing this software that should open a file, that must be passed as an argument, and write the content of the file on the standard output using the open and write system calls. (It's a bit like the cat command)
The problem is that once I run the program as
./a.out /example/pattern/file
it writes on the standard output the pattern of the file and then it gets stuck, without writing anything or terminating, allowing me even to write on the terminal.
I've tried using the ddd debugger, but I wasn't able to find the problem.
All the necessary headers are included.
int main(int argc,char * argv[]){
printf("%s\n", argv[1]);
int fd, lung;
char buf[10];
if(fd = open(argv[1], O_RDONLY)==-1){
perror("argv[1], in apertura");
exit(EXIT_FAILURE);
}
while(lung = read(fd,buf,10)>0){
if( (write(1, buf, lung))==-1) perror("error");
}
if (lung==-1) {perror("error");exit(EXIT_FAILURE);}
fflush(NULL);
close(fd);
return 0;
}

Isn't that suspicious?
if(fd = open(argv[1], O_RDONLY)==-1) {
According to operator precedence, == will be executed before =.
Then:
while(lung = read(fd,buf,10)>0){
will similarly suffer from > been executed before =.
Tip: When in doubt, use parentheses! ;)

while(lung = read(fd,buf,10)>0){
if( (write(1, buf, lung))==-1) perror("error");
}
is the same as (due to operator precedence ):
while(lung = (read(fd,buf,10)>0) ){
if( (write(1, buf, lung))==-1) perror("error");
}
The value of lung will be either 1 or 0. When it is 0, the loop will break When it is 1, only 1 character will be written to stdout.
What you need is:
while( (lung = read(fd,buf,10)) > 0 ){

Related

C program hangs after creating file

I'm doing an exercise for University, which asks:
Create a C program called 'split', which accepts a file, and a number. The program will divide the input file in two files, one called 'part1.txt' which will contain the first n bytes, and one called 'part2.txt' which will contain the other bytes.
If the input file contains less than n bytes, the file 'part2.txt' will not be created.
This is my program. What happens when I execute it, is that it creates the part1.txt file (without anything written in it) and the program hangs.
I've been looking at this for a day, but can't spot the problem. Any help?
I've compiled using:
gcc -o split split.c
When i execute it, i write:
./split text.txt 10
Where 'text.txt' is a text file containing words i accurately typed by pressing random buttons on my keyboard.
int splitter;
int fd, fd1, fd2;
char buffer[5000];
int main(int argc, char** argv){
if(argc<2){
printf("Insert 2 arguments.");
exit(1);
}
splitter = atoi(argv[2]);
if (fd=open(argv[1], O_RDONLY) < 0){
perror("Error\n");
exit(1);
} else {
if (fd1=open("part1.txt", O_RDWR | O_CREAT, S_IRWXU) <0){
perror("Error");
exit(1);
}
if(read(fd,buffer,splitter) == splitter){
write(fd1,buffer,splitter);
if (fd2=open("part2.txt", O_RDWR | O_CREAT, S_IRWXU)<0){
perror("Errore");
exit(1);
};
while (read(fd,buffer,1) ==1){
write(fd2,buffer,1);
}
close(fd1);
close(fd2);
} else {
while (read(fd,buffer,1) ==1){
write(fd1,buffer,1);
}
close(fd1);
}
close(fd);
}
The relational operators reside at the 6th level of C's precedence table, much higher than the assignment operators.
This statement:
if (fd=open(argv[1], O_RDONLY) < 0)
is equivalent to:
if (fd = (open(argv[1], O_RDONLY) < 0))
The < operator returns either 1 or 0, or in other words, true or false, which gets assigned to fd.
Change it to:
if ((fd = open(argv[1], O_RDONLY)) < 0)
You have the same issue in the subsequent if statement.
From Expert C Programming:
Some authorities recommend that there are only two precedence levels
to remember in C: multiplication and division come before addition and
subtraction.
Everything else should be in parentheses. We think that's
excellent advice.

Can not read from a pipe, and another stdin issue

So, I asked here just a while ago, but half of that question was just me being dumb. And I still have issues. I hope that this will be clearer than the question before.
I'm writing POSIX cat, I nearly got it working, but I have couple of issues:
My cat can not read from a pipe and I really do not know why (redirecting (<) works fine)
I can not figure out how to make it continuously read stdin, without some issues. I had a version that worked "fine", but would create a stack-overflow. The other version wouldn't stop reading from stdin if there was only stdin i.e.: my-cat < file would read from stdin until it got terminated which it shouldn't, but it has to read from stdin and wait for termination if no files are suplied.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
char opt;
while ((opt = getopt(argc, argv, "u")) != EOF) {
switch(opt) {
case 'u':
/* Make the output un-buffered */
setbuf(stdout, NULL);
break;
default:
break;
}
}
argc -= optind;
argv += optind;
int i = 0, fildes, fs = 0;
do {
/* Check for operands, if none or operand = "-". Read from stdin */
if (argc == 0 || !strcmp(argv[i], "-")) {
fildes = STDIN_FILENO;
} else {
fildes = open(argv[i], O_RDONLY);
}
/* Check for directories */
struct stat fb;
if (!fstat(fildes, &fb) && S_ISDIR(fb.st_mode)) {
fprintf(stderr, "pcat: %s: Is a directory\n", argv[i]);
i++;
continue;
}
/* Get file size */
fs = fb.st_size;
/* If bytes are read, write them to stdout */
char *buf = malloc(fs * sizeof(char));
while ((read(fildes, buf, fs)) > 0)
write(STDOUT_FILENO, buf, fs);
free(buf);
/* Close file if it's not stdin */
if (fildes != STDIN_FILENO)
close(fildes);
i++;
} while (i < argc);
return 0;
}
Pipes don't have a size, and nor do terminals. The contents of the st_size field is undefined for such files. (On my system it seems to always contain 0, but I don't think there is any cross-platform guarantee of that.)
So your plan of reading the entire file at one go and writing it all out again is not workable for non-regular files, and is risky even for them (the read is not guaranteed to return the full number of bytes requested). It's also an unnecessary memory hog if the file is large.
A better strategy is to read into a fixed-size buffer, and write out only the number of bytes you successfully read. You repeat this until end-of-file is reached, which is indicated by read() returning 0. This is how you solve your second problem.
On a similar note, write() is not guaranteed to write out the full number of bytes you asked it to, so you need to check its return value, and if it was short, try again to write out the remaining bytes.
Here's an example:
#define BUFSIZE 65536 // arbitrary choice, can be tuned for performance
ssize_t nread;
char buf[BUFSIZE]; // or char *buf = malloc(BUFSIZE);
while ((nread = read(filedes, buf, BUFSIZE)) > 0) {
ssize_t written = 0;
while (written < nread) {
ssize_t ret = write(STDOUT_FILENO, buf + written, nread - written);
if (ret <= 0)
// handle error
written += ret;
}
}
if (nread < 0)
// handle error
As a final comment, your program lacks error checking in general; e.g. if the file cannot be opened, it will proceed anyway with filedes == -1. It is important to check the return value of every system call you issue, and handle errors accordingly. This would be essential for a program to be used in real life, and even for toy programs created just as an exercise, it will be very helpful in debugging them. (Error checking would probably have given you some clues in figuring out what was wrong with this program, for instance.)
Your cat (You can call it my-cat, but I preferred to call it felix, just permit me the pun) should be used with stdio all the time to get the benefit of the buffering done by the stdio package. Below is a simplified version of cat using exclusively stdio package (almost exactly equal as it appears in K&R) and you'll see that is completely efficient as shown (you will see that the structure is almost exactly as yours, but I simplify the processing of the data copy /like K&R book/ and the processing of arguments /yours is a bit meshy/):
felix.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#define ERR(_code, _fmt, ...) do { \
fprintf(stderr,"%s: " _fmt, progname, \
##__VA_ARGS__); \
if (_code) exit(_code); \
} while (0)
char *progname = "cat";
void process(FILE *f);
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "u")) != EOF) {
switch (opt) {
case 'u': setbuf(stdout, NULL); break;
}
}
/* for the case it has been renamed, calculate the basename
* of argv[0] (progname is used in the macro ERR above) */
progname = strrchr(argv[0], '/');
progname = progname
? progname + 1
: argv[0];
/* shift options */
argc -= optind;
argv += optind;
if (argc) {
int i;
for (i = 0; i < argc; i++) {
FILE *f = fopen(argv[i], "r");
if (!f) {
ERR(EXIT_FAILURE,
"%s: %s (errno = %d)\n",
argv[i], strerror(errno), errno);
}
process(f);
fclose(f);
}
} else {
process(stdin);
}
exit(EXIT_SUCCESS);
}
/* you don't need to complicate here, fgetc and putchar use buffering as you stated in main
* (no output buffering if you do the setbuf(NULL) and input buffering all the time). The buffer
* size is best to leave stdio to calculate it, as it queries the filesystem to get the best
* input/output size and create buffers this size. and the processing is simple with a loop like
* the one below. You'll get no appreciable difference between this and any other input/output.
* you can believe me, I've tested it. */
void process(FILE *f)
{
int c;
while ((c = fgetc(f)) != EOF) {
putchar(c);
}
}
As you see, nothing has been specially done to support redirection, as redirection is not done inside a program, but done by the program that calls it (in this case by the shell) When you start a program, you receive three already open file descriptors. These are the ones that the shell is using, or the ones that the shell just puts in the places of 0, 1, and 2 before starting your program. So your program has nothing to do to cope with redirection. Everything is done (in this case) in the shell... and this is why your program redirection works, even if you have not done anything for it to work. You have only to do redirection if you are going to call a program with its input, output or standard error redirected somewhere (and this somewhere is not the standard input, output or error you have received from your parent process)... but this is not the case of my-cat.

Program gets stuck while trying to read a file using read() system call

Here is my code snippet:
int fd;
bufsize = 30;
char buf[bufsize];
char cmd[100] = "file.txt";
int newfd = 1;
if (fd = open(cmd,O_RDONLY) >=0){
puts("wanna read");
while (read(fd,&bin_buf,bufsize)==1){
puts("reading");
write(newfd,&bin_buf,bufsize);
}
close(fd);
}
So here the program prints "wanna read" but never prints "reading". I have also tried opening using nonblock flag, but no use. Can anybody help me? I must use open() and read() system calls only. Thanks.
Edit: I have made some clarifications in the code. Actually the newfd that I'm writing to is a socket descriptor, but I don't think that is important for this problem because it sticks on the read which is before the write.
The first problem is your if statement. You forgot to use enough parentheses, so if the open() works, the read tries to read from file descriptor 1, aka standard output. If that's your terminal (it probably is) on a Unix box, then that works — surprising though that may be; the program is waiting for you to type something.
Fix: use parentheses!
if ((fd = open(cmd, O_RDONLY)) >= 0)
The assignment is done before, not after, the comparison.
I observe in passing that you don't show how you set cmd, but if you see the 'wanna read' message, it must be OK. You don't show how newfd is initialized; maybe that's 1 too.
You also have the issue with 'what the read() call returns'. You probably need:
int fd;
char buf[bufsize];
int newfd = 1;
if ((fd = open(cmd, O_RDONLY)) >= 0)
{
puts("wanna read");
int nbytes; // ssize_t if you prefer
while ((nbytes = read(fd, buf, sizeof(buf))) > 0)
{
puts("reading");
write(newfd, buf, nbytes);
}
close(fd);
}
You can demonstrate my primary observation by typing something ('Surprise', or 'Terminal file descriptors are often readable and writable' or something) with your original if but my loop body and then writing that somewhere.
Your read() call attempts to read bufsize bytes and returns the number of bytes actually read. Unless bufsize ==, it is quite unlikely read() will return 1, so the block is almost always skipped and nothing get written.
Also note that if (fd = open(cmd, O_RDONLY) >= 0) is incorrect and would set fd to 1, the handle for standard output, if the file exists, causing the read to fail as standard input is most likely not opened for reading.
Note that reading with the read system call is tricky on some environments, because a return value of -1 may be restartable.
Here is an improved version:
int catenate_file(const char *cmd, int newfd, size_t bufsize) {
int fd;
char buf[bufsize];
if ((fd = open(cmd, O_RDONLY)) >= 0) {
puts("wanna read");
ssize_t nc;
while ((nc = read(fd, buf, bufsize)) != 0) {
if (nc < 0) {
if (errno == EINTR)
continue;
else
break;
}
printf("read %zd bytes\n", nc);
write(newfd, buf, nc);
}
close(fd);
return 0;
}
return -1;
}
read returns the number of bytes read from file that can be bufsize or less if the remainder of the file that has to be read is shorter than bufsize.
In your case most probably bufsize is bigger than 1 and the file is bigger than 1 byte so the condition of the while loop is evaluated false, the code is skipped to the point where file is closed.
You should check if there if there are more bytes to be read:
while( read(fd,&bin_buf,bufsize) > 0 ) {

How to write and read at the same file using "popen" in C

I'm using Intel Edison and SensorTag. In order to get temperature data via BLE, there are a bunch of commands. When I define popen as:
popen(command,"w");
code works fine most of the times. (Crashes other times due to delay issues I assume as I don't control the responses.)
However, when I want to control the command/console responses (such as step into next line when bluetooth connection is established and if not try to connect again etc.), I cannot read the responses. My "data" variable is not changed.
I also tried other modes of "popen" but they give run-time errors.
Here is the code I'm using:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int endsWith (char* base, char* str) {
int blen = strlen(base);
int slen = strlen(str);
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
}
FILE* get_popen(char* command, int close, int block) {
FILE *pf;
char data[512];
// Setup our pipe for reading and execute our command.
pf = popen(command,"w");
// Error handling
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);
// the data is now in 'data'
}
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
FILE* command_cont_exe(FILE* pf, char* command, int close, int block) {
char data[512];
// Error handling
if (pf == NULL) {
// print error
return NULL;
}
fwrite(command, 1, strlen(command), pf);
fwrite("\r\n", 1, 2, pf);
if (block == 1) {
// Get the data from the process execution
char* result;
do {
result=fgets(data, 512 , stderr);
if (result != NULL) {
printf("Data is [%s]\n", data);
}
} while (result != NULL);//
}
// the data is now in 'data'
if (close != 0) {
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
}
return pf;
}
int main()
{
char command[50];
sprintf(command, "rfkill unblock bluetooth");
get_popen(command, 1, 0);
printf("Working...(rfkill)\n");
sleep(2);
sprintf(command, "bluetoothctl 2>&1");
FILE* pf = get_popen(command, 0, 1);
printf("Working...(BT CTRL)\n");
sleep(3);
sprintf(command, "agent KeyboardDisplay");
command_cont_exe(pf, command, 0, 1);
printf("Working...(Agent)\n");
sleep(3);
//Main continues...
You cannot do this with popen, but can build a program using fork, exec and pipe. The last opens two file descriptors, which are related: the parent's connection to a pipe, and the child's connection. To make a two-way connection to a child process, you must use two calls to pipe.
The file-descriptors opened by pipe are not buffered, so you would use read and write to communicate with the child (rather than fgets and fprintf).
For examples and discussion, see
Does one end of a pipe have both read and write fd?
Read / Write through a pipe in C
UNIX pipe() : Example Programs
pipe(7) - Linux man page
6.2.2 Creating Pipes in C
Unfortunately, you can use popen() in one direction only. To get a bidirectional communication, you need to create two anonymous pipes with pipe() for stdin and stdout and assign them to the file handles 0 and 1 with dup2().
See http://tldp.org/LDP/lpg/node11.html for more details.

How to Search for New Lines while Reading from a File in C/C++

I am implementing my own version of the ("cat") command in Unix for practice. After i did that i became interested in implementing some flags like (-n) and (-b).
My Question: I am looking for a way to locate the blank and new lines while reading from my file. I can't remember what library or function i should use.
Here is the source code I am working on:
#include <fcntl.h>
#include <unistd.h>
static int cat_fd(int fd)
{
char buf[4096];
ssize_t nread;
while ((nread = read(fd, buf, sizeof buf)) > 0)
{
ssize_t ntotalwritten = 0;
while (ntotalwritten < nread)
{
ssize_t nwritten = write(STDOUT_FILENO, buf + ntotalwritten, nread - ntotalwritten);
if (nwritten < 1)
{
return -1;
}
ntotalwritten += nwritten;
}
}
return (nread == 0) ? 0 : -1;
}
static int cat(const char *fname)
{
int fd, success;
if ((fd = open(fname, O_RDONLY)) == -1)
{
return -1;
}
success = cat_fd(fd);
if (close(fd) != 0)
{
return -1;
}
return success;
}
int main(int argc, char **argv)
{
int i;
if (argc == 1)
{
if (cat_fd(STDIN_FILENO) != 0)
goto error;
}
else
{
for (i = 1; i < argc; i++)
{
if (cat(argv[i]) != 0)
{
goto error;
}
}
}
return 0;
error:
write(STDOUT_FILENO, "error\n", 6);
return 1;
}
Any ideas or suggestions concerning my question are greatly appreciated.
I would be even more grateful if you can type for me the complete function prototype that i shall be using as i am not an experienced programmer.
Thanks in advance for your help.
P.S: I am implementing the (-n) and (-b) flags. Thus, i am looking forward to write the line number at the beginning of each line in the file that i am reading.
While there is a function that does line-based file input in C (it's called fgets), you can't really use it for cat, because:
There's no way to know the maximum length of the line beforehand;
You'll lose portions of the input if it contains null bytes.
You'll have to look for newline symbols in your buffer after you read it, and once you find any, print the prefix of the buffer, followed by newline, line number, and the rest of the buffer (with additional processing of remaining newlines, of course).
An easier solution would be to switch to processing input one byte at a time; you can use FILE* and fgetc to use CRT-provided buffering so that you don't actually do a syscall for each read/write, or read file in blocks as you do now, and do byte processing inside the loop. Then it's a matter of writing a state machine - if a previous read character was a newline, then output a line number, unless this character is a newline and -b option is used, etc.
This still results in a less efficient solution, so you may want to treat cat without arguments specially - i.e. switch to byte-per-byte processing only if you need it. In fact, this is exactly what at least one of actual cat implementations does.
I recall reading that cat memory maps files for fast execution. Use mmap(2).
http://kernel.org/doc/man-pages/online/pages/man2/munmap.2.html
I found this example: http://ladweb.net/src/map-cat.c
I know this doesn't answer your question about newlines. I guess
memchr() would do the trick.

Resources