mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
a quick C cat
This commit is contained in:
@@ -17108,6 +17108,7 @@ Good sanity check for user mode: <<qemu-user-mode-getting-started>>
|
|||||||
*** link:userland/c/stderr.c[]
|
*** link:userland/c/stderr.c[]
|
||||||
*** File IO
|
*** File IO
|
||||||
**** link:userland/c/file_write_read.c[]
|
**** link:userland/c/file_write_read.c[]
|
||||||
|
***** link:userland/c/cat.c[]: a quick and dirty `cat` implementation for interactive <<user-mode-simulation>> tests
|
||||||
**** link:userland/linux/open_o_tmpfile.c[]: https://stackoverflow.com/questions/4508998/what-is-an-anonymous-inode-in-linux/44388030#44388030
|
**** link:userland/linux/open_o_tmpfile.c[]: https://stackoverflow.com/questions/4508998/what-is-an-anonymous-inode-in-linux/44388030#44388030
|
||||||
** `time.h`
|
** `time.h`
|
||||||
*** link:userland/c/timespec_get.c[] `timespec_get` is a C11 for `clock_gettime` http://stackoverflow.com/questions/361363/how-to-measure-time-in-milliseconds-using-ansi-c/36095407#36095407
|
*** link:userland/c/timespec_get.c[] `timespec_get` is a C11 for `clock_gettime` http://stackoverflow.com/questions/361363/how-to-measure-time-in-milliseconds-using-ansi-c/36095407#36095407
|
||||||
|
|||||||
66
lkmc/file_io.h
Normal file
66
lkmc/file_io.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef LKMC_FILE_IO_H
|
||||||
|
#define LKMC_FILE_IO_H
|
||||||
|
|
||||||
|
/* Returns the size of the given open `FILE*`.
|
||||||
|
*
|
||||||
|
* If an error occurs, returns `-1L`.
|
||||||
|
*
|
||||||
|
* Does not work for pipes.
|
||||||
|
*/
|
||||||
|
long lkmc_fget_file_size(FILE *fp) {
|
||||||
|
long oldpos;
|
||||||
|
long return_value;
|
||||||
|
oldpos = ftell(fp);
|
||||||
|
if (oldpos == -1L) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
if (fseek(fp, 0, SEEK_END) != 0) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
return_value = ftell(fp);
|
||||||
|
if (return_value == -1L) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
/* Restore the old position. */
|
||||||
|
if (fseek(fp, oldpos , SEEK_SET) != 0) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the entire file to a char[] dynamically allocated inside this function.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the start of that array.
|
||||||
|
*
|
||||||
|
* In case of any error, returns NULL.
|
||||||
|
*
|
||||||
|
* http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c
|
||||||
|
*/
|
||||||
|
char *lkmc_file_read(char *path) {
|
||||||
|
FILE *fp;
|
||||||
|
char *buffer;
|
||||||
|
long fsize;
|
||||||
|
|
||||||
|
fp = fopen(path , "rb");
|
||||||
|
if (fp == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fsize = lkmc_fget_file_size(fp);
|
||||||
|
if (fsize < 0){
|
||||||
|
fprintf(stderr, "could not determine lenght of:\n%s\n", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buffer = (char*)malloc(fsize);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (fread(buffer, 1, fsize, fp) != (size_t)fsize) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (fclose(fp) == EOF){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -67,7 +67,6 @@ class PathProperties:
|
|||||||
'no_build': False,
|
'no_build': False,
|
||||||
# The path does not generate an executable in itself, e.g.
|
# The path does not generate an executable in itself, e.g.
|
||||||
# it only generates intermediate object files. Therefore it
|
# it only generates intermediate object files. Therefore it
|
||||||
# should not be run while testing.
|
|
||||||
'no_executable': False,
|
'no_executable': False,
|
||||||
'qemu_unimplemented_instruction': False,
|
'qemu_unimplemented_instruction': False,
|
||||||
# The script requires a non-trivial to determine argument to be passed to run properly.
|
# The script requires a non-trivial to determine argument to be passed to run properly.
|
||||||
@@ -655,8 +654,8 @@ path_properties_tuples = (
|
|||||||
'test_run_args': {'cpus': 3},
|
'test_run_args': {'cpus': 3},
|
||||||
},
|
},
|
||||||
'assert_fail.c': {'signal_received': signal.Signals.SIGABRT},
|
'assert_fail.c': {'signal_received': signal.Signals.SIGABRT},
|
||||||
# This has complex failure modes, too hard to assert.
|
# Not sure which argument to pass.
|
||||||
'smash_stack.c': {'skip_run_unclassified': True},
|
'cat.c': {'skip_run_unclassified': True},
|
||||||
'exit1.c': {'exit_status': 1},
|
'exit1.c': {'exit_status': 1},
|
||||||
'exit2.c': {'exit_status': 2},
|
'exit2.c': {'exit_status': 2},
|
||||||
'false.c': {'exit_status': 1},
|
'false.c': {'exit_status': 1},
|
||||||
@@ -666,6 +665,8 @@ path_properties_tuples = (
|
|||||||
'm5ops.c': {'allowed_emulators': {'gem5'}},
|
'm5ops.c': {'allowed_emulators': {'gem5'}},
|
||||||
'return1.c': {'exit_status': 1},
|
'return1.c': {'exit_status': 1},
|
||||||
'return2.c': {'exit_status': 2},
|
'return2.c': {'exit_status': 2},
|
||||||
|
# This has complex failure modes, too hard to assert.
|
||||||
|
'smash_stack.c': {'skip_run_unclassified': True},
|
||||||
# Wrapper not defined by newlib.
|
# Wrapper not defined by newlib.
|
||||||
'timespec_get.c': {'baremetal': False},
|
'timespec_get.c': {'baremetal': False},
|
||||||
}
|
}
|
||||||
|
|||||||
13
userland/c/cat.c
Normal file
13
userland/c/cat.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <lkmc/file_io.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
assert(argc == 2);
|
||||||
|
char *s = lkmc_file_read(argv[1]);
|
||||||
|
puts(s);
|
||||||
|
free(s);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -1,38 +1,12 @@
|
|||||||
/* https://cirosantilli.com/linux-kernel-module-cheat#c */
|
/* https://cirosantilli.com/linux-kernel-module-cheat#c */
|
||||||
|
|
||||||
#include <lkmc.h>
|
#include <lkmc.h>
|
||||||
|
#include <lkmc/file_io.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/* Returns the size of the given open `FILE*`.
|
|
||||||
*
|
|
||||||
* If an error occurs, returns `-1L`.
|
|
||||||
*
|
|
||||||
* Does not work for pipes.
|
|
||||||
*/
|
|
||||||
long fget_file_size(FILE *fp) {
|
|
||||||
long oldpos;
|
|
||||||
long return_value;
|
|
||||||
oldpos = ftell(fp);
|
|
||||||
if (oldpos == -1L) {
|
|
||||||
return -1L;
|
|
||||||
}
|
|
||||||
if (fseek(fp, 0, SEEK_END) != 0) {
|
|
||||||
return -1L;
|
|
||||||
}
|
|
||||||
return_value = ftell(fp);
|
|
||||||
if (return_value == -1L) {
|
|
||||||
return -1L;
|
|
||||||
}
|
|
||||||
/* Restore the old position. */
|
|
||||||
if (fseek(fp, oldpos , SEEK_SET) != 0) {
|
|
||||||
return -1L;
|
|
||||||
}
|
|
||||||
return return_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Same as `file_size`, but takes the path instead of a `FILE*`. */
|
/* Same as `file_size`, but takes the path instead of a `FILE*`. */
|
||||||
long file_size(char *path) {
|
long file_size(char *path) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -41,48 +15,13 @@ long file_size(char *path) {
|
|||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
return_value = fget_file_size(fp);
|
return_value = lkmc_fget_file_size(fp);
|
||||||
if (fclose(fp) == EOF) {
|
if (fclose(fp) == EOF) {
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the entire file to a char[] dynamically allocated inside this function.
|
|
||||||
*
|
|
||||||
* Returns a pointer to the start of that array.
|
|
||||||
*
|
|
||||||
* In case of any error, returns NULL.
|
|
||||||
*
|
|
||||||
* http://stackoverflow.com/questions/174531/easiest-way-to-get-files-contents-in-c
|
|
||||||
*/
|
|
||||||
char *file_read(char *path) {
|
|
||||||
FILE *fp;
|
|
||||||
char *buffer;
|
|
||||||
long fsize;
|
|
||||||
|
|
||||||
fp = fopen(path , "rb");
|
|
||||||
if (fp == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
fsize = fget_file_size(fp);
|
|
||||||
if (fsize < 0){
|
|
||||||
fprintf(stderr, "could not determine lenght of:\n%s\n", path);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
buffer = (char*)malloc(fsize);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (fread(buffer, 1, fsize, fp) != (size_t)fsize) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (fclose(fp) == EOF){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a null terminated string to file
|
/* Write a null terminated string to file
|
||||||
*
|
*
|
||||||
* Return -1 on failure, 0 on success.
|
* Return -1 on failure, 0 on success.
|
||||||
@@ -117,9 +56,9 @@ int main(void) {
|
|||||||
|
|
||||||
/* Read entire file at once to a string. */
|
/* Read entire file at once to a string. */
|
||||||
{
|
{
|
||||||
char *output = file_read(path);
|
char *output = lkmc_file_read(path);
|
||||||
if (output == NULL) {
|
if (output == NULL) {
|
||||||
LKMC_IO_ERROR("file_read", path);
|
LKMC_IO_ERROR("lkmc_file_read", path);
|
||||||
}
|
}
|
||||||
assert(strcmp(data, output) == 0);
|
assert(strcmp(data, output) == 0);
|
||||||
free(output);
|
free(output);
|
||||||
|
|||||||
Reference in New Issue
Block a user