undefined reference to `FIFORequestChannel::FIFORequestChannel - c++

I am trying to copy data values from one .csv file to another, but when I am compiling I keep getting an undefined reference error. I am confused because I made sure to include the header file. Can anyone provide any input?
client.cpp (main):
#include "common.h"
#include "FIFOreqchannel.h" // this is where I included the header file
#include <iostream>
#include <string>
#include <stdio.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char *argv[]){
cout<<"test"<<endl;
int n = 100; // default number of requests per "patient"
int p = 15; // number of patients
srand(time_t(NULL));
struct timeval tv; // this is the starting struct
struct timeval ts;// this is the ending struct
gettimeofday(&tv, NULL); // starts the clock
FIFORequestChannel chan ("control", FIFORequestChannel::CLIENT_SIDE); // this is the creation of the server
//datamsg first = datamsg(1,59.996, 2); // This is the creation of the first datamsg. It gets the information for the first person, up to 59.996 seconds, and gets info from the second ecg.
//The next step is to create the file
string file = "x1.csv";
//gettimeofdayI(&start, null);
ofstream inputfile;
inputfile.open(file); // opens the data for the first person
double seconds = 0.0;
while (seconds<59.996){
datamsg ecg1 = datamsg(1,seconds,1); // gets the data from the first ECG
datamsg ecg2 = datamsg(1,seconds,2); // gets the data from the second ECG
//cout<<test<<endl;
char*size= new char [sizeof(ecg1)];
*(datamsg*)size=ecg1;
chan.cwrite(size,sizeof(ecg1));
char * read=chan.cread();
double ecgfirst=*(double*)read;
inputfile<<ecgfirst<<","<<"\n";
char*size2= new char [sizeof(ecg2)];
*(datamsg*)size2=ecg2;
chan.cwrite(size2,sizeof(ecg2));
char * read2=chan.cread();
double ecgsecond=*(double*)read2;
inputfile<<ecgsecond<<","<<"\n";
seconds = seconds +.004; // this is the incrementation of the seconds
}
inputfile.close();
gettimeofday(&ts, NULL);
double totaltime; // this will count the total time of the process
totaltime = ts.tv_sec-tv.tv_sec;
cout<<" The total time to get the info for person is "<<totaltime<<"."<<endl;
// sending a non-sense message, you need to change this
char x = 55;
chan.cwrite (&x, sizeof (x));
char* buf = chan.cread ();
// closing the channel
MESSAGE_TYPE m = QUIT_MSG;
chan.cwrite (&m, sizeof (MESSAGE_TYPE));
}
FIFOreqchannel.h:
#ifndef _FIFOreqchannel_H_
#define _FIFOreqchannel_H_
#include "common.h"
class FIFORequestChannel
{
public:
enum Side {SERVER_SIDE, CLIENT_SIDE};
enum Mode {READ_MODE, WRITE_MODE};
private:
/* The current implementation uses named pipes. */
string my_name;
Side my_side;
int wfd;
int rfd;
string pipe1, pipe2;
int open_pipe(string _pipe_name, int mode);
public:
FIFORequestChannel(const string _name, const Side _side);
/* Creates a "local copy" of the channel specified by the given name.
If the channel does not exist, the associated IPC mechanisms are
created. If the channel exists already, this object is associated with the channel.
The channel has two ends, which are conveniently called "SERVER_SIDE" and "CLIENT_SIDE".
If two processes connect through a channel, one has to connect on the server side
and the other on the client side. Otherwise the results are unpredictable.
NOTE: If the creation of the request channel fails (typically happens when too many
request channels are being created) and error message is displayed, and the program
unceremoniously exits.
NOTE: It is easy to open too many request channels in parallel. Most systems
limit the number of open files per process.
*/
~FIFORequestChannel();
/* Destructor of the local copy of the bus. By default, the Server Side deletes any IPC
mechanisms associated with the channel. */
char* cread(int *len=NULL);
/* Blocking read of data from the channel. Returns a string of characters
read from the channel. Returns NULL if read failed. */
int cwrite(void *msg, int msglen);
/* Write the data to the channel. The function returns the number of characters written
to the channel. */
string name();
};
#endif
FIFOreqchannel.cpp:
#include "common.h"
#include "FIFOreqchannel.h"
using namespace std;
/*--------------------------------------------------------------------------
*/
/* CONSTRUCTOR/DESTRUCTOR FOR CLASS R e q u e s t C h a n n e l */
/*--------------------------------------------------------------------------
*/
FIFORequestChannel::FIFORequestChannel(const string _name, const Side _side)
: my_name( _name), my_side(_side){
pipe1 = "fifo_" + my_name + "1";
pipe2 = "fifo_" + my_name + "2";
if (_side == SERVER_SIDE){
wfd = open_pipe(pipe1, O_WRONLY);
rfd = open_pipe(pipe2, O_RDONLY);
}
else{
rfd = open_pipe(pipe1, O_RDONLY);
wfd = open_pipe(pipe2, O_WRONLY);
}
}
FIFORequestChannel::~FIFORequestChannel(){
close(wfd);
close(rfd);
remove(pipe1.c_str());
remove(pipe2.c_str());
}
int FIFORequestChannel::open_pipe(string _pipe_name, int mode){
mkfifo (_pipe_name.c_str (), 0600);
int fd = open(_pipe_name.c_str(), mode);
if (fd < 0){
EXITONERROR(_pipe_name);
}
return fd;
}
char* FIFORequestChannel::cread(int *len){
char * buf = new char [MAX_MESSAGE];
int length = read(rfd, buf, MAX_MESSAGE);
if (length < 0){
EXITONERROR ("Connection Error");
}
if (len) // the caller wants to know the length
*len = length;
return buf;
}
int FIFORequestChannel::cwrite(void* msg, int len){
if (len > MAX_MESSAGE){
cerr << "message length exceeds buffer size" << endl;
exit (-1);
}
if (write(wfd, msg, len) < 0){
EXITONERROR("cwrite");
}
return len;
}
The errors I am getting are undefined reference errors. So, I assume that it is a problem with linking, but I am confused because I included the header file.
Here are the errors I am getting:
client.cpp:(.text+0xc8): undefined reference to
`FIFORequestChannel::FIFORequestChannel(std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >, FIFORequestChannel::Side)'
client.cpp:(.text+0x22e): undefined reference to `FIFORequestChannel::cwrite(void*, int)'
client.cpp:(.text+0x242): undefined reference to `FIFORequestChannel::cread(int*)'
client.cpp:(.text+0x2f3): undefined reference to `FIFORequestChannel::cwrite(void*, int)'
client.cpp:(.text+0x307): undefined reference to `FIFORequestChannel::cread(int*)'
client.cpp:(.text+0x446): undefined reference to `FIFORequestChannel::cwrite(void*, int)'
client.cpp:(.text+0x45a): undefined reference to `FIFORequestChannel::cread(int*)'
client.cpp:(.text+0x489): undefined reference to `FIFORequestChannel::cwrite(void*, int)'
client.cpp:(.text+0x4b6): undefined reference to `FIFORequestChannel::~FIFORequestChannel()'
client.cpp:(.text+0x54d): undefined reference to `FIFORequestChannel::~FIFORequestChannel()'
collect2: error: ld returned 1 exit status
I am using Cloud 9 IDE on Amazon Webservices, and all the files are in the same folder.

I am confused because I made sure to include the header file.
Using #include "FIFOreqchannel.h" is necessary, but not sufficient to link your program. You must also supply FIFOreqchannel.o to the linker.
You are doing something like:
g++ client.cpp
You should do:
g++ client.cpp FIFOreqchannel.cpp ...other_object_files... ...other_libraries...

Related

FIFO: One process never reads from pipe

I'm following THIS TutorialsPoint guide to Linux Piping, and I specifically need to use FIFOs.
However, the code doesn't work at all for the server side.
The server file either hangs indefinitely or it reads nothing, while the client instead writes on the FIFO and immediately reads it has just written.
Here's the full code for both files in case you don't want to go through TutorialsPoint:
fifoserver_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1) {
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
}
return 0;
}
void reverse_string(char *str) {
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last) {
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
}
return;
}
fifoclient_twoway.cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
When I run both processes, this is what I get:
./fifoserver_twoway
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
FIFOSERVER: Received string: "" and length is 0
FIFOSERVER: Sending Reversed String: "" and length is 0
./fifoclient_twoway
FIFOCLIENT: Sent string: "ciao" and string length is 4
FIFOCLIENT: Received string: "ciao" and length is 4
Enter string: why won't you reverse?
FIFOCLIENT: Sent string: "why won't you reverse?" and string length is 29
FIFOCLIENT: Received string: "why won't you reverse?" and length is 29
It's also worth noting that before starting to write this question, the server behaviour was completely different: instead of receiving nothing and printing like you see here, it would hang indefinitely after the "read" (and I haven't changed the code one bit, except for changing the FIFO_FILE path)
You let the server sleep after writing – but not the client. That way, the client still might read its own output back before the server can fetch it. So at very least you should add a sleep after both writes, letting the server sleep a bit longer to make sure the client wakes up first to read the servers output.
Accessing the same end of unnamed pipes (created via pipe functions) concurrently is undefined behaviour. While not sure for named pipes, I'd assume pretty much the same there as well. Synchronising concurrent access to such ends via simple delays (sleep, usleep) might perhaps do the trick, but it is a pretty unsafe method.
I'd rather recommend two separate pipes instead (as Tony Tannous proposed already), one for each direction (open the respective ends RDONLY or WRONLY as needed), then you get full duplex communication instead of half duplex and you don't need further synchronisation either (delays in most simple variant):
// server
int fd_cs = open(FIFO_FILE_CS, O_RDONLY);
int fd_sc = open(FIFO_FILE_SC, O_WRONLY);
read(fd_cs, ...);
write(fd_sc, ...);
// client
int fd_cs = open(FIFO_FILE_CS, O_WRONLY);
int fd_sc = open(FIFO_FILE_SC, O_RDONLY);
write(fd_cs, ...);
read(fd_sc, ...);

Adafruit Fona 3g Library; How exactly does this work?

I am trying to send a packet to a server over 3g and TCP connection. Below is a link to the .cpp and .h file I have found:
https://os.mbed.com/users/Nels885/code/Adafruit_FONA_3G/
More specifically, I am really confused on how TCPSend works under the Adafruit_FONA_3G class. I am trying to implement it but my code seems to get stuck at packet[0] = 0; under function bool Adafruit_FONA_3G::TCPsend(char *packet).
I have tried commenting out packet[0] = 0; and the code runs all the way through. I have also tried initializing char* packet[32]; before packet[0] = 0; and the code runs all the way through. I am assuming the function is not detecting the packet input.
Here is the specific function from the .cpp file:
bool Adafruit_FONA_3G::TCPsend(char *packet)
{
if (strlen(packet) > 0)
{
mySerial.printf("%s", packet);
//mySerial.printf("%s\r\n", packet);
readline();
packet[0] = 0;
return true;
}
else
return false;
}
Here is my main code:
#include "mbed.h"
#include "Adafruit_FONA.h"
#define FONA_RST D4
#define FONA_TX D1
#define FONA_RX D0
#define FONA_RI D7 //not used
char replybuffer[255];
Adafruit_FONA_3G fona(FONA_TX, FONA_RX, FONA_RST, FONA_RI);
Serial pc(USBTX, USBRX);
int main()
{
fona.TCPinitialize();
char Timeout[21];
fona.getTCPtimeout(Timeout);
char * Server = "52.14.99.26";
uint16_t Port = 10001;
fona.TCPconnect(Server,Port);
char *Packet = "Pick Up %";
fona.TCPsend(Packet);
fona.TCPclose();
}
Adafruit_FONA_3G::TCPsend() assumes that you pass it a writable buffer. You're passing a read-only buffer. So, replace
char *Packet = "Pick Up %";
with
char Packet[] = "Pick Up %";
The problem is really that your compiler allows you to initialize writable pointers with read-only values. This is a shortcoming of your compiler.

Running an executable from a C++ program in the same process

Is that possible? I'd like an easy access to the executable's memory to edit it. Alternately, when I'm not the administrator, is it possible to edit the executable's memory from another process? I've tried the ptrace library and it fails if I'm not the administrator. I'm on Linux
I'm not entirely sure what you are asking, but this is possible with shared memory.
See here: http://www.kernel.org/doc/man-pages/online/pages/man7/shm_overview.7.html
This is what a debugger does. You could look at the code of an open source debugger, e.g. gdb, to see how it works.
The answer:
Yes - it works: you don't have to be administrator / root, but of course you need the rights to access the process' memory, i.e. same user.
No - it is not easy
The possibility to write to /proc/pid/mem was added some time ago to the Linux kernel. Therefore it depends on the kernel you are using. The small programs were checked with kernel 3.2 where this works and 2.6.32 where it fails.
The solution consists of two programs:
A 'server' which is started, allocates some memory, writes some pattern into this memory and outputs every three seconds the memory contents which is placed after the pattern is printed.
A 'client' which connects via the /proc/pid/maps and /proc/pid/mem to the server, searches for the pattern and writes some other string into the server's memory.
The implementation uses heap - but as long as the permissions allow - it is also possible to change other portions of the other process' memory.
This is implemented in C, because it is very 'low level' - but it should work in C++. It is a proof of concept - no production code - e.g. there are some error checks missing and it has some fixed size buffers.
memholder.c
/*
* Alloc memory - write in some pattern and print out the some bytes
* after the pattern.
*
* Compile: gcc -Wall -Werror memholder.c -o memholder.o
*/
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main() {
char * m = (char*) malloc(2048);
memset(m, '\xAA', 1024);
strcpy(m + 1024, "Some local data.");
printf("PID: %d\n", getpid());
while(1) {
printf("%s\n", m + 1024);
sleep(3);
}
return 0;
}
memwriter.c
/*
* Searches for a pattern in the given PIDs memory
* and changes some bytes after them.
*
* Compile: gcc -Wall -std=c99 -Werror memwriter.c -o memwriter
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
int open_proc_file(pid_t other_pid, char const * const sn,
int flags) {
char fname[1024];
snprintf(fname, 1023, "/proc/%d/%s", other_pid, sn);
// Open file for reading and writing
int const fd = open(fname, flags );
if(fd==-1) {
perror("Open file");
exit(1);
}
return fd;
}
void get_heap(int fd_maps, size_t * heap_start, size_t * heap_end) {
char buf[65536];
ssize_t const r = read(fd_maps, buf, 65535);
if(r==-1) {
perror("Reading maps file");
exit(1);
}
buf[r] = '\0';
char * const heap = strstr(buf, "[heap]");
if(heap==NULL) {
printf("[heap] not found in maps file");
exit(1);
}
// Look backward to the latest newline
char const * hl_start;
for(hl_start = heap; hl_start > buf && *hl_start != '\n';
--hl_start) {}
// skip \n
++hl_start;
// Convert to beginnig and end address
char * lhe;
*heap_start = strtol(hl_start, &lhe, 16);
++lhe;
*heap_end = strtol(lhe, &lhe, 16);
}
int main(int argc, char *argv[]) {
if(argc!=2) {
printf("Usage: memwriter <pid>\n");
return 1;
}
pid_t const other_pid = atoi(argv[1]);
int fd_mem = open_proc_file(other_pid, "mem", O_RDWR);
int fd_maps = open_proc_file(other_pid, "maps", O_RDONLY);
size_t other_mem_start;
size_t other_mem_end;
get_heap(fd_maps, &other_mem_start, &other_mem_end);
ptrace(PTRACE_ATTACH, other_pid, NULL, NULL);
waitpid(other_pid, NULL, 0);
if( lseek(fd_mem, other_mem_start, SEEK_SET) == -1 ) {
perror("lseek");
return 1;
}
char buf[512];
do {
ssize_t const r = read(fd_mem, buf, 512);
if(r!=512) {
perror("read?");
break;
}
// Check for pattern
int pat_found = 1;
for(int i = 0; i < 512; ++i) {
if( buf[i] != '\xAA' )
pat_found = 0;
break;
}
if( ! pat_found ) continue;
// Write about one k of strings
char const * const wbuf = "REMOTE DATA - ";
for(int i = 0; i < 70; ++i) {
ssize_t const w = write(fd_mem, wbuf, strlen(wbuf));
if( w == -1) {
perror("Write");
return 1;
}
}
// Append a \0
write(fd_mem, "\0", 1);
break;
} while(1);
ptrace(PTRACE_DETACH, other_pid, NULL, NULL);
close(fd_mem);
close(fd_maps);
return 0;
}
Example output
$ ./memholder
PID: 2621
Some local data.
Some local data.
MOTE DATA - REMOTE DA...
Other interpretation
There is also another interpretation of your question (when reading the headline and not the question), that you want to replace the 'executable' from one process with another one. That can be easily handled by exec() (and friends):
From man exec:
The exec() family of functions replaces the current process image with a new process image.
In Windows, the methods used for this are named ReadProcessMemory / WriteProcessMemory, you will, however, need administrative rights for this. The same is for linux, as I've said in my comment, no sane system would allow user process to modify non-owned memory.
For linux, the only function is ptrace. You will need to be administrator.
http://cboard.cprogramming.com/cplusplus-programming/92093-readprocessmemory-writeprocessmemory-linux-equivalent.html contains more detailed discussion.
Can you imagine the consequences of allowing process to modify other process memory, without being administrator?

inotify notifies of a new file wrongly multiple times

Using inotify to monitor a directory for any new file created in the directory by adding a watch on the directory by
fd = inotify_init();
wd = inotify_add_watch(fd, "filename_with_path", IN_CLOSE_WRITE);
inotify_add_watch(fd, directory_name, IN_CLOSE_WRITE);
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
while(true) {
char buf[buf_len];
int no_of_events, count = 0;
no_of_events = read(fd, buf, buf_len);
while(count < no_of_events) {
struct inotify_event *event = (struct inotify_event *) &buf[count];
if (event->len) {
if (event->mask & IN_CLOSE_WRITE) {
if (!(event->mask & IN_ISDIR)) {
//It's here multiple times
}
}
}
count += event_size + event->len;
}
When I scp a file to the directory, this loops infinitely. What is the problem with this code ? It shows the same event name and event mask too. So , it shows that the event for the same, infinite times.
There are no break statements. If I find an event, I just print it and carry on waiting for another event on read(), which should be a blocking call. Instead, it starts looping infinitely. This means, read doesn't block it but returns the same value for one file infinitely.
This entire operation runs on a separate boost::thread.
EDIT:
Sorry all. The error I was getting was not because of the inotify but because of sqlite which was tricky to detect at first. I think I jumped the gun here. With further investigation, I did find that the inotify works perfectly well. But the error actually came from the sqlite command : ATTACH
That command was not a ready-only command as it was supposed to. It was writing some meta data to the file. So inotify gets notification again and again. Since they were happening so fast, it screwed up the application.I finally had to breakup the code to understand why.
Thanks everyone.
I don't see anything wrong with your code...I'm running basically the same thing and it's working fine. I'm wondering if there's a problem with the test, or some part of the code that's omitted. If you don't mind, let's see if we can remove any ambiguity.
Can you try this out (I know it's almost the same thing, but just humor me) and let me know the results of the exact test?
1) Put the following code into test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/inotify.h>
int main (int argc, char *argv[])
{
char target[FILENAME_MAX];
int result;
int fd;
int wd; /* watch descriptor */
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
strcpy (target, ".");
fd = inotify_init();
if (fd < 0) {
printf ("Error: %s\n", strerror(errno));
return 1;
}
wd = inotify_add_watch (fd, target, IN_CLOSE_WRITE);
if (wd < 0) {
printf ("Error: %s\n", strerror(errno));
return 1;
}
while (1) {
char buff[buf_len];
int no_of_events, count = 0;
no_of_events = read (fd, buff, buf_len);
while (count < no_of_events) {
struct inotify_event *event = (struct inotify_event *)&buff[count];
if (event->len){
if (event->mask & IN_CLOSE_WRITE)
if(!(event->mask & IN_ISDIR)){
printf("%s opened for writing was closed\n", target);
fflush(stdout);
}
}
count += event_size + event->len;
}
}
return 0;
}
2) Compile it with gcc:
gcc test.c
3) kick it off in one window:
./a.out
4) in a second window from the same directory try this:
echo "hi" > blah.txt
Let me know if that works correctly to show output every time the file is written to and does not loop as your code does. If so, there's something important your omiting from your code. If not, then there's some difference in the systems.
Sorry for putting this in the "answer" section, but too much for a comment.
My guess is that read is returning -1 and since you dont ever try to fix the error, you get another error on the next call to read which also returns -1.

How do I programmatically get the free disk space for a directory in Linux

Is there a function that returns how much space is free on a drive partition given a directory path?
check man statvfs(2)
I believe you can calculate 'free space' as f_bsize * f_bfree.
NAME
statvfs, fstatvfs - get file system statistics
SYNOPSIS
#include <sys/statvfs.h>
int statvfs(const char *path, struct statvfs *buf);
int fstatvfs(int fd, struct statvfs *buf);
DESCRIPTION
The function statvfs() returns information about a mounted file system.
path is the pathname of any file within the mounted file system. buf
is a pointer to a statvfs structure defined approximately as follows:
struct statvfs {
unsigned long f_bsize; /* file system block size */
unsigned long f_frsize; /* fragment size */
fsblkcnt_t f_blocks; /* size of fs in f_frsize units */
fsblkcnt_t f_bfree; /* # free blocks */
fsblkcnt_t f_bavail; /* # free blocks for unprivileged users */
fsfilcnt_t f_files; /* # inodes */
fsfilcnt_t f_ffree; /* # free inodes */
fsfilcnt_t f_favail; /* # free inodes for unprivileged users */
unsigned long f_fsid; /* file system ID */
unsigned long f_flag; /* mount flags */
unsigned long f_namemax; /* maximum filename length */
};
You can use boost::filesystem:
struct space_info // returned by space function
{
uintmax_t capacity;
uintmax_t free;
uintmax_t available; // free space available to a non-privileged process
};
space_info space(const path& p);
space_info space(const path& p, system::error_code& ec);
Example:
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
space_info si = space(".");
cout << si.available << endl;
Returns: An object of type space_info. The value of the space_info object is determined as if by using POSIX statvfs() to obtain a POSIX struct statvfs, and then multiplying its f_blocks, f_bfree, and f_bavail members by its f_frsize member, and assigning the results to the capacity, free, and available members respectively. Any members for which the value cannot be determined shall be set to -1.
With C++17
You can use std::filesystem::space:
#include <iostream> // only needed for screen output
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::space_info tmp = fs::space("/tmp");
std::cout << "Free space: " << tmp.free << '\n'
<< "Available space: " << tmp.available << '\n';
}
You can use Qt class QStorageInfo to acquire hardisk free space:
First,you should include the header:
#include <QStorageInfo>
#define GB (1024 * 1024 * 1024)
bool CheckHardiskFree(const QString &strDisk)
{
QStorageInfo storage(strDisk);
if(storage.isValid() && storage.isReady())
{
double useGb =(storage.bytesTotal()-storage.bytesAvailable()) * 1.0/ GB;
double freeGb =storage.bytesAvailable() * 1.0 / GB;
double allGb =storage.bytesTotal()* 1.0 / GB;
return true;
}
return false;
}
One can get the output of a command into a program by using a pipe like this:
char cmd[]="df -h /path/to/directory" ;
FILE* apipe = popen(cmd, "r");
// if the popen succeeds read the commands output into the program with
while ( fgets( line, 132 , apipe) )
{ // handle the readed lines
}
pclose(apipe);
// -----------------------------------