How to make sure memory leak is being taken care of? - memory-leaks

When does operating system deallocate memory? I don't see it being deleted when I use Performance counters. See the below code. The difference between Memory usage before allocation and Memory usage after de-allocation should be 0 but its not.
Basically I have a COM dll hosted in dllhost which leaks memory (more than 2GB on 32 bit MS-OS).
#include "stdafx.h"
#include <stdlib.h>
#include <crtdbg.h>
#include <list>
#include <map>
//#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
using namespace std;
/*
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif // _DEBUG
*/
template <class K, class T, class Pr = less<K>, class A = allocator<T> >
class CTypedHeapPtrMap : public map<K, T, Pr, A >
{
public:
// Construction
CTypedHeapPtrMap()
{
};
// Destructor
~CTypedHeapPtrMap()
{
DeleteContents();
};
void DeleteContents()
{
iterator ItEntry;
/* Empty the list and delete memory */
ItEntry = begin();
while (ItEntry != end())
{
T pT = ItEntry->second;
delete[] pT;
pT = NULL;
ItEntry++;
}
map<K,T,Pr,A>::clear();
};
};
typedef CTypedHeapPtrMap<long, char*> VALIDATION_MAP;
int _tmain(int argc, _TCHAR* argv[])
{
PROCESS_MEMORY_COUNTERS_EX pmcx = {};
pmcx.cb = sizeof(pmcx);
GetProcessMemoryInfo(GetCurrentProcess(),reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), pmcx.cb);
//assumuing GetProcessMemoryInfo call above allocates some memory. So get the memory status again
pmcx.cb = sizeof(pmcx);
GetProcessMemoryInfo(GetCurrentProcess(),reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), pmcx.cb);
printf(" Memory usage (Before allocation) = %ld\n", pmcx.WorkingSetSize);
{
VALIDATION_MAP pStr;
char *ptr1 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(1, ptr1));
char *ptr2 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(2, ptr2));
char *ptr3 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(3, ptr3));
char *ptr4 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(4, ptr4));
char *ptr5 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(5, ptr5));
char *ptr6 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(6, ptr6));
char *ptr7 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(7, ptr7));
char *ptr8 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(8, ptr8));
char *ptr9 = new char[10000];
pStr.insert(VALIDATION_MAP::value_type(9, ptr9));
}
pmcx.cb = sizeof(pmcx);
GetProcessMemoryInfo(GetCurrentProcess(),reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), pmcx.cb);
printf(" Memory usage (After de-allocation) = %ld\n", pmcx.WorkingSetSize);
Sleep(60000);//sleep for a minute
return 0;
}

The system will deallocate the memory after the program using that memory is terminated, i.e., after the return 0 in your main. The memory has not been freed when your GetProcessMemoryInfo function is called, hence the large difference in memory usage when it should be zero. The system is in fact deallocating the memory (it always does), just after your program ends.
However, you should not feel like you're in the clear, you said the leak is 2GB of memory, that a LOT, I highly highly doubt your program needs that much memory to run. You really should consider finding places in your code to free memory for variables not being used.

Related

Get function from x64 instruction pointers?

This is an exercise that I want to implement in real code
I send a signal to my app (x86-64 linux). My app then executes code that walks the stack and prints out instruction pointers. I'm not sure if I want only the last few or everything to main. Anyway, I'm releasing an optimized binary without debug information. I strip symbols before its distributed.
I was wondering, how do I translate it back? I don't need to translate it in the app. I can use the machine I build to go from rip's to functions. I was thinking maybe I should also distribute one with debug information and maybe have the user be able to see the function+line but I think line will be unlikely if its optimized well
Another problem I have is my code doesn't seem to walk past the signal function. backtrace figures it out but I'm trying to do this without libc. Here's some code
#include <signal.h>
#include <cstdio>
typedef unsigned long long u64;
int mybacktrace();
#include <execinfo.h>
#include <unistd.h>
void print_stacktrace(void) {
size_t size;
enum Constexpr { MAX_SIZE = 1024 };
void *array[MAX_SIZE];
size = backtrace(array, MAX_SIZE);
backtrace_symbols_fd(array, size, STDOUT_FILENO);
}
void mysig(int signo) {
mybacktrace();
_exit(1);
}
int mybacktrace() {
u64*p;
p = (u64*)((u64)&p + 16); //seems to work correctly
for (int i = 0; i < 10 && (u64)p >= 1<<16; i++)
{
printf("%d %p\n", i, p[1]);
p = (u64*)(p[0]);
}
print_stacktrace(); return 0;
return 0;
}
int test()
{
return mybacktrace();
}
int main(int argc, char *argv[])
{
signal(SIGILL, mysig);
test();
__builtin_trap();
return 0;
}

Crash system when the module is running

