Forcing a write to a file without newline?


 
Thread Tools Search this Thread
Top Forums Programming Forcing a write to a file without newline?
# 1  
Old 11-12-2014
Forcing a write to a file without newline?

Hello, I am writing a program which runs with root privileges, and it creates a child with lowered privileges and has to redirect it's stdout and stderr to a file and then run bash.

The problem is, whenever I read this file, I want to see all of the current output, even when the program is still running, but when the child writes anything to stdout or stderr, it does not appear in the file until a newline character is written, and then the whole line is actually output.

Here's the code (i tried things like O_RSYNC, O_DSYNC etc to hopefully cause it not to buffer the lines):

Code:
		pid_t pid = fork();
		if (pid == 0)
		{
			//if (setgid(uid) == -1)
			//{
			//	cerr << "could not set group; exiting for security reasons." << endl;
			//	return 1;
			//};
			//if (setuid(uid) == -1)
			//{
			//	cerr << "could not drop privileges; exiting for security reasons." << endl;
			//	return 1;
			//};
			int fd = open(outputFile.c_str(), O_RDWR | O_CREAT | O_RSYNC | O_DSYNC | O_TRUNC, 0644);
			dup2(fd, 1);
			dup2(fd, 2);
			close(fd);
			cout << "terminal-server starting";
			if (execl("/bin/bash", "bash", NULL) == -1)
			{
				cerr << "execl error" << endl;
				return 1;
			};
		}
		else
		{
			int code;
			waitpid(pid, &code, 0);
			cerr << "The shell has terminated with code " << code << "." << endl;
			break;
		};

The line 'cout << "terminal-server is starting" ' does not cause anything to be written to the file at all, ut if I add "<< endl;" to the end (to output a newline), the line is written. But bash writes the command prompt and waits for input, and the command prompt does not appear in the file.

I hope I explained the problem clearly enough. Is there a way to stop it from buffering the output? Thanks.
# 2  
Old 11-13-2014
That is because the output stream is buffered...so you need to follow the open with a call to either setbuf or setvbuf and specify in their that the IO stream is unbuffered...
# 3  
Old 11-13-2014
Quote:
Originally Posted by shamrock
That is because the output stream is buffered...so you need to follow the open with a call to either setbuf or setvbuf and specify in their that the IO stream is unbuffered...
... or flush STDOUT after adding the text to the buffer and before the execl().
# 4  
Old 11-13-2014
Quote:
Originally Posted by Don Cragun
... or flush STDOUT after adding the text to the buffer and before the execl().
The "cout" and "stdout" streams may not be the same.

If you want real control over IO streams, C++ "cout" style is NOT the way to do it.

Code:
setbuf( stdout, NULL );
printf( "String to stdout\n" );
fprintf( stderr, "String to stderr\n" );

And even then, if you're doing multithreaded/multiprocess writes to the same file, printf() and fprintf() are NOT atomic calls - the data from multiple calls to printf()/fprintf() can be interleaved. If you want atomic writes where data from a single call is guaranteed to be contiguous at the end of the file, such as for a log file, you need to open the file with standard C open() in O_APPEND mode, format your data yourself, and use write().

And if you're doing your own log files like that, now you have to handle the log file getting too big. It can't be deleted because you have an open file descriptor on it - if someone does try to delete it all they'll do is remove it from the directory and the file will stay on disk until your process closes its descriptor.

There's a reason why library calls such as "syslog()" already exist.

You're not going to come up with a better logging system. Redirecting stdout/stderr is a logging scheme just like a Lego house is a place to live. Sometimes that's OK. For important processes, it's not.
# 5  
Old 11-13-2014
I thought the C++ cout iostream and the C++ C library stdout standard I/O stream were required to be synchronized by default. I know that an application writer could use:
Code:
    sync_with_stdio(false);

to disable that synchronization and make the stdout stream independent of the cout iostream, but I didn't see anything in the code samples shown in this thread indicating that cout and stdout are not synchronized in this application.

You are, of course, correct in noting that iostreams and stdio streams are not appropriate in a multi-threaded application where I/O between threads to a single stream is not coordinated. But again, this thread was just talking about flushing a (buffered) prompt written by a process before it overlays itself with a new program by invoking execl(). If you have multiple active threads running in a process when one of those threads calls execl(), that process has undefined behavior all over the place.

