Installing message handler - c++

I have tried to create a log file for an application by installing a message handler using qinstallMessageHandler() function. My program is as follows:
#include <QCoreApplication>
#include <QtDebug>
#include <QDir>
#include <fstream>
#include <iostream>
#include <QtCore>
#include <stdio.h>
#include <stdlib.h>
FILE *fd;
void myMessageOutput(QtMsgType type, const char *msg)
{
QString timeStamp = QTime::currentTime().toString("hh:mm:ss:zzz");
switch (type) {
case QtDebugMsg:
fprintf(fd, "[%s]", timeStamp.toStdString().c_str());
fprintf(fd, "[Debug] %s\n", msg);
break;
case QtWarningMsg:
fprintf(fd, "[%s]", timeStamp.toStdString().c_str());
fprintf(fd, "[Warning] %s\n", msg);
break;
case QtCriticalMsg:
fprintf(fd, "[%s]", timeStamp.toStdString().c_str());
fprintf(fd, "[Critical] %s\n", msg);
break;
case QtFatalMsg:
fprintf(fd, "[%s]", timeStamp.toStdString().c_str());
fprintf(fd, "[Fatal] %s\n", msg);
abort();
}
}
int main(int argc, char *argv[])
{
fd = fopen("log.txt", "a");
qInstallMessageHandler(myMessageOutput);
QCoreApplication a(argc, argv);
qDebug()<<"\t Hello World!!! \n";
return a.exec();
}
But after compiling I get the following error:
error: invalid conversion from 'void ()(QtMsgType, const char)' to 'QtMessageHandler {aka void (*)(QtMsgType, const QMessageLogContext&, const QString&)}' [-fpermissive]
Anyone here who have faced the same problem earlier?

It looks like you switch to Qt5 and used the message handler function signature defined in Qt4.x. You need to declare your message handler as follows:
void myMessageOutput(QtMsgType type,
const QMessageLogContext &context,
const QString &msg)
{
[..]
}
instead.

Related

unshare user namespace, fork, map uid then execvp failing

I am trying to do the following sequence of actions:
unshare the user namespace;
Map the user in child process to root;
execvp.
However, when running id, my code outputs the user as a nobody or fails without error.
#include <sched.h>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <system_error>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
void unshare_user_namespace() {
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
}
void map_id() {
int pid = getpid();
char file[100];
if (0 > sprintf(file, "/proc/%d/uid_map", pid)) {
printf("Couldn't sprintf uid_map path.");
exit(1);
}
int fd;
fd = open(file, 1);
if (fd < 0) {
printf("Coudln't open file for writing.\n");
exit(1);
}
int uid = getuid();
char * buf;
if (0 > sprintf(buf, "0 %d 1", uid)) {
printf("Couldn't sprintf uid_map content.");
exit(1);
}
if (write(fd, buf, strlen(buf))) {
printf("Coudln't write mapping into file.\n");
exit(1);
}
free(buf);
close(fd);
}
void start(char * command, char ** args) {
unshare_user_namespace();
int fork_pid = fork();
if (-1 == fork_pid) {
fprintf(stderr, "%s\n", "couldn't fork");
exit(1);
}
if (0 == fork_pid) {
map_id();
if (-1 == execvp(command, args)) {
fprintf(stderr, "%s\n", "couldn't execvp");
exit(1);
}
}
}
int main(int argc, char ** argv) {
start(argv[1], & argv[1]);
int status;
wait( & status);
return 0;
}
I tried reading the man pages for namespaces, unshare etc but couldn't figure out what's wrong with my code.
To run the code:
$ g++ <file_containing_code> && ./a.out id
Pretty sure you've already found the answer, but this is a minimal sample I could come up with:
// gcc -Wall -std=c11
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdarg.h>
void write_to_file(const char *which, const char *format, ...) {
FILE * fu = fopen(which, "w");
va_list args;
va_start(args, format);
if (vfprintf(fu, format, args) < 0) {
perror("cannot write");
exit(1);
}
fclose(fu);
}
int main(int argc, char ** argv) {
// array of strings, terminated with NULL entry
char **cmd_and_args = (char**) calloc(argc, sizeof(char*));
for (int i = 1 ; i < argc; i++) {
cmd_and_args[i-1] = argv[i];
}
uid_t uid = getuid();
gid_t gid = getgid();
// first unshare
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
// remap uid
write_to_file("/proc/self/uid_map", "0 %d 1", uid);
// deny setgroups (see user_namespaces(7))
write_to_file("/proc/self/setgroups", "deny");
// remap gid
write_to_file("/proc/self/gid_map", "0 %d 1", gid);
// exec the command
if (execvp(cmd_and_args[0], cmd_and_args) < 0) {
perror("cannot execvp");
exit(1);
}
// unreachable
free(cmd_and_args);
return 0;
}

