I am trying to write a small log system.
void write_log_msg(char * type, char * file_name, int line_number, char * fmt, ...);
To call this function in a nice way, I used macro
#define log_msg(fmt, ...) (write_log_msg(LOG, __FILE__, __LINE__, fmt, ##__VA_ARGS__))
I want to format the date of now and I use the function strftime to do that. But when I do, it seems it overwrites the data stored in __FILE__ and __LINE__ and I can't tell why.
time_t now = time(NULL);
char date_str[DATE_SIZE];
char time_str[TIME_SIZE];
struct tm * local_now = localtime(&now);
printf("file %s\n", file_name);
printf("line %d\n", line_number);
status = strftime(date_str, DATE_SIZE, "%b %d %Y", local_now);
if(status == 0){
printf("Error 1");
exit(EXIT_FAILURE);
}
status = strftime(time_str, TIME_SIZE, "%X", local_now);
if(status == 0){
printf("Error 2");
exit(EXIT_FAILURE);
}
When I check for the content of the value of __FILE__ and __LINE__ before strftime, it works just fine then the __FILE__ takes the value of date_str and line_str I can't even tell. Any idea why it would do that ? Thanks !
Any idea why it would do that ?
Related
I have come across many questions related to this but my requirement is quite different. I developed a C application(mib-test.c) earlier which uses fprintf at lot of places. fprintf logs the messages in a file.
But now I need to print these messages to console also. I am looking for a solution in which I do not need to change fprintf in all the places.
Is there a way to do it?
No, there is not, you will have to edit each instance. A better approach to begin with would have been to create your own logging function or macro. I would suggest you to do that now, and save yourself some time if you ever change mind again in the future.
Example using a function:
void log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
va_start(args, fmt);
vfprintf(logfile, fmt, args);
va_end(args);
}
Example using a macro:
#define log(fmt, ...) do { \
fprintf(stderr, fmt, __VA_ARGS__); \
fprintf(logfile, fmt, __VA_ARGS__); \
} while (0)
See also: do { ... } while (0) — what is it good for?
Note that using a macro will evaluate expressions twice. For example log("%d\n", get_int()); using the macro form will call get_int() twice. You should only use the macro if you plan to pass simple values.
Both solutions assume that logfile is global and already opened for writing. You could actually define it static inside the function and handle the initial opening checking if (logfile == NULL) before doing anything.
#marcobonelli wrote a great answer. So for the replacing part, if you're not using an IDE that can do all the replacements for you, you could probably use this simple sed command to do all the replacement. Assume you have a log function like in this answer, then just do this:
sed 's/fprintf(logfile/log(/g' -i <file>
This is incomplete (error handling is omitted), but it demonstrates the principle of replacing filedescriptors via dup() and dup2():
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
int errtee(char * path);
/*
** Function to write to *both* stderr and a named file
** Return the new filedescriptor, which should be
** used instead of STDERR_FILENO.
** (or -1 on error)
*/
int errtee(char * path){
int out[2];
pipe(out);
int pid=fork();
if(pid<0){ // error
perror( "fork() failed\n" );
return -1;
}
if(pid>0){ // parent
close(out[0]);
return out[1];
}
if(pid==0){ // child
int fd_extra;
char buff[512];
fd_extra = open(path, O_CREAT | O_WRONLY, 0666);
if (fd_extra < 0) return -1;
close(out[1]);
dup2(out[0], STDIN_FILENO);
close(out[0]);
while(1) {
unsigned done, todo;
int cnt, this;
cnt = read(STDIN_FILENO, buff, sizeof buff) ;
if (cnt <=0) break;
for(todo = cnt, done = 0; done < todo; done += this) {
this = write(STDERR_FILENO, buff+done, todo-done);
if (cnt <=0) break; // this is not perfect ...
}
for(todo = cnt, done = 0; done < todo; done += this) {
this = write(fd_extra, buff+done, todo-done);
if (cnt <=0) break; // this is not perfect ...
}
}
close( fd_extra);
}
exit(0);
}
int main(void){
int new_fd;
int old_fd;
char buff[222];
new_fd = errtee("Mylogfile.log" );
if (new_fd < 0) {
perror( "errtee() failed\n" );
exit(1);
}
// Save the stdin filedescriptor
old_fd = dup( STDERR_FILENO);
// ... and replace it by the one from the subprocess.
dup2(new_fd, STDERR_FILENO);
// Send some output to stderr ...
while (fgets(buff, sizeof buff, stdin) ) {
fprintf(stderr, "%s", buff);
}
// Restore the old stdin filedescriptor
dup2(old_fd, STDERR_FILENO);
// ... and check if stderr still works ...
fprintf(stderr,"Completed\n" );
return 0;
}
Note: diagnostic output should go to stderr. If you keep it that way, it can always be replaced by a method like above.
[It is also possible to fetch the fileno() from the fopen'd log file, and do it the other way around. YMMV]
I'm getting the following error:
wlan_config_vap_priv_int vap lan0 cmd cpauth val 0(0) error: Bad address
Which is from the print in wlan_config_vap_priv_int. Does anyone know what might be causing the "Bad address" error?
From why does ioctl return "bad address" I suspect the culprit may be the ioctl call, but I don't see why.
int wlan_config_vap_priv(char *vap, char *cmd, char * val) {
int fd, ret;
struct ifreq ifr;
param_t fp;
strncpy(ifr.ifr_name, vap, IFNAMSIZ);
strncpy(fp.cmd, cmd, sizeof(fp.cmd));
strncpy(fp.val, val, sizeof(fp.val));
ifr.ifr_data = (void *) &fp;
printf("%s:%d: config vap %s priv %s=%s\n", __func__, __LINE__, vap, cmd, val);
if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return -1;
}
ret = ioctl(fd, SIOCSPARAM, &ifr);
close(fd);
return (ret);
}
int wlan_config_vap_priv_int(uint8_t rId, char *vap, char *cmd, int val) {
char buf[32];
int ret;
snprintf(buf, sizeof(buf), "%d", val);
ret = wlan_config_vap_priv(vap, cmd, buf);
if (ret < 0) {
CW_LOG_ERR("%s vap %s cmd %s val %s(%d) error: %s\n",
__FUNCTION__, vap, cmd, buf, val, strerror(errno));
}
return ret;
}
Your information is incomplete because you do not have the Kernel part for SIOCSPARAM.
However according to http://man7.org/linux/man-pages/man2/ioctl.2.html, this error happens when argp references an inaccessible memory area
EFAULT argp references an inaccessible memory area.
Your source strings do not have size attached to them. Using strncpy on this string is unsafe and could be the culprit. You can try using something like snprintf.
I am sorry if this is a stupid question, but I have been searching but unable to find the answer anywhere else. Its most likely pretty simple, but here goes:
I am asked to write a C program which takes one argument. If I try to give it more than one, it should print a usage message to stderr, with the format Usage: %s argument\n, where %s is the name of the binary.
It is this last part which I do not understand.
I know it should look like this if it fails:
$./hello
Usage: ./hello argument
Can someone please explain this to me?
EDIT:
Got it working like this:
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
int args_test(int args, char argument[]){
if(args < 1){
fprintf(stderr, "Usage: %s argument\n", argument);
exit(EXIT_SUCCESS);
}
if(args < 2){
fprintf(stderr, "Usage: %s argument\n", argument);
exit(EXIT_SUCCESS);
}
if(args > 2){
fprintf(stderr, "Usage: %s argument\n", argument);
exit(EXIT_SUCCESS);
}
return 0;
}
int args_usage(char argument[]){
printf("Hello, %s!\n", argument);
exit(EXIT_SUCCESS);
}
int main(int args, char* argv[]){
if(args < 2 || args > 2){
args_test(args, argv[0]);
}
args_test(args, argv[1]);
args_usage(argv[1]);
exit(EXIT_SUCCESS);
}
Hell first of all you can try and hardcode it :) Just kidding.
If you are on linux, you can get binary name withing /proc/pid/exe.
For example:
auto ret = readlink("/proc/self/exe", buf, sizeof(buf));
if (ret == -1) //error
std::string fpath(buf, ret);
Now in fpath you have absolute path to your program. You can parse your program out with function like dirname.
So first you need to get absolute path to char*. This can be done with strcpy
char *fullpath = new char[fpath.length()+1];
strcpy(fullpath, fpath.c_str());
std::string dir = dirname(fullpath);
std::string program_name = fpath.substr(dir.length());
printf("Usage: %s argument\n", program_name);
And that is it. I will just leave it for you to decide size of the buffer ;)
If you are on Windows, you can use function GetModuleFileName
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197(v=vs.85).aspx
Enjoy
I have a nest struct here.
typedef struct
{
struct_one one;
struct_two two;
struct_three three;
} outermost_struct;
Passing a pointer to the outer struct in the function
outermost_struct settings
readFileInStruct(settings_file, &settings)
My Function to read the bin file in struct
int readConfigIn2Struct
(
char file_name[],
outermost_struct*settings_mem_location
)
{
FILE *ptr_file;
ptr_file = fopen(file_name,"rb");
if(ptr_file == NULL)
{
return -1;
}
fread(&(*settings_mem_location),sizeof(outermost_struct),1,ptr_file);
fclose(ptr_file);
return 0;
}
Here fread fails and returns to the main function. Can anyone tell me why is my fread failing? The size of teh file is 73kb and struct has enough memory to accommodate the entire file.
Now instead of doing fread once for the entire file, I am trying to do fread for each struct.
fread(&(*settings_mem_location),sizeof(struct_one),1,ptr_file);
Here fread correctly writes into struct_one. Now I need fread to write into struct_two. How do I advance the pointer to point to struct_two?
Detailed error checking and logging is debugging for free. On top of this including additional logging mostly helps.
Below a possible version of the code you show, reflecting my statements above:
int readConfigIn2Struct (
char file_name[],
outermost_struct * settings_mem_location)
{
#ifdef DEBUG
fprintf(stderr, "%s:%d - Entering %s with file_name = '%s', outermost_struct * = %p\n",
__FILE__, __LINE__, __func__, file_name, (void*) settings_mem_location);
#endif
assert(NULL != file_name);
assert(NULL != settings_mem_location);
int result = 0; /* be optimistic. */
FILE *ptr_file = fopen(file_name, "rb");
if (ptr_file == NULL)
{
result = -1;
}
else
{
size_t bytes_to_read = sizeof * settings_mem_location;
#ifdef DEBUG
fprintf(stderr, "Bytes to read from '%s': %zu\", file_name, bytes_to_read);
#endif
size_t bytes_read = fread(settings_mem_location, 1, bytes_to_read, ptr_file);
if (bytes_read < bytes_to_read)
{
result = -1;
if (feof(ptr_file))
{
fprintf(stderr, "Unexpectedly reached EOF after %zu bytes\", bytes_read);
}
else if (ferror(ptr_file))
{
fprintf(stderr, "An error occurred after reading %zu bytes\", bytes_read);
}
}
fclose(ptr_file);
}
#ifdef DEBUG
fprintf(stderr, "%s:%d - Leaving %s with result = %d\n", __FILE__,
__LINE__, __func__, result);
#endif
return result; /* One exit point per function is preferred over several. */
}
Compile with option -DDEBUG to enable additional logging like entry and exit.
To have the calls to assert() being removed automagically compile with option -DNDEBUG.
Details about assert() are in the documentation here.
In the following code, I need a unique filename, do some stuff with it, and let it be. It is about converting a .class file to binary, let us call it compilation.
It works perfectly when run in isolation or done 3 times at a time; however, I run into issues when I start up many multiple processes (e.g., 7) where one or more of my compilations fail.
This is the code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static unsigned int numFiles = 0;
static unsigned long numBytes = 0;
FILE* rawf;
char* raw_file_name_end = ".raw_ujc";
char * rawfilename;
static void byte(unsigned char v){
if(numBytes) printf(", ");
printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v);
fwrite(&v,sizeof(v),1,rawf);
numBytes++;
}
int main(int argc, char** argv){
const char* self = argv[0];
int c;
const char* classCvt = 0;
long len;
if(argc == 1){
fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self);
return -1;
}
argv++;
argc--;
if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){
classCvt = argv[1];
argv += 2;
argc -= 2;
}
printf("\nService optimized bytecode = {\n\t");
while(argc--){
char* filename = *argv;
rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1);
strncpy(rawfilename,filename,(strlen(filename)-strlen(".class")));
strcat(rawfilename,raw_file_name_end);
fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename);
if(classCvt){
char* t;
filename = tempnam(NULL, NULL);
if(!filename){
fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno);
return -10;
}
t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32);
if(!t){
fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self);
free(t);
return -11;
}
sprintf(t, "%s < %s > %s", classCvt, *argv, filename);
if(system(t)){
fprintf(stderr, "%s: system() fail: %d\n", self, errno);
free(t);
return -12;
}
free(t);
}
printf("filename is %s\n",filename);
FILE* f = fopen(filename, "r");
rawf = fopen(rawfilename, "wb");
if(filename != *argv){
unlink(filename);
free(filename);
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(fseek(f, 0, SEEK_END)){
fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -3;
}
len = ftell(f);
if(len < 0){
fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno);
fclose(f);
return -4;
}
if(fseek(f, 0, SEEK_SET)){
fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -5;
}
if(len > 0x00FFFFFFUL){
fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL);
fclose(f);
return -6;
}
byte(len >> 16);
byte(len >> 8);
byte(len);
while((c = fgetc(f)) != EOF){
byte(c);
}
numFiles++;
fclose(f);
fclose(rawf);
argv++;
}
byte(0);
byte(0);
byte(0);
printf("\n};\n");
fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes);
fprintf(stderr, "rawfilename at end: %s \n", rawfilename);
free(rawfilename);
return 0;
}
After looking around, people recommend using mkstemp(); however, as you can see, I actually do need the filename in several places.
I tried adjusting this but keep running into errors. How can I safely adjust this work method?
From the manpage for mkstemp
int mkstemp(char *template);
The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file.
The last six characters of template must be "XXXXXX" and these are
replaced with a string that makes the filename unique. Since it will
be modified, template must not be a string constant, but should be
declared as a character array.
The file is created with permissions 0600, that is, read plus write
for owner only. The returned file descriptor provides both read and
write access to the file. The file is opened with the open(2) O_EXCL
flag, guaranteeing that the caller is the process that creates the
file.
so if you need the filename, you can find it in the template argument passed to mkstemp.