Using fprintf at a C++ code - c++

I have an odd problem. When I try to compile the code below, it works without a failure as expected:
#include <iostream>
#include <Windows.h>
int main(){
FILE *f = fopen("trystl.geo","w");
fprintf(f,"Merge \"trystl.stl\";");
fprintf(f,"\n");
fprintf(f,"Surface Loop(2) = {1};");
fprintf(f,"\n");
fprintf(f,"Volume(3) = {2};");
fclose(f);
return 0;
}
But when I try to connect this program to a button with FLTK user interface, it gives me an assertion runtime error. The segment of my code:
void UserInterface::cb_m_BtnSTLToGEOConverter_i(Fl_Button*, void*){
//OnSTLToGEOConvert();
FILE *f = fopen("trystl.geo","w");
fprintf(f,"Merge \"trystl.stl\";");
fprintf(f,"\n");
fprintf(f,"Surface Loop(2) = {1};");
fprintf(f,"\n");
fprintf(f,"Volume(3) = {2};");
fclose(f);
}
void UserInterface::cb_m_BtnSTLToGEOConverter(Fl_Button* o, void* v){
((UserInterface*)(o->parent()->parent()->parent()->parent()->parent()->parent()->parent()->user_data()))->cb_m_BtnSTLToGEOConverter_i(o,v);
}
When the user presses the button, I want the program to create a file called trystl.geo and perform the operations shown. But when compile and open the program and click the button, it says:
Debug Assertion Failed!
Program: *.......\src\fprintf.c Line 55:
Expression: (str! NULL)
abort retry or ignore...
I'm using Visual Studio 2010.

The error is simple: Line 55 in fprintf.c in VC++ is _VALIDATE_RETURN( (str != NULL), EINVAL, -1); and str is the FILE* parameter (I've seen better named variables though).
For the curious (I was) _VALIDATE_RETURN is defined as follows:
#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
{ \
int _Expr_val=!!(expr); \
_ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
if ( !( _Expr_val ) ) \
{ \
errno = errorcode; \
_INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
return ( retexpr ); \
} \
}
So better check if your fopen() call succeeds before trying to write to a nonexistant filedescriptor.

OK I found the solution. The only problem is that if you don't type in the whole path in the program, the file doesn't get opened. I replaced
FILE *f = fopen("trystl.geo","w");
with
FILE *f = fopen("c:/Users/anypath/trystl.geo","w");
it works!
Thank you for all your help!

Related

Why can't I run some programs after using unshare(CLONE_NEWUSER)

I'm working on adding some restrictions to my build process - to detect cycles, specifically. To achieve this I've been experimenting with user namespaces.
Here's my 'hello world' program:
#include <sched.h>
#include <unistd.h>
int main()
{
if( unshare(CLONE_NEWUSER) != 0)
{
return -1;
}
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}
Here is the makefile being run by make, namespace_test.cpp is the name of the file above:
namespace_test: namespace_test.cpp
g++ namespace_test.cpp -o ./namespace_test
When everything is up to date (as determined by make) the exec'd program works as expected:
make: 'namespace_test' is up to date.
But if make actually runs the g++ invocation I get an opaque error:
g++ namespace_test.cpp -o ./namespace_test
make: g++: Invalid argument
make: *** [Makefile:2: namespace_test] Error 127
What is the reason for this behavior?
This error was due to my failure to set up the uid_map and gid_map. I have not produced a satisfactory, explicit, minimal example of the error, but I have written a working minimal solution, that I will share here. Notice that int main() is identical, except before exec'ing the target command we first set up the uid_map and then the gid_map (granting ourselves permission via setgroups).
On my terminal $ id informs me that my real uid and gid are both 1000, so I have hardcoded that in the maps. It is more correct to query for the original id at the start of the process, see this excellent blog post. Also instrumental in this solution is this man page.
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#define fatal_error(...) \
do { \
fprintf(stderr, "namespace_test \033[1;31merror:\033[0m "); \
fprintf(stderr, __VA_ARGS__ ); \
fprintf(stderr, "\n"); \
exit(EXIT_FAILURE); \
} while(0)
void write_string_to_file(const char* filename, const char* str, size_t str_len)
{
int fd = open(filename, O_RDWR);
if(fd == -1)
{
fatal_error("Failed to open %s: %m", filename);
}
if( write(fd, str, str_len) != str_len )
{
fatal_error("Failed to write %s: %m", filename);
}
close(fd);
}
void write_uid_mapping()
{
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/uid_map", mapping, strlen(mapping));
}
void write_set_groups()
{
const char* deny = "deny\n";
write_string_to_file("/proc/self/setgroups", deny, strlen(deny));
}
void write_gid_mapping()
{
write_set_groups();
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/gid_map", mapping, strlen(mapping));
}
int main()
{
if(unshare(CLONE_NEWUSER) != 0)
{
fatal_error("Failed to move into new user namespace");
}
write_uid_mapping();
write_gid_mapping();
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}

How to search and move files from one path to another C++?

I'm trying to search all files that follow this pattern "console-*" and move them to another path on my machine if they exist. (For example from: /documents/fs/pstore to /sdk/sys/kernel_dump/).
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int dirExists(const char *pathname)
{
struct stat info;
if( stat( pathname, &info ) != 0 )
return 0; // printf( "cannot access %s\n", pathname );
else if( info.st_mode & S_IFDIR ) // S_ISDIR() doesn't exist on my windows
return 1; // printf( "%s is a directory\n", pathname );
else
return 0; // printf( "%s is no directory\n", pathname );
}
int main()
{
const char *path = "/documents/fs/pstore";
if(dirExists(path))
system("mv /documents/fs/pstore/console-* /sdk/sys/kernel_dump/ ");
else
printf( "error" );
return 0;
}
I've experienced with the code above, but it does not seem to work properly, should I try another approach, maybe with the rename() function? (I'm working on Linux)
Any advice would be greatly appreciated, thank you in advance.
You can call glob() and rename() C functions in Linux if C++17's std::filesystem is not an option for you. glob() gives you the list of files that matches globbing pattern like *, ? and []. However, rename() may fail if the mount position of from and to path are not identical. In this case, you should create your own copy and remove file function.

