String buffer overflow produced by asctime() in C - c

I want to print out the time in C using asctime(), but when the text gets printed out random charaters are appended after timeString. Also, the text syslog() prints out in the log file differs from the text printed in the shell by printf(). Under the code I've provided the exact output from both outputs. How do I get rid of this behavior? The code is running on a RaspberryPi and I'm logged in via the default macOS terminal.
time_t rawTime;
time(&rawTime);
struct tm timeInfo = *gmtime(&rawTime);
// ...
char *log;
char *timeString = strdup(asctime(&timeInfo));
asprintf(&log, "UTC: %s %.*s Last status: %s. New status: %s.",
timeString, 5, " ", "Hello", "World");
openlog("httpd-status-notifier", LOG_PID, LOG_USER);
syslog(logLevel, "%s", log);
printf("%s\n", log);
// ...
Syslog:
Dec 22 17:18:17 rasp httpd-status-notifier[25458]: UTC: Sun Dec 22 17:18:17 2019#012 Last status: Hello. New status: World.
(Here syslog produces #012)
Shell (printf):
UTC: Sun Dec 22 17:18:17 2019
Last status: Hello. New status: World.
(Here printf produces a new line charater)
Btw., yes I did notice that syslog already logs the date.

The problem is that asctime() produces a new line character and this gets represented as the octal ASCII value 012 in the log file as pointed out by #mangusta in the comment section. So trimming the string solves the problem.

Related

Avoiding a newline when using fprintf with time.h

I keep getting a new line printed after the current time is written to a log.txt file. In this example I want the time and logMessage printed on the same line. Could you point me in the right direction as to what I'm missing here?
The logWrite function is called from the main function:
strcpy(logMessage, "**********RESTART**********");
logWrite(logMessagePtr);
The logWrite function is:
void logWrite(char * logMessagePtr)
{
/* Initialise time variables for log file. */
int hours, minutes, seconds, day, month, year;
// time_t is an arithmetic time type
time_t now;
// Update current time using time(&now);
time(&now);
FILE * logFilePtr;
logFilePtr = fopen ("C:\\log.txt", "a");
if (logFilePtr != NULL)
{
fprintf(logFilePtr, ("%s", ctime(&now)));
fprintf(logFilePtr, "%s", logMessagePtr);
fprintf(logFilePtr,"\n");
fclose(logFilePtr);
printf("Log file found\n"); //debug
}
else
{
perror("log.txt");
}
}
The log.txt file is sucessfully (created) appended to but I consistently get a new line feed after the time is written to the file.
When I run the program twice in a row for example, the log.txt reads:
Sat May 22 09:16:47 2021
**********RESTART**********
Sat May 22 09:16:48 2021
**********RESTART**********
What I want is:
Sat May 22 09:16:47 2021 **********RESTART**********
Sat May 22 09:16:48 2021 **********RESTART**********
Info on time.h
ctime(3) - Linux man page says:
The call ctime(t) is equivalent to asctime(localtime(t)). It converts the calendar time t into a null-terminated string of the form
"Wed Jun 30 21:49:08 1993\n"
It looks like adding newline character is included in the specification of ctime(). You should use strftime() to manually format the date and time without newline.
char date[128];
strftime(date, sizeof(date), "%a %b %d %T %Y", localtime(&now));
fprintf(logFilePtr, "%s", date);
The ctime function always adds '\n' to the end of string. There are many different ways to solve the problem, but the easiest way is to remove this symbol. This can be done, for example, like this (based on the fact that the ctime (see man) returns char *, not const char *):
#include <string.h>
...
char *ctime_line = ctime (&now);
ctime_line[strlen (ctime_line) - 1] = '\0';
and then print this line:
fprintf (logFilePtr, "%s", ctime_line);
P.S. I do not recommend using a record like this, since the string AAA may contain, for example, the % character, which will be interpreted as a special character.
// bad
fprintf (logFilePtr, logMessagePtr);
// good
fprintf (logFilePtr, "%s", logMessagePtr);
P.P.S. The following three lines
fprintf (logFilePtr, "%s", ctime (&now));
fprintf (logFilePtr, "%s", logMessagePtr);
fprintf (logFilePtr, "\n");
can be combined into one
fprintf (logFilePtr, "%s %s\n", ctime (&now), logMessagePtr);
As per documentation of ctime, the string has a newline embedded. You need to remove it from consideration for printing.
Since the string returned by ctime has a specified format of constant width, this should accomplish that:
fprintf(logFilePtr, "%.24s ", ctime(&now));
(edit: This is assuming you wish to use ctime in the first place, as you do in the question. There are other, potentially better, options, such as strftime.)

Repetition of the last string when reading from .txt file C

This is the code, it reads from a file and then it prints what is written in that file.
I don't know why but the last string of the file is readed twice.
Code
FILE* src = fopen(name_email_src, "r");
if (src == NULL)
{
printf("ERROR source file not found");
}
while(fgets(buff_src, sizeof(buff_src), src) != NULL)
{
fputs(buff_src, stdout);
}
fclose(src);
printf("%s", buff_src);
This is the output:
Date: Tue, 07 Feb 2017 21:32:46 +0100 (CET)
From: Rental <rental#house-rental.com>
To: me <me#upf.edu>
Message-ID: message2
Subject: Paga el alquiler ya.
Dear customer,
you are late in your payment, please pay or LEAVE!
Sincerely yours,
House rental
House rental
What can I do to solve this problem? Thank you.
printf("%s", buff_src); is printing the last line.
You have an extra call to printf() after your while loop:
while(fgets(buff_src, sizeof(buff_src), src) != NULL)
{
fputs(buff_src, stdout); // prints each line
}
fclose(src);
printf("%s", buff_src); // prints buff_src which still holds the last line
Just remove this unnecessary call to printf() and it will work as you expect.
fgets() reads line by line from the file. From the man page of fgets()
If a newline is read, it is stored into the buffer.
fgets(buff_src, sizeof(buff_src), src) /* read upto New line or EOF from src and store into buff_src */
when loop fails whatever buff_src contains that's been printed using last printf statement.

C string output not performing as expected

In C running in Visual Studio Express 2013 on a Windows 7 system, I have the following code which is intended to print out the lines in a text file on which a comment appears. Such lines are indicated in the input file by a # sign as the first character in a line. Assuming a line is:
#George Washington lives here
when I execute the program, it prints out:
comment: α°/
Why isn't my code printing out the line? It has no problem detecting these lines and otherwise processing them.
string str;
ifstream in;
in.open(filename);
if (in.is_open())
getline (in, str);
while (in) {
if (str[0] == '#') { printf("\ncomment: %s", str); }
In Visual Studio 2013 you can configure the character set between Unicode and Multibyte. You can find it in the project propriety.
To "normalize" the string you can add c_str()
printf("\ncomment: %s", str.c_str());

C program time stamp in hh:mm:ss.xxx millisecond and file handling issue

I am currently doing a research project on VANETs (vehicular Ad hoc networks). I am using 4 laptops installed with ubuntu 12. and above. So, my GPS displays the time stamp in the format (hh:mm:ss.xxx) where xxx is the millisecond. I have tried using gettimeofday() and other date and time functions, but none seems to give me the same required time format output. nevertheless the command on the terminal ( date +"%T.%3N") gives me the exact format as mentioned above. Since, I need this output to be saved in an external file. I have tried using a bash script inside my c program. But I am unable to print a new line in the file from the main using file handling fopen() to insert a new line in the file.
Using this code. I was able to print the time in required format in the file(datebash.csv) , but the problem is that I need to add new line to the same file from the main() using file pointer. But the new line is not getting added to the file and the time is being printed in the same line of the datebash.csv file.
My C program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <sys/timeb.h>
#define SHELLSCRIPT "\
#/bin/bash \n\
now=$(date +'%T.%3N') \n\
printf \"$now \" >> datebash.csv \n\
printf \" \" >> datebash.csv \n\
"
int main()
{
int i,a=3,b=3,j;
FILE *fp;
puts("Will execute sh with the following script :");
puts(SHELLSCRIPT);
puts("Starting now:");
system(SHELLSCRIPT); // calls the bash script above and runs(SHELLSCRIPT)
for(i=0;i<300;i++) // just to have a few milliseconds to lapse doing this loop
{ a+b*100;}
system(SHELLSCRIPT); // calls the bash script again and prints the result in the same file(datebash.csv)
fp = fopen ("datebash.csv", "a+ "); // I am opening from here the same file datebash.csv so That I can print a new line to it.
if(fp==NULL)
{
printf("Error!");
exit(1);
}
fseek(fp,0,SEEK_END); // placing cursor at end of file to insert new line here
fprintf(fp ,"\n"); //printing new line
system(SHELLSCRIPT);***//the problem is here.. the new line is not getting printed in the datebash.csv when the function is called from here. the time is getting printed in the first line itself.***
return 0;
}
Thanks
If I understand, you want to write to a file, with a time stamp,
followed by a ,
followed by another time stamp.
and you want to gen the time stamps via date+"%T.%3N on your terminal.
on your terminal:::
( date +"%T.%3N") >> file.csv
However, if you want to write a program to do so (pseudo code)
fn = open( "file.csv", O_append, S_iwrite );
check that open was successful, I.E. fn >= 0
if ( 0 <= fn ) // actually, expect fn to be greater than 2
{
char buffer[30] = {0};
while(1)
{
read GPS value into buffer
write ( fn, buffer, strlen(buffer) );
fflush( fn );
memset( buffer, 0x00, sizeof buffer );
strcat( buffer, " ,");
// if the reading of the GPS value is not self pacing, then
// use sleep(5); or something similar here
}
}
you probably want to add some way to close the file upon program exit

scanf(), Linux's shell input in handled differently, why?

I got the following.
my-app.c file:
char username[USERNAME_MAX_LEN] = "\0";
char password[PASSWORD_MAX_LEN] = "\0";
scanf("%s %s", username, password);
printf("username-len: %ld, password-len: %ld\n", strlen(username), strlen(password));
credentials.data file:
jdons f4$dsef35fs
So:
$ ./my-app < credentials.data
username-len: 0, password-len: 0
and:
$ cat credentials.data | ./my-app
username-len: 5, password-len: 10
Why in the both ways the input is handled differently? What is the difference to be so?
What is the right way to use scanf() to be able to handle both cases in the same way?
This line:
scanf("%s %s", username, password);
is inherently unsafe (unless you have complete control over what will appear on your program's standard input). The "%s" format says to read an arbitrarily long sequence of non-whitespace characters. However long the target array is, a sufficiently long word (say, caused by your cat sitting on the keyboard) will overflow it.
You can use a length modifier to limit the size of the input. For example (untested):
scanf("%36s %36s", username, password);
or, better:
scanf("%*s, %*s", USERNAME_MAX_LEN, username, PASSWORD_MAX_LEN, password);
But it's probably better to use fgets() to read an entire line at a time, and then use, say, sscanf() to process the line after you've read it.
And there's a possible problem in your printf call:
printf("username-len: %ld, password-len: %ld\n",
strlen(username),
strlen(password));
strlen() returns a result of type size_t, but "%ld" requires an argument of type long int. If your system supports it, you can use "%zu" to print a value of type size_t, but that's not 100% portable. Or you can convert the size_t value to, say, unsigned long:
printf("username-len: %lu, password-len: %lu\n",
(unsigned long)strlen(username),
(unsigned long)strlen(password));
It's possible, but not very likely, that that could cause non-zero size_t values to be displayed as 0.
Barankin,
Hmmm... that's an interesting behavior.
Both standard input indirection techniques work (as expected) for me...
landkrc#lasun175:/home/user/landkrc/crap
$ cat lg.c
#include <stdio.h>
#include <strings.h>
#define USERNAME_MAX_LEN 36
#define PASSWORD_MAX_LEN 36
int main(int argc, char *argv[])
{
printf("Hello, world\n");
char username[USERNAME_MAX_LEN];
char password[PASSWORD_MAX_LEN];
*username = 0;
*password = 0;
scanf("%s %s", username, password);
printf("username-len: %ld, password-len: %ld\n", strlen(username), strlen(password));
return 0;
}
landkrc#lasun175:/home/user/landkrc/crap
$ cc -V
cc: Sun C 5.8 2005/10/13
usage: cc [ options] files. Use 'cc -flags' for details
landkrc#lasun175:/home/user/landkrc/crap
$ cc -o lg lg.c
landkrc#lasun175:/home/user/landkrc/crap
$ echo '12345678 1234567890
> ' >data.txt
landkrc#lasun175:/home/user/landkrc/crap
$ lg <data.txt
username-len: 8, password-len: 10
landkrc#lasun175:/home/user/landkrc/crap
$ cat data.txt | lg
username-len: 8, password-len: 10
Maybe you just need an end-of-line-character on the end of your credentials.data file?
Cheers. Keith.
Check if your credentials.data contains a a newline character at the end? cat command appends it after the last line of file automatically.
As much as I try, I can't manage to reproduce the same problem as you. I even manually removed the end of line byte from the credentials.data file and it still works fine (as it should). What version of Linux or the shell are you running?

Resources