I need to write a module that creates a file and outputs an inscription with a certain frequency. I implemented it. But when this module is running, at some point the system crashes and no longer turns on.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
#define BUF_LEN 255
#define TEXT "Hello from kernel mod\n"
int g_timer_interval = 10000;
static struct file *i_fp;
struct timer_list g_timer;
loff_t offset = 0;
char buff[BUF_LEN + 1] = TEXT;
void timer_rest(struct timer_list *timer)
{
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
i_fp = filp_open("/home/hajol/Test.txt", O_RDWR | O_CREAT, 0644);
kernel_write(i_fp, buff, strlen(buff), &offset);
filp_close(i_fp, NULL);
}
static int __init kernel_init(void)
{
timer_setup(&g_timer, timer_rest, 0);
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
return 0;
}
static void __exit kernel_exit(void)
{
pr_info("Ending");
del_timer(&g_timer);
}
module_init(kernel_init);
module_exit(kernel_exit);
When the system crashes, you should get a very detailed error message from the kernel, letting you know where and why this happened (the "oops" message):
Read that error message
Read it again
Understand what it means (this often requires starting over from step 1 a couple of times :-) )
One thing that jumps out at me is that you're not going any error checking on the return value of filp_open. So you could very well be feeding a NULL pointer (or error pointer) into kernel_write.

pthread_create allocates a lot of memory in Linux?

Here's a simple example
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
void* run(void*)
{
while (true)
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main()
{
std::vector<pthread_t> workers(192);
for (unsigned i = 0; i < workers.size(); ++i)
pthread_create(&workers[i], nullptr, &run, nullptr);
pthread_join(workers.back(), nullptr);
}
top shows 1'889'356 KiB VIRT! I know this isn't resident memory, but still, this is huge amount of memory for a single thread creation.
Is it really so memory-expensive (8MiB in this case) to create a thread? Is this configurable?
Or, maybe and most probably, I have some misunderstanding what virtual memory is?
Details:
I double quadruple-checked the memory usage, using:
generated a core dump of the running exe, it's also 1.6GB;
valgrind --tool=massif also confirms this size;
pmap -x <pid> also confirms the size.
As this size matches the max size of a stack (also confirmed by /proc/<pid>/limits), I tried to make the max size of the stack smaller. Tried with 1 MiB, but this didn't change anything.
Please, put aside the creation and usage of 192 threads, it has a reason behind it.
Sorry for the mixed C and C++ - initially tried with std::thread and the results are the same.
pthread_attr_setstacksize() function is available to set stack size.
This function have to be used with an thread attribute object.
The thread attribute object has to be passed as 2nd argument of pthread_create().
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
void* run(void*)
{
while (true)
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main()
{
std::vector<pthread_t> workers(192);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 16384);
for (unsigned i = 0; i < workers.size(); ++i)
pthread_create(&workers[i], &attr, &run, nullptr);
pthread_join(workers.back(), nullptr);
}

Memory Leak. FInding line number

So this is a homework project first and foremost. My whole program is working, it was an intermediate/advancedintro project to deal with dynamic memory allocation. I can't figure out how to display the line numbers with the normal output. I've attempted to look at the other questions on stack about this topic but I cannot seem to figure out a reason that helps me. Any suggestions to how to make the line number appear?
Here is my "LeakWatcher.cpp"
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
And my main()
int main()
{
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
try
{
Directory().Run();
}
catch ( ... )
{
cout << "Uncaught Exception" << endl;
}
_CrtDumpMemoryLeaks();
return 0;
}
Something that did occur to me based on your code is this. You say you placed all the debug macros into LeakWatcher.cpp and not LeakWatcher.h . I suspect this is your issue.
Create LeakWatcher.h with everything you currently have in your LeakWatcher.cpp. You don't need LeakWatcher.cpp so you should be able to remove it. Now use #include "LeakWatcher.h" at the top of all of your .cpp files. So it would look something like the following.
File LeakWatcher.h
#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{ return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); }
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard
Then in a file like test.cpp you can do this (similar to your test code):
#include "LeakWatcher.h"
int main()
{
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
new int[40]; // This should be a memory leak
_CrtDumpMemoryLeaks(); // This should dump with line numbers and file names
return 0;
}
Of course this will only work if you are building debug versions of your project.
To get some other insights into overriding these heap routines, I found this MSDN Article valuable.
I presume you're asking about the actual algorithm of keeping track of memory that's been allocated but not released.
The typical approach of keeping track of where your memory allocation requests came from, for the purposes of producing diagnostic output is as follows:
Say you want to track the caller requested n_bytes worth of memory.
Allocate n_bytes+sizeof(const char *)+sizeof(int).
Store FILE and LINE in the first part of the allocated memory, and return the rest of the allocated memory as supposedly what's been allocated.
Something like this:
struct hdr {
const char *file;
int line;
};
void *my_allocation_request(const char *file, int line, size_t nbytes)
{
struct hdr *p=(struct hdr *)malloc(nbytes+sizeof(hdr));
p->file=file;
p->line=line;
// Here be dragons
return (void *)(p+1);
}
(presumably, your new operator gets punted here).
Similar, when something wants to deallocate a memory block
void my_deallocation_request(char *p)
{
struct hdr *h=reinterpret_cast<hdr *>(p+1);
// Here be dragons
free(h);
}
Before this can be a final solution, you'll also need to write a bit more code that goes into the "Here be dragons" part, and I think you could probably figure it out yourself:
A) Take each newly allocated memory and put it on a list of some kind (the first location of dragons).
B) Remove the allocated memory from a list of some kind (the second location of dragons).
Then, at the end of your program, you can go through anything that's left on the list. That's going to be your leaked memory, and you'll have the file and the line number where it was allocated from.
Note that you'll probably want to implement the linked list of unreleased memory blocks manually. Using some standard container will probably result in an infinite loop, due to container's very reasonable expectation of being able to allocate memory for its own use, which will loop back into your own new/delete intercepts, which will ask the container to allocate more memory, which will loop back into your own new/delete intercepts, etc...
There might be some implementation-specific issues here regarding alignment of allocated memory, but it's unlikely, and this hair-splitting can probably be ignored, for now.

