Blame | Last modification | View Log | RSS feed
/*
* esh-utils.c
* A set of utility routines to manage esh objects.
*
* Developed by Godmar Back for CS 3214 Fall 2009
* Virginia Tech.
*/
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
#include <limits.h>
#include "esh.h"
static const char rcsid [] = "$Id: esh-utils.c,v 1.5 2011/03/29 15:46:28 cs3214 Exp $";
/* List of loaded plugins */
struct list esh_plugin_list;
/* Create new command structure and initialize first command word,
* and/or input or output redirect file. */
struct esh_command *
esh_command_create(char ** argv,
char *iored_input,
char *iored_output,
bool append_to_output)
{
struct esh_command *cmd = malloc(sizeof *cmd);
cmd->iored_input = iored_input;
cmd->iored_output = iored_output;
cmd->argv = argv;
cmd->append_to_output = append_to_output;
return cmd;
}
/* Create a new pipeline containing only one command */
struct esh_pipeline *
esh_pipeline_create(struct esh_command *cmd)
{
struct esh_pipeline *pipe = malloc(sizeof *pipe);
pipe->bg_job = false;
cmd->pipeline = pipe;
list_init(&pipe->commands);
list_push_back(&pipe->commands, &cmd->elem);
return pipe;
}
/* Complete a pipe's setup by copying I/O redirection information */
void
esh_pipeline_finish(struct esh_pipeline *pipe)
{
if (list_size(&pipe->commands) == 0)
return;
struct esh_command *first;
first = list_entry(list_front(&pipe->commands), struct esh_command, elem);
pipe->iored_input = first->iored_input;
struct esh_command *last;
last = list_entry(list_back(&pipe->commands), struct esh_command, elem);
pipe->iored_output = last->iored_output;
pipe->append_to_output = last->append_to_output;
}
/* Create an empty command line */
struct esh_command_line *
esh_command_line_create_empty(void)
{
struct esh_command_line *cmdline = malloc(sizeof *cmdline);
list_init(&cmdline->pipes);
return cmdline;
}
/* Create a command line with a single pipeline */
struct esh_command_line *
esh_command_line_create(struct esh_pipeline *pipe)
{
struct esh_command_line *cmdline = esh_command_line_create_empty();
list_push_back(&cmdline->pipes, &pipe->elem);
return cmdline;
}
/* Print esh_command structure to stdout */
void
esh_command_print(struct esh_command *cmd)
{
char **p = cmd->argv;
printf(" Command:");
while (*p)
printf(" %s", *p++);
printf("\n");
if (cmd->iored_output)
printf(" stdout %ss to %s\n",
cmd->append_to_output ? "append" : "write",
cmd->iored_output);
if (cmd->iored_input)
printf(" stdin reads from %s\n", cmd->iored_input);
}
/* Print esh_pipeline structure to stdout */
void
esh_pipeline_print(struct esh_pipeline *pipe)
{
int i = 1;
struct list_elem * e = list_begin (&pipe->commands);
printf(" Pipeline\n");
for (; e != list_end (&pipe->commands); e = list_next (e)) {
struct esh_command *cmd = list_entry(e, struct esh_command, elem);
printf(" %d. ", i++);
esh_command_print(cmd);
}
if (pipe->bg_job)
printf(" - is a background job\n");
}
/* Print esh_command_line structure to stdout */
void
esh_command_line_print(struct esh_command_line *cmdline)
{
struct list_elem * e = list_begin (&cmdline->pipes);
printf("Command line\n");
for (; e != list_end (&cmdline->pipes); e = list_next (e)) {
struct esh_pipeline *pipe = list_entry(e, struct esh_pipeline, elem);
printf(" ------------- \n");
esh_pipeline_print(pipe);
}
printf("==========================================\n");
}
/* Deallocation functions. */
void
esh_command_line_free(struct esh_command_line *cmdline)
{
struct list_elem * e = list_begin (&cmdline->pipes);
for (; e != list_end (&cmdline->pipes); ) {
struct esh_pipeline *pipe = list_entry(e, struct esh_pipeline, elem);
e = list_remove(e);
esh_pipeline_free(pipe);
}
free(cmdline);
}
void
esh_pipeline_free(struct esh_pipeline *pipe)
{
struct list_elem * e = list_begin (&pipe->commands);
for (; e != list_end (&pipe->commands); ) {
struct esh_command *cmd = list_entry(e, struct esh_command, elem);
e = list_remove(e);
esh_command_free(cmd);
}
free(pipe);
}
void
esh_command_free(struct esh_command * cmd)
{
char ** p = cmd->argv;
while (*p) {
free(*p++);
}
if (cmd->iored_input)
free(cmd->iored_input);
if (cmd->iored_output)
free(cmd->iored_output);
free(cmd->argv);
free(cmd);
}
#define PSH_MODULE_NAME "esh_module"
/* Load a plugin referred to by modname */
static struct esh_plugin *
load_plugin(char *modname)
{
printf("Loading %s ...", modname);
fflush(stdout);
void *handle = dlopen(modname, RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "Could not open %s: %s\n", modname, dlerror());
return NULL;
}
struct esh_plugin * p = dlsym(handle, PSH_MODULE_NAME);
if (p == NULL) {
fprintf(stderr, "%s does not define %s\n", modname, PSH_MODULE_NAME);
dlclose(handle);
return NULL;
}
printf("done.\n");
return p;
}
static bool sort_by_rank (const struct list_elem *a,
const struct list_elem *b,
void *aux __attribute__((unused)))
{
struct esh_plugin * pa = list_entry(a, struct esh_plugin, elem);
struct esh_plugin * pb = list_entry(b, struct esh_plugin, elem);
return pa->rank < pb->rank;
}
/* Load plugins from directory dirname */
void
esh_plugin_load_from_directory(char *dirname)
{
DIR * dir = opendir(dirname);
if (dir == NULL) {
perror("opendir");
return;
}
struct dirent * dentry;
while ((dentry = readdir(dir)) != NULL) {
if (!strstr(dentry->d_name, ".so"))
continue;
char modname[PATH_MAX + 1];
snprintf(modname, sizeof modname, "%s/%s", dirname, dentry->d_name);
struct esh_plugin * plugin = load_plugin(modname);
if (plugin)
list_push_back(&esh_plugin_list, &plugin->elem);
}
closedir(dir);
}
/* Initialize loaded plugins */
void
esh_plugin_initialize(struct esh_shell *shell)
{
/* Sort plugins and call init() method. */
list_sort(&esh_plugin_list, sort_by_rank, NULL);
struct list_elem * e = list_begin(&esh_plugin_list);
for (; e != list_end(&esh_plugin_list); e = list_next(e)) {
struct esh_plugin *plugin = list_entry(e, struct esh_plugin, elem);
if (plugin->init)
plugin->init(shell);
}
}
/* TBD: implement unloading. */