GED 2006 (C++)
File detail
Source code
/*
* File: pluginsuppport.cc - Maintain plugins
* Project: GED - bitmap editor (ICP)
* Author: Kamil Dudka, xdudka00
* Team: xdudka00, xfilak01, xhefka00, xhradi08
* Created: 2006-04-06
*/
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include "global.h"
#include "pluginsupport.h"
using std::string;
using std::map;
using GlobalH::min;
using GlobalH::max;
typedef map<string, string> TPluginNameMap;
/*
* Initialize singleton PluginList
*/
PluginList *PluginList::_instance = 0;
/*
* Global point to singleton PluginList
*/
PluginList *PluginList::ptr ()
{
if (0== _instance)
_instance = new PluginList;
return _instance;
}
/*
* This function should be called on program exit
*/
void PluginList::destroy ()
{
delete _instance;
}
/*
* PluginList destructor
*/
PluginList::~PluginList ()
{
_instance = 0;
}
/*
* return true if file "szFileName" is executable for "procUid" or "procGid"
*/
static inline bool isExec (const char *szFileName, uid_t procUid, gid_t procGid) {
struct stat fileInfo;
if (0!= stat (szFileName, &fileInfo))
// could not read fileInfo
return false;
if (!(fileInfo.st_mode & S_IFREG) || !(fileInfo.st_mode & S_IFLNK))
// not a file
return false;
return
(fileInfo.st_mode & S_IXOTH) ||
((fileInfo.st_mode & S_IXUSR) && fileInfo.st_uid == procUid) ||
((fileInfo.st_mode & S_IXGRP) && fileInfo.st_gid == procGid);
}
/*
* Lookup for plugins in directory "szDirectory"
*/
void PluginList::pluginDirLookup (const char *szDirectory)
{
#ifndef NDEBUG
std::cerr << "Scanning directory \'" << szDirectory << "\' for plugins:\n";
#endif
DIR *pDir = opendir (szDirectory);
if (NULL== pDir)
throw ErrPluginDir ();
uid_t myUid = getuid ();
gid_t myGid = getgid ();
// Scan opened directory for executable files
for (struct dirent *currDir; NULL!= (currDir= readdir (pDir)); ) {
string fileName = string (szDirectory) + "/" + currDir->d_name;
if (!isExec (fileName.c_str(), myUid, myGid))
// File not executable
continue;
// Try to add plugin
addPluginFile (fileName);
}
closedir (pDir);
#ifndef NDEBUG
std::cerr << "Directory scan complete..\n";
#endif
}
/*
* Add file "fileName" as plugin (if recornized)
*/
void PluginList::addPluginFile (std::string &fileName)
{
// Plugin name limit
const size_t pluginNameLength = 256;
// Run plugin with "--name" option
FILE *pluginPipe = popen ((fileName + " --name").c_str(), "r");
// Read identification
char szPluginName [pluginNameLength];
const size_t cbRead = fread (szPluginName, sizeof(char), pluginNameLength, pluginPipe);
szPluginName [ min<unsigned> (pluginNameLength-1, max<int> (0, int(cbRead)-1)) ] = '\0';
// Wait
if (0!= pclose (pluginPipe))
return;
// Add plugin to plugin map
_pluginNameMap [string (szPluginName)] = fileName;
#ifndef NDEBUG
std::cerr << " \'" << szPluginName << "\'\n";
#endif
}
/*
* Call plugin
* fb: FrameBuffer to share
* pluginName: name (id) of called plugin
* args: plugin arguments
*/
void PluginList::callByName (FrameBuffer &fb, std::string pluginName, std::string args)
{
// Lookup for plugin fileName
TPluginNameMap::iterator i= _pluginNameMap.find (pluginName);
if (i == _pluginNameMap.end ())
throw ErrPluginNotFound ();
invokePlugin (fb, (*i).second, args);
}
/*
* Call plugin
* fb: FrameBuffer to share
* cmd: complete cmd-line string to call plugin
*/
void PluginList::invokePlugin (FrameBuffer &fb, std::string &fileName, std::string &args)
{
int shmID = SharedObject::create (fb);
// Build cmd using stream
std::ostringstream cmdStream;
cmdStream << fileName << " " << shmID << " " << args;
// Save stream to string
string cmd = cmdStream.str();
#ifndef NDEBUG
std::cerr << "Plugin call: " << cmd << "\n";
#endif
// Plugin call
if (int iErrCode = system (cmd.c_str()) ) {
SharedObject::destroy (shmID);
throw ErrPluginEC (iErrCode);
}
// Commit changes to fb
fb = SharedFrameBuffer (shmID);
SharedObject::destroy (shmID);
}
/*
* Create shared object from fb
* return: id of shared object
*/
int SharedObject::create (FrameBuffer &fb)
{
#ifndef NDEBUG
std::cerr << "Creating shared object..\n";
#endif
// Allocate shm for SharedObject
int soID = shmget (IPC_PRIVATE, sizeof(SharedObject), IPC_CREAT | 0600 );
SharedObject *pSO = attach (soID);
pSO->_fb._size = fb._size;
pSO->_fb._select = fb._select;
pSO->_fb._pBuff = 0;
// Allocate shm for bitmap
pSO->bitmapAlloc (fb._size);
// Copy bitmap
Pixel *bitmap = pSO->bitmapAttach();
for (int i=0; i<fb._size.nPixels(); i++)
bitmap[i] = fb._pBuff[i];
shmdt (bitmap);
detach (pSO);
return soID;
}
/*
* Destroy shared object
* shmID: id returned by create()
*/
void SharedObject::destroy (int shmID)
{
#ifndef NDEBUG
std::cerr << "Deleting shared object..\n";
#endif
SharedObject *pSO = attach (shmID);
pSO->bitmapFree ();
detach (pSO);
shmctl (shmID, IPC_RMID, NULL);
}
/*
* Attach process to shared object
* shmID: id of shared object
* return: address of shared object
*/
SharedObject *SharedObject::attach (int shmID)
{
return static_cast<SharedObject *>(shmat (shmID, NULL, 0));
}
/*
* Detach process from shared object
* addr: address of shared object returned by attach()
*/
void SharedObject::detach (SharedObject *addr)
{
shmdt (addr);
}
/*
* Free shm allocated by bitmapAlloc()
*/
void SharedObject::bitmapFree ()
{
shmctl (_shmBitmap, IPC_RMID, NULL);
}
/*
* Allocate shared bitmap of size "size"
*/
void SharedObject::bitmapAlloc (BoxSize &size)
{
_shmBitmap = shmget (IPC_PRIVATE, size.nPixels() * sizeof(Pixel), IPC_CREAT | 0600 );
}
/*
* Attach process to bitmap
* return: address of attached bitmap
*/
Pixel *SharedObject::bitmapAttach ()
{
return static_cast<Pixel *>(shmat (_shmBitmap, NULL, 0));
}
/*
* Detach process from bitmap
* addr: address of bitmap object returned by bitmapAttach()
*/
void SharedObject::detach (Pixel *addr)
{
shmdt (addr);
}
/*
* Create frame buffer from shared object
* shmID: id of shared object
*/
SharedFrameBuffer::SharedFrameBuffer (int shmID)
{
#ifndef NDEBUG
std::cerr<<"Importing data from shared object..\n";
#endif
SharedObject *src = SharedObject::attach (shmID);
// set fb properties
this->size (src->pFB()->_size);
this->select (src->pFB()->_select);
// copy bitmap
Pixel *bitmap = src->bitmapAttach();
for (int i=0; i<_size.nPixels(); i++)
_pBuff[i] = bitmap[i];
shmdt (bitmap);
SharedObject::detach (src);
}
/*
* Commit data to shared object
* shmID: id of shared object
*/
void SharedFrameBuffer::commit (int shmID)
{
#ifndef NDEBUG
std::cerr<<"Commiting changes to shared object..\n";
#endif
SharedObject *desc = SharedObject::attach (shmID);
if (_size != desc->pFB()->_size)
{
// FB size changed
desc->pFB()->_size = _size;
#ifndef NDEBUG
std::cerr<<"Reallocating sahred bitmap (fb size changed)..\n";
#endif
desc->bitmapFree ();
desc->bitmapAlloc (_size);
}
// Copy selection (not needed by most of plugins)
desc->pFB()->_select = _select;
// Copy bitmap
Pixel *bitmap = desc->bitmapAttach();
for (int i=0; i<_size.nPixels(); i++)
bitmap[i] = _pBuff[i];
shmdt (bitmap);
SharedObject::detach (desc);
}