Why does opstring not create the expected response when using getopt in c?

I am trying to write a getopt() module for a program I am writing and for some Reason my use of getopt() is not working.
#include "setopt.h"
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct flags_t getFlags(int argc, char** argv) {
struct flags_t ourflags;
int opt;
ourflags.threadpool = 4;
while (1) {
opt = getopt(argc, argv, "N:l:");
if (opt == -1) {
//printf("getting bad read -1\n");
break;
}
switch (opt) {
case 'l' :
strcpy(ourflags.logfilename, optarg);
break;
case 'N' :
ourflags.threadpool = atoi(optarg);
break;
default :
printf("unkown flag %c\n", opt);
exit(-1);
}
}
const int requiredargs = 1;
if (argc - optind != requiredargs) {
printf("incorrect amount of flags, wanted : %d: got %d\n",
requiredargs, (argc - optind));
exit(-1);
}
ourflags.port = atoi(argv[optind]);
return ourflags;
}
When I run my program using
./setopt 8080 -N 6 -l log_file
I get the output
incorrect amount of flags, wanted : 1: got 5
I think the problem is in my optstring argument, But I am not sure. I cannot get he switch cases to take. Any help would be appreciated.

Converting from Char to Int with qFromBigEndian says: "No matching function for call to"

I am trying to read incoming data from a QTcpSocket but it gives me the error:
error: no matching function for call to 'qFromBigEndian(char [4])'
qint32 peekedSize = qFromBigEndian<qint32> (buffer);
What am I doing wrong?
This is my function:
void TcpServer::readIncomingData(){
if(mDebug)
qDebug() << "readIncomingData()";
QTcpSocket * tcpSocket = (QTcpSocket*)sender();
while(true){
if (tcpSocket->bytesAvailable() < 4){
break;
}
char buffer[4];
tcpSocket->peek(buffer, 4);
qint32 peekedSize = qFromBigEndian<qint32> (buffer);
if (peekedSize==0xffffffffu) // null string
peekedSize = 0;
peekedSize += 4;
QString str;
QDataStream(tcpSocket) >> str;
emit stringHasBeenRead(str);
}
}
I have included the headers:
#include <QtNetwork>
#include <QtEndian>
#include <QtCore>
#include <QDataStream>
#include <QtGlobal>
but that still gives the same error.
Also, in the .pro file I have:
QT += core gui network
According to Qt documentation qFromBigEndian() function argument type must be const uchar *:
http://doc.qt.io/qt-5/qtendian.html#qFromBigEndian
Try this:
qint32 peekedSize = qFromBigEndian<qint32>((const uchar*)&buffer);

::write() and ::read() has not been declared error. Qt5 UNIX signal handling

