diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-09 20:27:19 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-09 20:27:19 +0000 |
commit | c6ca83d07d95e076b09bd802f66ba72d363b0235 (patch) | |
tree | f13000febb0c9c5a5da621b4bba53ba3eace022e /common | |
download | kgtk-qt3-c6ca83d07d95e076b09bd802f66ba72d363b0235.tar.gz kgtk-qt3-c6ca83d07d95e076b09bd802f66ba72d363b0235.zip |
* Added kgtk-qt3
* Slight kpowersave message cleanup
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kgtk-qt3@1173604 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'common')
-rw-r--r-- | common/common.h | 237 | ||||
-rw-r--r-- | common/connect.h | 311 |
2 files changed, 548 insertions, 0 deletions
diff --git a/common/common.h b/common/common.h new file mode 100644 index 0000000..ca246b9 --- /dev/null +++ b/common/common.h @@ -0,0 +1,237 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define KDIALOGD_APP + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> +#include "config.h" + +#ifdef __KDIALOGD_H__ +#include <kstandarddirs.h> +#endif + +typedef enum +{ + OP_NULL = 0, + OP_FILE_OPEN = 1, + OP_FILE_OPEN_MULTIPLE = 2, + OP_FILE_SAVE = 3, + OP_FOLDER = 4 +} Operation; + +#define PID_DIR "kde-" +#define PID_NAME "kdialogd.pid" + +static const char * getPidFileName() +{ + static char *pidfile=NULL; + + if(!pidfile) + { + char *user=getenv("USER"); + + if(!user) + user=getenv("LOGNAME"); + + if(user) + { + char *tmp=getenv("KDETMP"); + + if(!tmp || !tmp[0]) + tmp=getenv("TMPDIR"); + + if(!tmp || !tmp[0]) + tmp=(char *)"/tmp"; + + pidfile=(char *)malloc(strlen(tmp)+strlen(PID_DIR)+strlen(user)+strlen(PID_NAME)+1); + pidfile=(char *)malloc(strlen(tmp)+strlen("/")+strlen(PID_DIR)+strlen(user)+strlen("/")+strlen(PID_NAME)+1); + +#ifdef __KDIALOGD_H__ + // We are kdialogd - so create socket folder if it does not exist... + sprintf(pidfile, "%s/%s%s", tmp, PID_DIR, user); + KStandardDirs::makeDir(QString::fromAscii(pidfile)); +#endif + + /* CPD: TODO get dispaly number! */ + sprintf(pidfile, "%s/%s%s/%s", tmp, PID_DIR, user, PID_NAME); + } + } + + return pidfile; +} + +#define SOCK_DIR "ksocket-" +#define SOCK_NAME "kdialogd" + +static const char * getSockName() +{ + static char *sock=NULL; + + if(!sock) + { + char *user=getenv("USER"); + + if(!user) + user=getenv("LOGNAME"); + + if(user) + { + char *tmp=getenv("KDETMP"); + + if(!tmp || !tmp[0]) + tmp=getenv("TMPDIR"); + + if(!tmp || !tmp[0]) + tmp=(char *)"/tmp"; + + sock=(char *)malloc(strlen(tmp)+strlen("/")+strlen(SOCK_DIR)+strlen(user)+strlen("/")+strlen(SOCK_NAME)+strlen("18446744073709551616")+1); + +#ifdef __KDIALOGD_H__ + // We are kdialogd - so create socket folder if it does not exist... + sprintf(sock, "%s/%s%s", tmp, SOCK_DIR, user); + KStandardDirs::makeDir(QString::fromAscii(sock)); +#endif + + /* CPD: TODO get dispaly number! */ + sprintf(sock, "%s/%s%s/%s-%d", tmp, SOCK_DIR, user, SOCK_NAME, 1); + } + } + + return sock; +} + +static int readBlock(int fd, char* pData, int size) +{ + int bytesToRead=size; + + do + { + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + + if(select(fd + 1, &fdSet, NULL, NULL, NULL)<0) + return 0; + + if(FD_ISSET(fd, &fdSet)) + { + int bytesRead=read(fd, &pData[size-bytesToRead], bytesToRead); + + if (bytesRead>0) + bytesToRead-=bytesRead; + else + return 0; + } + } + while(bytesToRead>0); + + return 1; +} + +static int writeBlock(int fd, const char *pData, int size) +{ + int bytesToWrite=size; + + do + { + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + + if(select(fd + 1, NULL, &fdSet, NULL, NULL)<0) + return 0; + + if(FD_ISSET(fd, &fdSet)) + { + int bytesWritten=write(fd, (char *)&pData[size-bytesToWrite], bytesToWrite); + + if (bytesWritten>0) + bytesToWrite-=bytesWritten; + else + return 0; + } + } + while(bytesToWrite>0); + + return 1; +} + +#ifdef KDIALOGD_APP +/* + So that kdailogd can terminate when the last app exits, need a way of synchronising the Gtk/Qt + apps that may wish to connect, and the removal of the socket. + + To this en, a lockfile is created,and used to guard around the critical sections +*/ +static int lockFd=-1; + +#define LOCK_EXT ".lock" + +const char * getLockName() +{ + static char *lockName=NULL; + + if(!lockName) + { + const char *sock=getSockName(); + + if(sock) + { + lockName=(char *)malloc(strlen(sock)+strlen(LOCK_EXT)+1); + sprintf(lockName, "%s%s", sock, LOCK_EXT); + } + } + + return lockName; +} + +/* Lock is stale if it does not exist or is older than 2 seconds */ +static int isStale(const char *fname) +{ + struct stat stat_buf; + + return 0!=stat(fname, &stat_buf) || + abs(stat_buf.st_mtime-time(NULL))>2; +} + +static int grabLock(int tries) +{ + do + { + lockFd=open(getLockName(), O_WRONLY | O_CREAT | O_EXCL, 0777); + if (lockFd<0 && errno==EEXIST) + { + /* Hmm, lock file already exists. Is it stale? */ + if(isStale(getLockName())) + { + tries++; /* Increment tries so that we try again... */ + unlink(getLockName()); + } + else if(tries) + usleep(100000); + } + } + while(lockFd<0 && --tries); + + return lockFd; +} + +static void releaseLock() +{ + if(lockFd>0) + { + close(lockFd); + unlink(getLockName()); + } +} +#endif + +#endif diff --git a/common/connect.h b/common/connect.h new file mode 100644 index 0000000..2499054 --- /dev/null +++ b/common/connect.h @@ -0,0 +1,311 @@ +#ifndef __CONNECT_H__ +#define __CONNECT_H__ + +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> +#include "config.h" +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> + +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + +#include "common.h" +#include "config.h" + +#ifdef __cplusplus +typedef bool kgtk_bool; +#define KGTK_TRUE true +#define KGTK_FALSE false +#else +typedef gboolean kgtk_bool; +#define KGTK_TRUE TRUE +#define KGTK_FALSE FALSE +#endif + + +static int kdialogdSocket=-1; + +/* From kdelibs/kdesu */ +#ifdef KDIALOGD_APP +static int createSocketConnectionReal() +#else +static int createSocketConnection() +#endif +{ +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection A\n"); +#endif + int sockfd=-1; + const char *sock=getSockName(); + struct sockaddr_un addr; + + if (access(sock, R_OK|W_OK)) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not access socket, %s\n", sock); +#endif + return -1; + } + + sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not create socket, %d\n", errno); +#endif + return -1; + } + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sock); + + if (connect(sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - Could not connect socket, %d\n", errno); +#endif + close(sockfd); + return -1; + } + +#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED) +# if defined(HAVE_GETPEEREID) + { + uid_t euid; + gid_t egid; + /* Security: if socket exists, we must own it */ + if (getpeereid(sockfd, &euid, &egid) == 0) + { + if (euid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", euid); +#endif + close(sockfd); + return -1; + } + } + } +# else +# ifdef __GNUC__ +# warning "Using sloppy security checks" +# endif + /* We check the owner of the socket after we have connected. + If the socket was somehow not ours an attacker will be able + to delete it after we connect but shouldn't be able to + create a socket that is owned by us. */ + { + struct stat s; + if (lstat(sock, &s)!=0) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - stat failed %s\n", sock); +#endif + close(sockfd); + return -1; + } + if (s.st_uid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", s.st_uid); +#endif + close(sockfd); + return -1; + } + if (!S_ISSOCK(s.st_mode)) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket is not a socket %s\n", sock); +#endif + close(sockfd); + return -1; + } + } +# endif +#else + { + struct ucred cred; + socklen_t siz = sizeof(cred); + + /* Security: if socket exists, we must own it */ + if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0) + { + if (cred.uid != getuid()) + { +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", cred.uid); +#endif + close(sockfd); + return -1; + } + } + } +#endif + +#ifdef KGTK_DEBUG + printf("KGTK::createSocketConnection - sockfd:%d\n", sockfd); +#endif + return sockfd; +} + +#ifdef KDIALOGD_APP +static int createSocketConnection() +{ + int rv=-1, + tries=0; + + do + { + if(-1==(rv=createSocketConnectionReal())) + usleep(10000); + } + while(-1==rv && ++tries<50); + + if(-1==rv) + fprintf(stderr, "ERROR: Could not talk to KDialogD!!!\n"); + return rv; +} +#endif + +static int kdialogdPid=-1; + +static kgtk_bool processIsRunning() +{ +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning\n"); +#endif + + if(-1!=kdialogdPid && 0==kill(kdialogdPid, 0)) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning (%d) YES\n", kdialogdPid); +#endif + return KGTK_TRUE; + } + else + { + FILE *f=fopen(getPidFileName(), "r"); + + if(f) + { + int pid=0; + + if(1==fscanf(f, "%d", &pid)) + { + fclose(f); + + if(-1!=kdialogdPid && kdialogdPid!=pid) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning pid has changed from:%d to %d - need to reconnect\n", kdialogdPid, pid); +#endif + kdialogdPid=pid; + return KGTK_FALSE; + } +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning file has pid:%d\n", pid); +#endif + if(0==kill(pid, 0)) + { +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning (file:%d) YES\n", pid); +#endif + kdialogdPid=pid; + return KGTK_TRUE; + } + + kdialogdPid=-1; /* Process is not running! */ + } + } + } +#ifdef KGTK_DEBUG + printf("KGTK::processIsRunning NO\n"); +#endif + return KGTK_FALSE; +} + +static void closeConnection() +{ +#ifdef KGTK_DEBUG + printf("KGTK::closeConnection\n"); +#endif + close(kdialogdSocket); + kdialogdSocket=-1; +} + +/* Note: Calling 'fork' seems to mess things up with eclipse! */ +#define KGTK_USE_SYSTEM_CALL + +static kgtk_bool connectToKDialogD(const char *appName) +{ +#ifdef KGTK_DEBUG + printf("KGTK::connectToKDialogD %s\n", appName ? appName : "<null>"); +#endif + if(!processIsRunning()) + closeConnection(); + + if(-1!=kdialogdSocket) + return KGTK_TRUE; + else + { + unsigned int slen=strlen(appName); + kgtk_bool rv=KGTK_TRUE; + + if(slen) + slen++; + +#ifdef KGTK_DEBUG + printf("KGTK::connectToKDialogD - start wrapper\n"); +#endif + +#ifdef KDIALOGD_APP + grabLock(5); +#ifdef KGTK_USE_SYSTEM_CALL + system("kdialogd-wrapper &"); +#else + switch(fork()) + { + case -1: + rv=KGTK_FALSE; + printf("ERROR: Could not start fork :-(\n"); + break; + case 0: + execl(KDIALOGD_LOCATION"/kdialogd-wrapper", "kdialogd-wrapper", (char *)NULL); + break; + default: + { + int status=0; + wait(&status); + } + } +#endif + releaseLock(); +#endif + + if(!rv) + return rv; + + rv= +#ifdef KDIALOGD_APP + grabLock(3)>0 && +#else + 0==system("dcop kded kded loadModule kdialogd") && +#endif + -1!=(kdialogdSocket=createSocketConnection()) && + writeBlock(kdialogdSocket, (char *)&slen, 4) && + (0==slen || writeBlock(kdialogdSocket, appName, slen)); +#ifdef KDIALOGD_APP + releaseLock(); +#endif + return rv; + } +} + +#endif |