Last edited by Don Cragun; 11-13-2014 at 11:01 PM.. Reason: Fix typo in spelling of "coordinated".
# 6  
Old 11-14-2014
Simply flushing stdout will not do anything, because when I execute bash, I also need its output automatically flushed. Would setbuf(stdout, NULL) cause bash not to buffer the output?
# 7  
Old 11-14-2014
C file streams are not "global", they're limited to your own program. That's why your text "disappears" when you fork before flushing, because it's sitting in your buffer, which ceases to exist the instant you execl.

So the problem is a library your program uses, not stdout itself. stdio is fundamentally an "assemble lines for me in memory instead of calling write 200 individual times" library. You could bypass it and use file descriptor 1 directly with write(), but printf and its relatives are handy, no?

bash does a good enough job of managing its own streams, I don't think you need to worry about it as long as you properly wait() for it to make sure it's done printing and quitting and all that.
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

No newline at end of file

Hello all, I have maybe a simple Problem - but I do not know to handle it. All what I want, is to write a line to file without a newline at the end. It works with "echo -n" for all lines, but not for the last one. At the end of the file is always a "0a" (hex) My small script: ... (10 Replies)
Discussion started by: API
10 Replies

2. Shell Programming and Scripting

Newline in the file

I have requirement to remove the /n ( newline ) characters from the file. When I open file in VI .. I want to see newline char how to display newline char .. or where can I see the content with newline char visible? (3 Replies)
Discussion started by: freakabhi
3 Replies

3. Shell Programming and Scripting

Newline characters in fields of a file

My source file is pipe delimeted file with 53 fields.In 33 rd column i am getting mutlple new line characters,dule to that record is breaking into multiple records. Note : here record delimter also \n sample Source file with 6 fields : 1234|abc| \nabcd \n bvd \n cde \n |678|890|900\n ... (6 Replies)
Discussion started by: lakshmi001
6 Replies

4. Shell Programming and Scripting

How to check newline character in file?

Hi All, I have file with only one record,always be only one record. as like below. if that line contains newline end of the line..no need to add, if not just add the new line character. END OF FILE. ROW COUNT: 7 Please help me.. Thanks, (9 Replies)
Discussion started by: bmk
9 Replies

5. UNIX for Dummies Questions & Answers

Match EOF on newline in a file

Hi, i have a file where the end-of-file might be at the end of of a valid text line or on a new line case a) p q r s t u <eof> case b) p q r s t u <eof> case c) p q r s t u <no data, only carriage return> <eof> I have a requirement where <eof> line should not be read if it's... (3 Replies)
Discussion started by: ysrini
3 Replies

6. IP Networking

read/write,write/write lock with smbclient fails

Hi, We have smb client running on two of the linux boxes and smb server on another linux system. During a backup operation which uses smb, read of a file was allowed while write to the same file was going on.Also simultaneous writes to the same file were allowed.Following are the settings in the... (1 Reply)
Discussion started by: swatidas11
1 Replies

7. Shell Programming and Scripting

SED to convert ~ in a file to newline

Hi, I have a .txt file which has a tilde(~) in it. All that I want is to break into a newline whenever there is an occurence of '~'. I have tried SED to do that but I could not succeed. I would appreciate if I can get a shell script(ksh) for this problem real quick. Thanks in advance. ... (5 Replies)
Discussion started by: ntekupal
5 Replies

8. Shell Programming and Scripting

Append newline at the file end

Hi All, Is there any way to append a newline character at the end of a file(coma-separated file), through shell script? I need to check whether newline character exists at the end of a file, if it does not then append it. Regards, Krishna (1 Reply)
Discussion started by: KrishnaSaran
1 Replies

9. Solaris

forcing users to su

Is there a way in solaris 9 to prevent a user to login via ssh, telnet, rlogin, and only be able to su as that user, for example have DBA joe blow login as jblow, and then su to oracle BUT not vice versa have DBA joe blow login as oralce (6 Replies)
Discussion started by: csaunders
6 Replies

10. UNIX for Advanced & Expert Users

forcing su on a user

This is for 3 os's, AIX, Solaris, and AIX, didnt want to post three seperate times on the same subject, anyways, I want to force the user MQM to su, i.e. not be able to rlogin/telnet to the box as user MQM, only login as there ID(chris for example) and su to MQM, does anyone know how to do this,... (4 Replies)
Discussion started by: csaunders
4 Replies
Login or Register to Ask a Question