Fail to write to /proc/<pid>/coredump_filter

My code(below) fails:
11:Resource temporarily unavailable
The code is running as root (in an abrt hook) but has seteuid to the user that the pid in question is running as.
Writing to /proc/self/coredump_filter from within the process works OK.
How can I write to the coredump_filter from the abrt hook?
void SetDumpFlags(pid_t pid, int dumpflags){
std::string c_filter_name = "/proc/" + std::to_string( pid ) + "/coredump_filter";
int f = open( c_filter_name.c_str(), O_WRONLY );
if (f < 0) {
fprintf( log, "Couldn't open %s\n", c_filter_name.c_str());
bail_out(1);
}
int wsz = write( f, &dumpflags, sizeof dumpflags);
if (wsz != sizeof dumpflags){
fprintf( log, "Couldn't write to %s, %d:%s\n", c_filter_name.c_str(),errno, strerror(errno));
close( f );
bail_out(1);
}
close( f );
fprintf( log, "Pid %d, dump filter set to 0x%x\n", pid, dumpflags);
}
I tried to replicate your problem with a C example
(I would use C++11 but I'm on an ancient netbook without C++11 and it'd be hard to get it here and aclimate in the language).
I got an EACCESS on the open (and my guess you might be getting it too but the errno could get overwritten elsewhere?).
It seems the coredump_filter (at least on this Linux 3.2) starts as owned by
root and the seteuid doesn't change it.
I tried chown before setuid to no avail.
What did work (as expected) was to open the fd while you're still root
and keep it open during the seteuid call.
Then I could write to the file again successfully even after my euid changed.
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define FLAGS "0x11"
#define FLAGSSZ (sizeof(FLAGS)-1)
int main()
{
pid_t pid = getpid();
char buf[sizeof("/proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(buf,"/proc/%ld/coredump_filter",(long)pid);
int f;
if(0>(f=open(buf,O_WRONLY|O_TRUNC))) {perror("open");exit(1);}
if(FLAGSSZ != write(f,FLAGS,FLAGSSZ)){perror("write");exit(1);}
puts("ok");
char cat[sizeof("cat /proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(cat,"cat /proc/%ld/coredump_filter", (long)pid);
system(cat);
char ls[sizeof("ls -l /proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(ls,"ls -l /proc/%ld/coredump_filter", (long)pid);
system(ls); //owned by root, not writable by others
if(0>chown(buf,getuid(),getgid())){perror("chown"); exit(1); }
//chown returns success but ls -l doesn't agree
system(ls); //still owned by root
if(0>seteuid(getuid())){
perror("seteuid");
exit(1);
}
//can't reopen because of the perms but can still
//use the old fd if we kept it open
if(0>lseek(f,SEEK_SET,0)){perror("lseek"); exit(1);}
#define ALTFLAGS "0x22"
#define ALTFLAGSSZ (sizeof(ALTFLAGS)-1)
if(ALTFLAGSSZ != write(f,ALTFLAGS,ALTFLAGSSZ)){perror("write");exit(1);}
puts("ok");
system(cat);
}
I compiled with gcc c.c and made the a.out setuid root with sudo sh -c 'chown 0 $1 && chmod u+s $1' - a.out before running it.
I was trying to write data to the coredump_filter whereas I should have written a string! Doing it with a literal (e.g. #define FLAGS "0x11" as in the answer given by PSkocik ) fixes the problem.
The /proc/nnnnn/coredump_filter file is owned by the user that process nnnnn is running as. In my case this is root for some processes and another user for others. Switching user (in the abrt hook) to the appropriate user, before trying to write the coredump_filter, works OK.

QJson for Linux - Unsure How to Use QJSON Correctly

Some Background
Originally made a project on mac, now I want to use my Linux machine for the same project. The settings folder relied on:
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonParseError>
These weren't included in my qt-devel install for SL5 - it uses QT v4. So I downloaded QJson from Sourceforge and installed using cmake. Some example output:
--Installing: /usr/include/qjson/parser.h
--Installing /usr/lib/libqjson.so
That's fine. So I added to my .pro:
LIBS += -L/usr/lib/ -lqjson
INCLUDEPATH += /usr/include/qjson/
The Actual Problem
Now I have the task of translating my old settings.cpp file to parse data in this slightly new method.
{
"HwDescription": {
"ConnectionsName": "file://settings/connections.xml",
"ShelveId": 0,
"BeBoard": {
"Id": 10,
"connectionId": "board0",
"boardType": "GLIB"
}, // + more boring stuff
So now I have this json above in a QString, just as I did for my old working method, then I try to parse as per the instructions given to me. I used: #include <qjson/parser.h> and I don't think I need any forward declarations here.
QJson::Parser parser;
bool ok;
QVariantMap result = parser.parse (raw_json, &ok).toMap(); //where raw_json is a QString - this is where I get an error
if (!ok)
{
qFatal("An error occured during parsing");
exit (1);
}
The error I get:
error: no matching function to call to 'Qjson::Parser:parse(QString&, bool)
If I remove the include, the error says:
QJson has not been declared
So it must be finding the libraries at least. Any ideas on what's going wrong?
Comments aren't parsed by default in QJson.
Here is a small adaptation I made on my QJson logic to handle comments. Notice the simple Regex to remove comments.
QFile file( filename );
//File can't be opened!
if ( !file.open( QFile::ReadOnly ) )
{
qDebug("Couldn't load config file: %s", filename.toLatin1().data());
return;
}
//Strip out comments
QStringList list = QString( file.readAll() ).split('\n');
for ( int i = 0; i < list.size(); i++ )
list[i].replace( QRegExp("//[^\"]*$"), "" );
//Load the file, converting into an object file
QJsonParseError e;
QJsonObject json =
QJsonDocument::fromJson( list.join('\n').toLatin1(), &e ).object();
//Was there an error?
if ( e.error != QJsonParseError::NoError )
{
qDebug( "Json parse error: %s", e.errorString().toLatin1().data() );
return;
}

dlclose crashes when copying dynamic libraries

I have an interesting problem that seems to be unresolved by my research on the internet.
I'm trying to load libraries dynamically in my c++ project with the functions from dlfcn.h. The problem is that when I try to reload the plugins at running time (because I made a change on any of them), the main program crashes (Segmentation fault (core dumped)) when dlclose() is called.
Here is my example that reproduces the error:
main.cpp:
#include <iostream>
#include <dlfcn.h>
#include <time.h>
#include "IPlugin.h"
int main( )
{
void * lib_handle;
char * error;
while( true )
{
std::cout << "Updating the .so" << std::endl;
lib_handle = dlopen( "./test1.so", RTLD_LAZY );
if ( ! lib_handle )
{
std::cerr << dlerror( ) << std::endl;
return 1;
}
create_t fn_create = ( create_t ) dlsym( lib_handle, "create" );
if ( ( error = dlerror( ) ) != NULL )
{
std::cerr << error << std::endl;
return 1;
}
IPlugin * ik = fn_create( );
ik->exec( );
destroy_t fn_destroy = ( destroy_t ) dlsym( lib_handle, "destroy" );
fn_destroy( ik );
std::cout << "Waiting 5 seconds before unloading..." << std::endl;
sleep( 5 );
dlclose( lib_handle );
}
return 0;
}
IPlugin.h:
class IPlugin
{
public:
IPlugin( ) { }
virtual ~IPlugin( ) { }
virtual void exec( ) = 0;
};
typedef IPlugin * ( * create_t )( );
typedef void ( * destroy_t )( IPlugin * );
Test1.h:
#include <iostream>
#include "IPlugin.h"
class Test1 : public IPlugin
{
public:
Test1( );
virtual ~Test1( );
void exec( );
};
Test1.cpp:
#include "Test1.h"
Test1::Test1( ) { }
Test1::~Test1( ) { }
void Test1::exec( )
{
std::cout << "void Test1::exec( )" << std::endl;
}
extern "C"
IPlugin * create( )
{
return new Test1( );
}
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL )
{
delete plugin;
}
}
To compile:
g++ main.cpp -o main -ldl
g++ -shared -fPIC Test1.cpp -o plugin/test1.so
The problem occurs when for example I change something on the Test1::exec method (changing the string to be printed or commenting the line) and while the main program sleeps I copy the new test1.so to main running directory (cp). If I use the move command (mv), no error occurs. What makes the difference between using cp or mv? Is there any way to solve this problem or to do that using cp?
I'm using Fedora 14 with g++ (GCC) 4.5.1 20100924 (Red Hat 4.5.1-4).
Thanks in advance.
The difference between cp and mv that is pertinent to this question is as follows:
cp opens the destination file and writes the new contents into it. It therefore replaces the old contents with the new contents.
mv doesn't touch the contents of the original file. Instead, it makes the directory entry point to the new file.
This turns out to be important. While the application is running, the OS keeps open handles to the executable and the shared objects. When it needs to consult one of the these files, it uses the relevant handle to access the file's contents.
If you've used cp, the contents has now been corrupted, so anything can happen (a segfault is a pretty likely outcome).
If you've used mv, the open file handle still refers to the original file, which continues to exist on disk even though there's no longer a directory entry for it.
If you've used mv to replace the shared object, you should be able to dlclose the old one and dlopen the new one. However, this is not something that I've done or would recommend.
Try this:
extern "C"
void destroy( IPlugin * plugin )
{
if( plugin != NULL && dynamic_cast<Test1*>(plugin))
{
delete static_cast<Test1*>(plugin);
}
}