So, I'm trying to follow the tutorial given
http://qt-project.org/doc/qt-5/unix-signals.html
to catch UNIX/Linux signals and do something Qt related when triggered by them.
It's on the qtDocs, so I consider it legit.
My present code is as follows:
mydaemon.cpp
#include "mydaemon.h"
#include <QDebug>
#include <QObject>
#include <QSocketNotifier>
#include <csignal>
#include <sys/socket.h>
#include <iostream>
#include <stdio.h>
#include <signal.h>
//needed to not get an undefined reference to static members
int MyDaemon::sighupFd[2];
int MyDaemon::sigtermFd[2];
MyDaemon::MyDaemon(QObject *parent)
: QObject(parent)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
qFatal("Couldn't create HUP socketpair");
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
qFatal("Couldn't create TERM socketpair");
snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
}
MyDaemon::~MyDaemon() {}
void MyDaemon::hupSignalHandler(int)
{
qDebug() << "signal hup";
char a = '1';
::write(sighupFd[0], &a, sizeof(a));
}
void MyDaemon::termSignalHandler(int)
{
qDebug() << "signal term";
char a = '1';
::write(sigtermFd[0], &a, sizeof(a));
}
void MyDaemon::handleSigTerm()
{
snTerm->setEnabled(false);
char tmp;
::read(sigtermFd[1], &tmp, sizeof(tmp));
// do Qt stuff
qDebug() << "MyDaemon::handleSigTerm";
snTerm->setEnabled(true);
}
void MyDaemon::handleSigHup()
{
snHup->setEnabled(false);
char tmp;
::read(sighupFd[1], &tmp, sizeof(tmp));
// do Qt stuff
qDebug() << "MyDaemon::handleSigHup";
snHup->setEnabled(true);
}
Now, when I create my C++ class, and try to build, it gives the errors such as,
/home/xxxx/Documents/Qt Projects/mainScreen/mydaemon.cpp:-1: In static member function 'static void MyDaemon::termSignalHandler(int)':
/home/xxxx/Documents/Qt Projects/mainScreen/mydaemon.cpp:49: error: '::write' has not been declared
::write(sigtermFd[0], &a, sizeof(a));
^
and so on, for all instances of the ::read() or ::write() calls. I'm not sure what I'm doing wrong, I'm grateful for any help :)
If you are using "basic" Unix functions, you need to use
#include <unistd.h>
This will give you read, write, open, close, sleep, usleep and many other functions.

QList + QVariant + dbus, what difference?

Code bellow. In this variants it doesn't work, it says:
int main(int, char**): mount error msg `Method "FilesystemMount" with signature "bas" on interface "org.freedesktop.UDisks.Device" doesn't exit.
But if I replace "#if 0" with "#if 1" all will works fine.
Can you explain?
#include <cstdio>
#include <cstdlib>
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusPendingReply>
#include <QtDBus/QDBusConnection>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
if (argc != 2) {
fprintf(stderr, "Usage: %s path/to/device\n", argv[0]);
return EXIT_FAILURE;
}
const QString dev_path(argv[1]);
auto mount_call = QDBusMessage::createMethodCall("org.freedesktop.UDisks", dev_path, "org.freedesktop.UDisks.Device", "FilesystemMount");
#if 0
QList<QVariant> args;//WHY THIS WORKS???
args << QVariant(QString()) << QVariant(QStringList("sync"));
#else
QList<QVariant> args;//AND WHY THIS NOT WORKS???
QVariant filesystem_type(QString());
QVariant opts(QStringList("sync"));
args << filesystem_type << opts;
#endif
mount_call.setArguments(args);
QDBusPendingReply<QVariantMap> mount_res = QDBusConnection::systemBus().call(mount_call);
if (!mount_res.isValid())
fprintf(stderr, "%s: mount error msg `%s'\n", __PRETTY_FUNCTION__, mount_res.error().message().toLocal8Bit().data());
return app.exec();
}
So for me this looks likes:
Container<T> c;
T a;
T b;
c.append(a);
c.append(b);
vs
Container c;
c.append(T());
c.append(T());
but the content of "c" should be the same after end of both control flow?
Ok, I found the reason:
compiler thought that:
QVariant filesystem_type(QString());
is a pointer to function, not a QVariant object;