How do I use ioctl() to manipulate my kernel module?

So I'm trying to write a kernel module that uses the linux/timer.h file. I got it to work inside just the module, and now I am trying to get it to work from a user program.
Here is my kernel module:
//Necessary Includes For Device Drivers.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "mytimer"
#define DEVICE_FILE_NAME "mytimer"
#define MAJOR_NUM 61
#define MINOR_NUM 0
MODULE_LICENSE("Dual BSD/GPL");
static struct timer_list my_timer;
struct file_operations FileOps =
{
//No File Operations for this timer.
};
//Function to perform when timer expires.
void TimerExpire(int data)
{
printk("Timer Data: %d\n", data);
}
//Function to set up timers.
void TimerSetup(void)
{
setup_timer(&my_timer, TimerExpire, 5678);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(5000));
}
//Module Init and Exit Functions.
int init_module(void)
{
int initResult = register_chrdev(MAJOR_NUM, "mytimer", &FileOps);
if (initResult < 0)
{
printk("Cannot obtain major number %d\n", MAJOR_NUM);
return initResult;
}
printk("Loading MyTimer Kernel Module...\n");
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(MAJOR_NUM, "mytimer");
printk("Unloading MyTimer Kernel Module...\n");
}
More specifically, I want my user program to call the TimerSetup() function. I know that I'll need to use ioctl() but I'm not sure how to specify in my MODULE FILE that TimerSetup() should be callable via ioctl().
Also, my second question: I was able to insmod my module and also mknod into /dev/mytimer with the correct major number. But when I tried to open() it so that I can get the file descriptor from it, it kept returning -1, which I'm assuming is wrong. I made sure the permissions were fine (in fact, I made it 777 just to be sure)... It still doesn't work... Is there something I'm missing?
Here is the user program just in case:
#include <stdio.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/mytimer", "r");
printf("fd: %d\n", fd);
return 0;
}
The example code you need can be found in drivers/watchdog/softdog.c (from Linux 2.6.33 at the time this was written), which illustrates proper file operations as well as how to permit userland to fill a structure with ioctl().
It's actually a great, working tutorial for anyone who needs to write trivial character device drivers.
I dissected softdog's ioctl interface when answering my own question, which may be helpful to you.
Here's the gist of it (though far from exhaustive) ...
In softdog_ioctl() you see a simple initialization of struct watchdog_info that advertises functionality, version and device information:
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = "Software Watchdog",
};
We then look at a simple case where the user just wants to obtain these capabilities:
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
... which of course, will fill the corresponding userspace watchdog_info with the initialized values above. If copy_to_user() fails, -EFAULT is returned which causes the corresponding userspace ioctl() call to return -1 with a meaningful errno being set.
Note, the magic requests are actually defined in linux/watchdog.h , so that the kernel and userspace share them:
#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
#define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
#define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
WDIOC obviously signifying "Watchdog ioctl"
You can easily take that a step further, having your driver do something and place the result of that something in the structure and copy it to userspace. For instance, if struct watchdog_info also had a member __u32 result_code. Note, __u32 is just the kernel's version of uint32_t.
With ioctl(), the user passes the address of an object, be it a structure, integer, whatever to the kernel expecting the kernel to write its reply in an identical object and copy the results to the address that was provided.
The second thing you are going to need to do is make sure your device knows what to do when someone opens, reads from it, writes to it, or uses a hook like ioctl(), which you can easily see by studying softdog.
Of interest is:
static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
.unlocked_ioctl = softdog_ioctl,
.open = softdog_open,
.release = softdog_release,
};
Where you see the unlocked_ioctl handler going to ... you guessed it, softdog_ioctl().
I think you might be juxtaposing a layer of complexity that really doesn't exist when dealing with ioctl(), it really is that simple. For that same reason, most kernel developers frown on new ioctl interfaces being added unless they are absolutely necessary. Its just too easy to lose track of the type that ioctl() is going to fill vs the magic you use to do it, which is the primary reason that copy_to_user() fails often resulting in the kernel rotting with hordes of userspace processes stuck in disk sleep.
For a timer, I agree, ioctl() is the shortest path to sanity.
You are missing a .open function pointer in your file_operations structure to specify the function to be called when a process attempts to open the device file. You will need to specify a .ioctl function pointer for your ioctl function as well.
Try reading through The Linux Kernel Module Programming Guide, specifically chapters 4 (Character Device Files) and 7 (Talking to Device Files).
Chapter 4 introduces the file_operations structure, which holds pointers to functions defined by the module/driver that perform various operations such as open or ioctl.
Chapter 7 provides information on communicating with a module/drive via ioctls.
Linux Device Drivers, Third Edition is another good resource.
Minimal runnable example
Tested in a fully reproducible QEMU + Buildroot environment, so might help others get their ioctl working. GitHub upstream:
kernel module |
shared header |
userland.
The most annoying part was understanding that some low ids are hijacked: ioctl is not called if cmd = 2 , you have to use _IOx macros.
Kernel module:
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include "ioctl.h"
MODULE_LICENSE("GPL");
static struct dentry *dir;
static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
void __user *arg_user;
union {
int i;
lkmc_ioctl_struct s;
} arg_kernel;
arg_user = (void __user *)argp;
pr_info("cmd = %x\n", cmd);
switch (cmd) {
case LKMC_IOCTL_INC:
if (copy_from_user(&arg_kernel.i, arg_user, sizeof(arg_kernel.i))) {
return -EFAULT;
}
pr_info("0 arg = %d\n", arg_kernel.i);
arg_kernel.i += 1;
if (copy_to_user(arg_user, &arg_kernel.i, sizeof(arg_kernel.i))) {
return -EFAULT;
}
break;
case LKMC_IOCTL_INC_DEC:
if (copy_from_user(&arg_kernel.s, arg_user, sizeof(arg_kernel.s))) {
return -EFAULT;
}
pr_info("1 arg = %d %d\n", arg_kernel.s.i, arg_kernel.s.j);
arg_kernel.s.i += 1;
arg_kernel.s.j -= 1;
if (copy_to_user(arg_user, &arg_kernel.s, sizeof(arg_kernel.s))) {
return -EFAULT;
}
break;
default:
return -EINVAL;
break;
}
return 0;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = unlocked_ioctl
};
static int myinit(void)
{
dir = debugfs_create_dir("lkmc_ioctl", 0);
/* ioctl permissions are not automatically restricted by rwx as for read / write,
* but we could of course implement that ourselves:
* https://stackoverflow.com/questions/29891803/user-permission-check-on-ioctl-command */
debugfs_create_file("f", 0, dir, NULL, &fops);
return 0;
}
static void myexit(void)
{
debugfs_remove_recursive(dir);
}
module_init(myinit)
module_exit(myexit)
Shared header between the kernel module and userland:
ioctl.h
#ifndef IOCTL_H
#define IOCTL_H
#include <linux/ioctl.h>
typedef struct {
int i;
int j;
} lkmc_ioctl_struct;
#define LKMC_IOCTL_MAGIC 0x33
#define LKMC_IOCTL_INC _IOWR(LKMC_IOCTL_MAGIC, 0, int)
#define LKMC_IOCTL_INC_DEC _IOWR(LKMC_IOCTL_MAGIC, 1, lkmc_ioctl_struct)
#endif
Userland:
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "../ioctl.h"
int main(int argc, char **argv)
{
int fd, arg_int, ret;
lkmc_ioctl_struct arg_struct;
if (argc < 2) {
puts("Usage: ./prog <ioctl-file>");
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return EXIT_FAILURE;
}
/* 0 */
{
arg_int = 1;
ret = ioctl(fd, LKMC_IOCTL_INC, &arg_int);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d\n", arg_int);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
puts("");
/* 1 */
{
arg_struct.i = 1;
arg_struct.j = 1;
ret = ioctl(fd, LKMC_IOCTL_INC_DEC, &arg_struct);
if (ret == -1) {
perror("ioctl");
return EXIT_FAILURE;
}
printf("arg = %d %d\n", arg_struct.i, arg_struct.j);
printf("ret = %d\n", ret);
printf("errno = %d\n", errno);
}
close(fd);
return EXIT_SUCCESS;
}

Resources