How do I compare time in C?
My program is getting the last modified time of 2 files, then compare that time to see which time is the latest.
Is there a function that compares time for you, or you have to create one yourself? This is my get time function:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
void getFileCreationTime(char *path) {
struct stat attr;
stat(path, &attr);
printf("Last modified time: %s", ctime(&attr.st_mtime));
}
Use difftime(time1, time0) from time.h to get the difference between two times. This calculates time1 - time0 and returns a double representing the difference in seconds. If it's positive, then time1 is later than time0; if negative, time0 is later; if 0, they're the same.
You can compare two time_t values to find which is newer:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
static time_t getFileModifiedTime(const char *path)
{
struct stat attr;
if (stat(path, &attr) == 0)
{
printf("%s: last modified time: %s", path, ctime(&attr.st_mtime));
return attr.st_mtime;
}
return 0;
}
int main(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Usage: %s file1 file2\n", argv[0]);
return 1;
}
time_t t1 = getFileModifiedTime(argv[1]);
time_t t2 = getFileModifiedTime(argv[2]);
if (t1 < t2)
printf("%s is older than %s\n", argv[1], argv[2]);
else if (t1 > t2)
printf("%s is newer than %s\n", argv[1], argv[2]);
else
printf("%s is the same age as %s\n", argv[1], argv[2]);
return 0;
}
If you want to know the difference between the values in seconds, then you need to use difftime() officially, but in practice you can simply subtract the two time_t values.
You can use below method
double difftime (time_t end, time_t beginning);
It returns the time difference in seconds. You can find example here.
my code:
char * findLeastFile(char *file1, char *file2){
struct stat attr1, attr2;
if (stat(file1, &attr1) != 0 || stat(file2, &attr2) != 0)
{
printf("file excetion");
return NULL;
}
if(difftime(attr1.st_mtime,attr2.st_mtime) >= 0)
return file1;
else
return file2;
}
Related
I want to write a C program that takes as an argument the path to a folder and shows some info about the files it contains.
So far I have written this:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv){
char* dir_path = argv[1];
char* dir_path_bar = strcat(dir_path, "/");
DIR* dir = opendir(dir_path);
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)){
printf("Next entry is %s\n", entry->d_name);
char* entry_path = strcat(dir_path_bar, entry->d_name);
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
};
closedir(dir);
}
Which compiles, but the stat call is giving me a SEGFAULT. What is going on?
As others have mentioned, you can't append to argv[1]. You can't keep appending to it inside the loop. And, you can't use %s to output numbers.
Here is your code with the bugs annotated and fixed [using #if 0 to show the old code]:
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char *dir_path = argv[1];
// NOTE/BUG: argv[1] has a fixed size you can't append to it
#if 0
char *dir_path_bar = strcat(dir_path, "/");
#else
char dir_path_bar[PATH_MAX];
strcpy(dir_path_bar,dir_path);
strcat(dir_path_bar,"/");
#endif
DIR *dir = opendir(dir_path);
#if 1
if (dir == NULL) {
perror(dir_path);
exit(1);
}
#endif
for (struct dirent *entry = readdir(dir); entry != NULL;
entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
// NOTE/BUG: because you don't reset dir_path_bar, this just keeps appending
// to it
#if 0
char *entry_path = strcat(dir_path_bar, entry->d_name);
#else
char entry_path[PATH_MAX];
strcpy(entry_path,dir_path_bar);
strcat(entry_path,entry->d_name);
#endif
printf("\n");
printf("%s\n", entry_path);
struct stat buf;
stat(entry_path, &buf);
// NOTE/BUG: these need one or more of: %d/%ld/%lld (vs %s)
#if 0
printf("Its inode number is %s\n", entry->d_ino);
printf("Its inode number is %s\n", buf.st_ino);
printf("Its uid is %s\n", buf.st_uid);
printf("Its size is %s bytes\n", buf.st_size);
#else
printf("Its inode number is %ld\n", entry->d_ino);
printf("Its inode number is %ld\n", buf.st_ino);
printf("Its uid is %d\n", buf.st_uid);
printf("Its size is %ld bytes\n", buf.st_size);
#endif
};
closedir(dir);
return 0;
}
Two problems:
You're appending continuously to the input (argv[1]) argument which is undefined behaviour. You can't append to the strings of argv.
Also printing integer values using %s which is undefined as well. %s expects a char * argument but you wanted to print integer values.
You can instead use a temporary buffer and pass it to stat(2):
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
if (argc != 2) {
printf("Usage: %s dir\n", argv[0]);
exit(1);
}
char* dir_path = argv[1];
DIR* dir = opendir(dir_path);
if (!dir) {
perror("opendir");
exit(1);
}
for(struct dirent* entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
char entry_path[PATH_MAX] = {0};
int rc = snprintf(entry_path, sizeof entry_path, "%s/%s", dir_path, entry->d_name);
if ( rc < 0 || rc >= sizeof entry_path) {
fprintf(stderr, "Path truncated for '%s'\n", entry->d_name);
continue;
}
printf("Next entry is: %s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) == 0) {
printf("Its inode number is %ju\n", (uintmax_t)entry->d_ino);
printf("Its inode number is %ju\n", (uintmax_t)buf.st_ino);
printf("Its uid is %jd\n", (intmax_t)buf.st_uid);
printf("Its size is %jd bytes\n", (intmax_t)buf.st_size);
} else {
perror("stat");
}
}
closedir(dir);
}
I have also added some error checking.
Not shown in the other 2 earlier answers is a nice avoidance of excessive copying.
When forming the entry_path, only the entry itself needs to be overwritten, not the entire string. This becomes valuable with a long pre-fixed directory string.
dir_path_len = strlen(dir_path);
if (dir_path_len >= PATH_MAX - 1) { return EXIT_FAILURE; } // too long
char entry_path[PATH_MAX];
strcpy(entry_path, dir_path);
strcpy(entry_path + dir_path_len++, "/"); // Can use strcpy() here
DIR *dir = opendir(dir_path);
...
for (struct dirent *entry = readdir(dir); entry != NULL; entry = readdir(dir)) {
printf("Next entry is %s\n", entry->d_name);
entry_len = strlen(entry->d_name);
if (dir_path_len + entry_len >= PATH_MAX) {
continue;
// or
return EXIT_FAILURE; // too long
}
strcpy(path + dir_path_len, entry->d_name); // strcpy(), not strcat()
printf("\n%s\n", entry_path);
struct stat buf;
if (stat(entry_path, &buf) ...
...
Programming Language C
below is the code that uses multiple threads to print out a file. There are no errors, however the code doesn't work correctly. However, when compiled it shows this warning 5 times:
'cast from pointer to integer of different size'
I've tried everything I can think of to resolve this issue, but haven't been success and now are just shooting in the dark. Does anyone see where my mistake is? Any help is greatly appreciated and will gladly provide any other information upon request.
Thanks.
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define NUM_THREAD 4
struct fileParams {
int fd;
int size;
};
void *printFile(void *stuff)
{
struct fileParams *params = stuff;
int addr;
addr=(unsigned char *)mmap(NULL, (int) ¶ms->size, PROT_READ,
MAP_PRIVATE,(int) ¶ms->fd,0);
write(STDOUT_FILENO, addr, (int)¶ms->size);
}
int main (int argc, char * argv[])
{
pthread_t threads[NUM_THREAD];
unsigned char *addr;
int fd,rc;
struct stat sb;
int numCPU=sysconf(_SC_NPROCESSORS_ONLN);
struct fileParams params;
printf("Number of aviable cores: %d\n",numCPU);
printf("Using 4 processors\n");
if (argc != 2 || strcmp(argv[1], "—help") == 0)
printf("Usage: %s file\n", argv[0]);
fd=open(argv[1],O_RDONLY);
if (fd == -1)
{
printf("File open fdailed.\n");
exit(EXIT_FAILURE);
}
if (fstat(fd, &sb) == -1)
{
printf ("fstat error\n");
exit(EXIT_FAILURE);
}
params.fd=fd;
params.size=sb.st_size/4;
for (int n = 0; n<4; n++)
rc=pthread_create(&threads[n],NULL,printFile,¶ms);
exit(EXIT_SUCCESS);
}
You need provide inputs to functions that match the function - passing pointers where integers are wanted (or the other way around) will generate warnings or errors depending on compile options.
mmap takes an size_t as the 2nd parameter, but you are giving it a cast int to a pointer (¶ms->size), the same with mmaps 5th parameter.
Get rid of the '&' so it is just a int.
mmap also returns a void *, which you are then assigning to addr (an int).
Change int to a void * pointer type which should also fix the 5th warning.
While retrieving the broken-out fields of the record in the password database (e.g., the local password file /etc/passwd, NIS, and LDAP) that matches a provided username name, I am using the getpwnam_r (http://linux.die.net/man/3/getpwnam_r) function.
#define __USE_BSD
#define _BSD_SOURCE
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct passwd pwd;
struct passwd *result;
char *buf;
size_t bufsize;
int s;
if (argc != 2) {
fprintf(stderr, "Usage: %s username\n", argv[0]);
exit(EXIT_FAILURE);
}
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1) /* Value was indeterminate */
bufsize = 16384; /* Should be more than enough */
buf = malloc(bufsize);
if (buf == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
s = getpwnam_r(argv[1], &pwd, buf, bufsize, &result);
if (result == NULL) {
if (s == 0)
printf("Not found\n");
else {
errno = s;
perror("getpwnam_r");
}
exit(EXIT_FAILURE);
}
printf("Name: %s; UID: %ld\n", pwd.pw_gecos, (long) pwd.pw_uid);
exit(EXIT_SUCCESS);
}
The code works fine, but Eclipse shows me a warning as follows:
warning: implicit declaration of function ‘getpwnam_r’ [-Wimplicit-function-declaration]
How could I fix it?
Note that I'm currently using Ubuntu 14.04 LTS.
To use this function you need two includes :
#include <sys/types.h>
#include <pwd.h>
Add them and it should not complain anymore.
You can see that by running man getpwnam_r.
You also need to define either __USE_MISC or __USE_SVID since it a POSIX only function.
I am trying to test out using papi, but I am getting some errors that I don't understand why they're occurring. I couldn't find anything online for them. The code is below
I am using PAPI and C.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <memory.h>
#include <malloc.h>
#include "papi.h"
#define INDEX 100
static void test_fail(char *file, int line, char *call, int retval);
int main(int argc, char **argv) {
extern void dummy(void *);
float matrixa[INDEX][INDEX], matrixb[INDEX][INDEX], mresult[INDEX] [INDEX];
float real_time, proc_time, mflops;
long long flpins;
int retval, status = 0;
int i,j,k;
long_long values[1];
FILE *file;
file = fopen("output.txt","w");
retval = PAPI_library_init(PAPI_VER_CURRENT);
int EventSet = PAPI_NULL;
PAPI_create_eventset(&EventSet);
if(PAPI_add_event(EventSet, PAPI_LD_INS) != PAPI_OK)
{
fprintf(file,"PAPI failed to add Load/Store instructions\n");
}
if (PAPI_state(EventSet, &status) != PAPI_OK)
fprintf(file,"state fail\n");
fprintf(file, "State is now %d\n", status);
if (PAPI_start(EventSet) != PAPI_OK)
fprintf(file,"start fail\n");
if (PAPI_state(EventSet, &status) != PAPI_OK)
fprintf(file,"state2 fail\n");
fprintf(file, "State is now %d\n", status);
/* Initialize the Matrix arrays */
for ( i=0; i<INDEX; i++ ){
mresult[0][i] = 0.0;
matrixa[0][i] = matrixb[0][i] = rand()*(float)1.1; }
if((retval=PAPI_flops( &real_time, &proc_time, &flpins, &mflops))<PAPI_OK)
fprintf(file,"retval failed\n");
for (i=0;i<INDEX;i++)
{
for(j=0;j<INDEX;j++)
{
for(k=0;k<INDEX;k++)
{
mresult[i][j]=mresult[i][j] + matrixa[i][k]*matrixb[k][j];
}
}
}
if((retval=PAPI_flops( &real_time, &proc_time, &flpins, &mflops)) <PAPI_OK)
{
fprintf(infile,"ret2 failed\n");
}
fprintf(file,"Real_time:\t%f\nProc_time:\t%f\nTotal flpins:\t%lld \nMFLOPS:\t\t%f\n",
real_time, proc_time, flpins, mflops);
fflush(file);
fprintf(file,"%s\tPASSED\n", __FILE__);
fflush(file);
if (PAPI_read(EventSet, values) != PAPI_OK)
{fprintf(file,"read fail\n");}
if (PAPI_stop(EventSet, values) != PAPI_OK)
{fprintf(file,"stop fail\n");}
if (PAPI_cleanup_eventset(&EventSet) != PAPI_OK)
{fprintf(file,"cleanup fail\n");}
if (PAPI_destroy_eventset(&EventSet) != PAPI_OK)
{fprintf(file,"destroy fail\n");}
fprintf(file,"\nValues is %f\n", values[0]);
fflush(file);
fclose(file);
PAPI_shutdown();
exit(0);
}
In the output file, I just see the below:
State is now 1
State is now 2
retval failed
ret2 failed
Real_time: 0.000000
Proc_time: 0.000000
Total flpins: 99
MFLOPS: 0.000000
PAPI_flops.c PASSED
cleanup fail
destroy fail
I don't understand why ret, ret2, cleanup and destroy failed. Why?
You can use the PAPI_perror or PAPI_strerror functions to get the error message associated with an error return value. This may help track down why, for example, PAPI_flops is failing. (It could be that there is no support on your system for the required events.)
The reason why PAPI_cleanup_eventset is failing though is because it takes just the integer EventSet, not a pointer to it.
I'd strongly recommend emitting the error return value strings, and also compiling with warnings on — the latter would likely have found the issue with the wrong parameter type.
need some advice on this one as im struggling abit and cannot figure it out.
i have a file that gets updated on a PC to indicate a system ran and what time it ran. i am writing a very simple linux console app (will eventually be a nagios plugin). that reads this file and responds depending on what it found within the file.
i am a total newbie to programming on Linux and using C so please be patient and if you would explain any answers it would really be appreciated.
basically i want to convert a char array containing 5 characters into an integer, however the 5th char in the array is always a letter. so technically all i want to-do is convert the first 4 chars in the array to a integer... how?? ive tried multiple ways with no success, my problem is that presently i do not have a good grasp of the language so have no real ideas on what it can and cannot do.
here is the source to my program.
basically the buf array will be holding a string taken from the file that will look something like this
3455Y (the number will be random but always 4 chars long).
Sorry for the poor formatting of the code, but i cannot get this stupid window for love nor money to format it correctly....
include <fcntl.h>
include <unistd.h>
include <stdio.h>
include <stdlib.h>
include <time.h>
include <string.h>
define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}
else
{
return STATE_OK;
}
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
You can use sscanf to do the job:
int num = 0;
sscanf(buf, "%4d", &num);
Then num should hold the number from the line in the file.
You can use atoi
atoi requires one char * argument and returns an int.
If the string is empty, or first character isn't a number or a minus sign, then atoi returns 0.If atoi encounters a non-number character, it returns the number formed up until that point
int num = atoi(buf);
if you want to convert the first four characters of a string to an integer do this:
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
uint8_t convertFirstFourChars(char * str, uint32_t *value){
char tmp[5] = {0};
strncpy((char *) tmp, str, 4);
*value = strtoul(tmp);
return errno;
}
then call / test this function like this
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv){
char test1[5] = "1234A";
char test2[5] = "ABCDE";
uint32_t val = 0;
if(convertFirstFourChars((char *) test1, &val) == 0){
printf("conversion of %s succeeded, value = %ld\n", test1, val);
}
else{
printf("conversion of %s failed!\n", test1);
}
if(convertFirstFourChars((char *) test2, &val) == 0){
printf("conversion succeeded of %s, value = %ld\n", test2, val);
}
else{
printf("conversion of %s failed!\n", test2);
}
return 0;
}
FWIW, don't use atoi(...) because it converts any string to an integer regardless of its validity as a number. atoi("foo") === 0.
this is as much of your code as I was able to recover from the formatting:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
} else {
return STATE_OK;
}
time_t ltime; /* calendar time /
struct tm Tm;
ltime=time(NULL); / get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
this is the version that does what you specified:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}/* else {
return STATE_OK;
buf[4] = 0;
} */
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d\n", test);
printf("%d\n", atoi(buf));
}
The biggest problem with your code was the if statement with the returns in each branch, insuring that nothing after the if statement was ever executed.