I'm trying to write a portable function in c that compares the last modified times of 2 files. The files are tiny and written one right after the other, so I need finer granularity than 1 second (milliseconds).
There seems to be a plethora of time/date functions...
You should look to the stat() function. It's available on *nix and on windows.
They will both return you a struct containing a field name st_msize. They are the finest functions I have heard of in order to get this kind of information from an Operating System.
Since you need portability, beware to take care of the various different types available on Windows. On *NIX, it's a classic time_t structure. If you include specific call, you can obtain nano seconds mtime: it was defined in POSIX.1-2008, according to the man page.
You can also take a look at how you can deal with 64/32 bit time_t
The C standard does not have any functions for this, but the Posix specification does. The 2008 edition even provides sub-second timestamps. #define _POSIX_C_SOURCE 200809L
The following code should give you an idea how to use it.
#define _POSIX_C_SOURCE 200809L
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h> // for printf
#include <stdlib.h> // for EXIT_FAILURE
int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i) {
struct stat st = {0};
int ret = lstat(argv[i], &st);
if (ret == -1) {
perror("lstat");
return EXIT_FAILURE;
}
printf("%s: mtime sec=%lld nsec=%lld\n", argv[i],
(long long) st.st_mtim.tv_sec,
(long long) st.st_mtim.tv_nsec);
}
return 0;
}
For POSIX UNIX, stat() is portable and gives struct stat st_mtime which is the modification time in epoch seconds. Windows stat returns windows time values, and has creation time rather than st_ctime.
For non-POSIX UNIX implementations, Windows and other OSes there is no portable concept of file modification time. So, depending on your idea of portable, this whole concept may or my not work for you.
Related
I have a minor and major numbers of a char device, and I want to turn them into dev_t (which used to hold device numbers), but I don't want to do all the process of building and writing a module, insmod it into the kernel and etc.
What's an easy way and fast to use the MKDEV macro?
#include <linux/kdev_t.h>
#include <linux/types.h>
dev_t device_num = MKDEV(int major, int minor);
Using a standard C program will not work, obviously, because it's kernel-code/kernel-space.
Update: Writing a User-Space program does work but I can't use the dev_t datatype, maybe because it can be used only by the kernel?
#include <linux/kdev_t.h> // MKDEV
#include <linux/types.h> // dev_t
#include <stdio.h> // I/O
int main(void)
{
int device_id = MKDEV(10, 249);
printf("%d\n", device_id); // 2809
return 0;
}
The header linux/kdev_t.h which provides MKDEV macro is accessible for user space programs too.
Definition of dev_t type is not accessible for the user space programs (headers linux/types.h are different for kernel and user), but for result of MKDEV you may use any integer type of 16 bit or more.
#include <linux/kdev_t.h>
<...>
int device_id = MKDEV(10, 249);
I have a version of a program that used to compile to a *.o file, but now it does not, and gives a compiler error.
I have tried to compile my code with gcc compiler on Linux, and the compile fails.
#include <stdio.h>
int isatty();
long isatty_(lio_number)
long *lio_number;
{
int file_desc;
if ((*lio_number)==5)
{
file_desc = stdin->_file;
return isatty(file_desc);
}
else
return 0;
}
I expect the command gcc -c isatty.c to yield isatty.o but it does not. Instead, I get this message:
isatty.c: In function ‘isatty_’:
isatty.c:11: error: ‘struct _IO_FILE’ has no member named ‘_file’
Never use any members of the FILE structure.
Use fileno(stdin) instead of stdin->_file.
The member _file is a MinGW-specific name for the file descriptor, while fileno is a widely-supported POSIX-compliant function.
Along with that, you may want to #include <unistd.h> instead of defining isatty explicitly.
If you're limited to writing your code this way for some reason, don't expect it to be portable. Otherwise, this should work:
#include <stdio.h>
#include <unistd.h>
long isatty_(long *lio_number)
{
int file_desc;
if (*lio_number == 5)
{
file_desc = fileno(stdin);
return isatty(file_desc);
}
else
{
return 0;
}
}
What this changes is that it includes unistd.h which provides a declaration for isatty, it includes the types of the arguments within the function definition, and it uses fileno(stdin) instead of stdin->_file, of which the former is much more portable. It also improves the formatting so others can read your code if they need to.
Modernize the code. The original seems to be targeting some ancient Unix. This should work on more recent POSIX-compliant systems, since virtually every such system should provide the fileno() function. Changing the code to standard C is also a good idea.
So use fileno(), include <unistd.h> instead of forward declaring isatty(), and use standard C function parameter declarations:
#include <stdio.h>
#include <unistd.h>
long isatty_(long *lio_number)
{
if (*lio_number == 5)
{
return isatty(fileno(stdin));
}
return 0;
}
I am working out of the 2nd edition of Jon Erickson's "Hacking: The Art of Exploitation" using a VM (virutalbox) to run the LiveCD it came with (Ubuntu 7.04). In section 0x281 "File Access", the author explains accessing files through file descriptors, as well as the open() close() read() and write() functions, using an example on pages 82-84.
The code for the simplenote.c is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *prog_name,char *filename){
printf("Usage: %s < data to add to %s>\n",prog_name,filename);
exit(0);
}
void fatal(char *);
void *ec_malloc(unsigned int );
int main(int argc,char *argv[]){
int fd; //file descriptor
char *buffer,*datafile;
buffer = (char *)ec_malloc(100);
datafile = (char *)ec_malloc(20);
strcpy(datafile,"/tmp/notes");
if(argc < 2)
usage(argv[0],datafile);
strcpy(buffer,argv[1]);
printf("[DEBUG] buffer # %p:\'%s'\n",buffer,buffer);
printf("[DEBUG] datafile # %p:\'%s'\n",datafile,datafile);
strncat(buffer,"\n",1);//Add a newline on the end.
fd = open(datafile,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR);
if(fd == -1)
fatal("in main() while opening file");
printf("[DEBUG] file descriptor is %d\n",fd);
//Writing data
if(write(fd,buffer,strlen(buffer)) == -1)
fatal("in main() while writing buffer to file");
//Closing file
if(close(fd) == -1)
fatal("in main() while closing file");
printf("Note has been saved.\n");
free(buffer);
free(datafile);
}
//A function to display an error message and then exit
void fatal(char *message){
char error_message[100];
strcpy(error_message,"[!!]Fatal Error");
strncat(error_message,message,83);
perror(error_message);
exit(-1);
}
//An error-checked malloc() wrapper function
void *ec_malloc(unsigned int size){
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
fatal("in ec_malloc() on memory allocation");
return ptr;
}
However, when I type the following instructions stated in the book into my terminal window, it returns the following error message:
reader#hacking:~/booksrc $ gcc -o simplenote simplenote.c
In file included from /usr/include/sys/stat.h:105, from simplenote.c:6:
/usr/include/bits/stat.h:70: error: field 'st_atim' has incomplete type
/usr/include/bits/stat.h:71: error: field 'st_mtim' has incomplete type
/usr/include/bits/stat.h:72: error: field 'st_ctim' has incomplete type
simplenote.c: In function 'main':
simplenote.c:35: error: 'O-WRONLY' undeclared (first use in this function)
simplenote.c:35: error: (Each undeclared identifier is reported only once
simplenote.c:35: error: for each function it appears in.)
simplenote.c:35: error: 'O_CREAT' undeclared (first use in this function)
simplenote.c:35: error: 'O_APPEND' undeclared (first use in this function)
Here is sys/stat.h line 105:
#include <bits/stat.h>
And here is bits/stat.h lines 63-83:
#ifdef __USE_MISC
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
identifier 'timespec' to appear in the <sys/stat.h> header.
Therefore we have to handle the use of this header in strictly
standard-compliant sources special. */
struct timespec st_atim; /* Time of last access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
# define st_atime st_atim.tv_sec /* Backward compatibility */
# define st_mtime st_mtim.tv_sec
# define st_ctime st_ctim.tv_sec
#else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
#endif
I suppose this might be of some use for the first set of issues:
C++ system file bits/stat.h suddenly breaks with "error: field ‘st_atim’ has incomplete type"
/usr/include/time.h
cat time.h
doesn't do anything in my terminal window.
And here is the simplenote.c main function lines 1-6, 34-35:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
// Opening the file
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
I'm guessing the open function problems stem from fcntl.h ?
I seem to keep running into issues because of faulty code the author provided. I don't want to constantly depend on the stackoverflow community for help, so what suggestions do you have for a novice about examining and fixing these problems in the future?
Thanks.
Transferring a selection of comments into a semi-coherent answer.
You should probably explicitly enable POSIX definitions. Add -D_XOPEN_SOURCE=700 to the command line, or #define _XOPEN_SOURCE 700 before the first #include and see if that solves anything. You should not be running into the problem though; the header should be self-contained.
Oh, but Ubuntu 7.04 is archaic…you may need to use 600 instead of 700. When was it released (when was the book published)? If it was 2009 or before, you probably need the older version (600). It's still surprising that you're seeing the error. The command line you specify doesn't contain the options that normally cause trouble (-ansi -pedantic, for example, or -std=c99 -pedantic). You could try using -std=gnu99 too; it might work better.
You had a similar problem recently (gcc -o stdlib.h syntax error c Hacking the Art of Exploitation). Did you get that resolved? It sounds as if the compilation system on the Live CD is not self-coherent, or the way you're able to use it means that it is not behaving self-coherently. Are you sure the compilation system works? It appears to be semi-defunct. Is it using the wrong headers, somehow?
I was able to resolve the previous problem by inserting #include <stdint.h> before #include <stdlib.h>
I will try the -D_XOPEN_SOURCE=600 and get back to you. Something must be wrong with the compilation system.
Well, you might need to include <time.h> (or possibly <sys/time.h>) before <sys/stat.h>, but the <sys/stat.h> header is broken if that works. And the <stdlib.h> header is broken if you have to include <stdint.h> before including it. I suppose Ubuntu 7.04 could be so old that you're supposed to #include <sys/types.h> before many of these headers, but that's still not an excuse for <stdlib.h>; that should be self-contained. POSIX 1997 required #include <sys/types.h> before <sys/stat.h>; POSIX 2004 did not. And I don't think Ubuntu 7.04 is quite that old.
Note, though, that the st_atim member is new; it was added to POSIX 2008 (and hence is in POSIX 2013). It was just st_atime before (and st_atime is now a macro for st_atim.tv_sec).
Including the -D_XOPEN_SOURCE=600 dealt with the bits stat issue. Ubuntu 7.04 was released in 2007 and the 2nd edition of the book that I am using came out in 2008. Also, not sure if this is of use, but in another previous example that included both <stdio.h> and <string.h> (as opposed to only <stdio.h>), the code would run fine without any intervention.
Interesting…it is going to make life interesting for you, in a way that life should not need to be interesting. (Chinese curses like "May you live in interesting times" spring to mind.) Use the -DXOPEN_SOURCE=600 option in all your compilations and keep your fingers crossed; that may well resolve most of your problems. Consider using -std=gnu99 as well, or instead. With luck, either or both of those should get you around most problems.
In case someone else is having the same issue with this book, I downloaded the iso file from hacking-live-1.0.iso.
Created a bootable usb and all works just fine without corrupted headers or anything.
I am learning to use getline in C programming and tried the codes from http://crasseux.com/books/ctutorial/getline.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int atgc, char *argv[])
{
int bytes_read = 1;
int nbytes = 10;
char *my_string;
my_string = (char *)malloc(nbytes+1);
puts("Please enter a line of text");
bytes_read = getline(&my_string, &nbytes, stdin);
if (bytes_read == -1)
{
puts ("ERROR!");
}
else
{
puts ("You typed:");
puts (my_string);
}
return 0;
}
However, the problem is that the compiler keeps returning errors of this: undefined reference to 'getline'.
Could you please tell me what the problem is? Thank you!
I am using Win7 64bit + Eclipse Indigo + MinGW
The other answers have covered most of this, but there are several problems. First, getline() is not in the C standard library, but is a POSIX 2008 extension. Normally, it will be available with a POSIX-compatible compiler, as the macros _POSIX_C_SOURCE will be defined with the appropriate values. You possibly have an older compiler from before getline() was standardized, in which case this is a GNU extension, and you must #define _GNU_SOURCE before #include <stdio.h> to enable it, and must be using a GNU-compatible compiler, such as gcc.
Additionally, nbytes should have type size_t, not int. On my system, at least, these are of different size, with size_t being longer, and using an int* instead of a size_t* can have grave consequences (and also doesn't compile with default gcc settings). See the getline manual page (http://linux.die.net/man/3/getline) for details.
With that change made, your program compiles and runs fine on my system.
I am also using MinGW. I checked MinGW headers and getline() does not appear in any C header, it appears only in C++ headers. This means the C function getline() does not exist in MinGW.
getline isn't a standard function, you need to set a feature test macro to use it, according to my man page,
_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
for glibc 2.10 or later,
_GNU_SOURCE
before that.
I have an application that has both two external kernel modules and a userspace daemon. I want to load the modules from the daemon code, written in C, at startup, and unload them on clean exit. Can I load them in a cleaner way than doing system("modprobe module"); and unload them using the corresponding rmmod?
init_module / remove_module minimal runnable example
Tested on a QEMU + Buildroot VM and Ubuntu 16.04 host with this simple parameter printer module .
We use the init_module / finit_module and remove_module Linux system calls.
The Linux kernel offers two system calls for module insertion:
init_module
finit_module
and:
man init_module
documents that:
The finit_module() system call is like init_module(), but reads the module to be loaded from the file descriptor fd. It is useful when the authenticity of a kernel module can be determined from its location in the filesystem; in cases where that is possible, the overhead of using cryptographically signed modules to determine the authenticity of a module can be avoided. The param_values argument is as for init_module().
finit is newer and was added only in v3.8. More rationale: https://lwn.net/Articles/519010/
glibc does not seem to provide a C wrapper for them, so we just create our own with syscall.
insmod.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values)
#define finit_module(fd, param_values, flags) syscall(__NR_finit_module, fd, param_values, flags)
int main(int argc, char **argv) {
const char *params;
int fd, use_finit;
size_t image_size;
struct stat st;
void *image;
/* CLI handling. */
if (argc < 2) {
puts("Usage ./prog mymodule.ko [args="" [use_finit=0]");
return EXIT_FAILURE;
}
if (argc < 3) {
params = "";
} else {
params = argv[2];
}
if (argc < 4) {
use_finit = 0;
} else {
use_finit = (argv[3][0] != '0');
}
/* Action. */
fd = open(argv[1], O_RDONLY);
if (use_finit) {
puts("finit");
if (finit_module(fd, params, 0) != 0) {
perror("finit_module");
return EXIT_FAILURE;
}
close(fd);
} else {
puts("init");
fstat(fd, &st);
image_size = st.st_size;
image = malloc(image_size);
read(fd, image, image_size);
close(fd);
if (init_module(image, image_size, params) != 0) {
perror("init_module");
return EXIT_FAILURE;
}
free(image);
}
return EXIT_SUCCESS;
}
GitHub upstream.
rmmod.c
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define delete_module(name, flags) syscall(__NR_delete_module, name, flags)
int main(int argc, char **argv) {
if (argc != 2) {
puts("Usage ./prog mymodule");
return EXIT_FAILURE;
}
if (delete_module(argv[1], O_NONBLOCK) != 0) {
perror("delete_module");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
GitHub upstream.
Busybox source interpretation
Busybox provides insmod, and since it is designed for minimalism, we can try to deduce how it is done from there.
On version 1.24.2, the entry point is at modutils/insmod.c function insmod_main.
The IF_FEATURE_2_4_MODULES is optional support for older Linux kernel 2.4 modules, so we can just ignore it for now.
That just forwards to modutils.c function bb_init_module.
bb_init_module attempts two things:
mmap the file to memory through try_to_mmap_module.
This always sets image_size to the size of the .ko file as a side effect.
if that fails, malloc the file to memory with xmalloc_open_zipped_read_close.
This function optionally unzips the file first if it is a zip, and just mallocs it otherwise.
I don't understand why this zipping business is done, since we can't even rely on it because the try_to_mmap_module does not seem to unzip things.
Finally comes the call:
init_module(image, image_size, options);
where image is the executable that was put into memory, and options are just "" if we call insmod file.elf without further arguments.
init_module is provided above by:
#ifdef __UCLIBC__
extern int init_module(void *module, unsigned long len, const char *options);
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif
ulibc is an embedded libc implementation, and it seems to provide init_module.
If it is not present, I think glibc is assumed, but as man init_module says:
The init_module() system call is not supported by glibc. No declaration is provided in glibc headers, but, through a quirk of history, glibc does export an ABI for
this system call. Therefore, in order to employ this system call, it is sufficient to manually declare the interface in your code; alternatively, you can invoke
the system call using syscall(2).
BusyBox wisely follows that advice and uses syscall, which glibc provides, and which offers a C API for system calls.
insmod/rmmod use the functions init_module and delete_module to do this, which also have a man-page available. They both declare the functions as extern instead of including a header, but the man-page says they should be in <linux/module.h>.
I'd recommend against the use of system() in any daemon code that runs with root permissions as it's relatively easy to exploit from a security standpoint. modprobe and rmmod are, indeed, the right tools for the job. However, it'd be a bit cleaner and much more secure to use an explicit fork() + exec() to invoke them.
I'm not sure there's a cleaner way than system.
But for sure, if you want to load/unload the modules from your userspace daemon, then you force yourself to run the daemon as root*, which may not be considered as secure.
*: or you can add the explicit commands in the sudoers file, but this will be a nightmare to manage when deploying your application.
You can perform the same tasks that modprobe and Co. do, but I doubt that could be characterized as cleaner.