sh
/* $Id$ */
/* Copyright (c) 2005-2012 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Unix sh */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "sh.h"
#include "job.h"
/* types */
typedef struct _Job
{
char * command;
pid_t pid;
JobStatus status;
int error;
} Job;
/* variables */
static Job * jobs = NULL;
static unsigned int jobs_cnt = 0;
/* job_add */
static int _add_wait(unsigned int id);
static void _add_wait_all(void);
int job_add(char * command, pid_t pid, JobStatus status)
{
int ret = 0;
Job * p;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%u)\n", __func__, jobs_cnt + 1);
#endif
if((command = strdup(command)) == NULL)
return sh_error("malloc", 1);
if((p = realloc(jobs, sizeof(*p) * (jobs_cnt + 1))) == NULL)
{
free(command);
return sh_error("malloc", 1);
}
jobs = p;
p = &jobs[jobs_cnt++];
p->command = command;
p->pid = pid;
p->status = status;
/* FIXME depending on further C-z handling we could do this earlier */
if(status == JS_WAIT)
ret = _add_wait(jobs_cnt);
_add_wait_all();
return ret;
}
static int _job_remove(unsigned int id);
static int _add_wait(unsigned int id)
{
int status;
for(;;)
if(waitpid(jobs[id - 1].pid, &status, 0) == -1)
return sh_error("waitpid", -1);
else if(WIFEXITED(status) || WIFSIGNALED(status))
break;
_job_remove(id);
return WEXITSTATUS(status);
}
static void _job_print(unsigned int id, char c, char * state);
static void _add_wait_all(void)
{
pid_t pid = 0;
int status;
unsigned int i;
while(jobs_cnt > 0 && (pid = waitpid(-1, &status, WNOHANG)) > 0)
{
for(i = 0; i < jobs_cnt && jobs[i].pid != pid; i++);
if(i == jobs_cnt)
continue;
_job_print(i + 1, 'X', "FIXME");
_job_remove(i + 1);
}
if(pid == -1)
sh_error("waitpid", 0);
}
/* job_kill_status */
int job_kill_status(int signum, JobStatus status)
{
int ret = 0;
unsigned int i;
for(i = 0; i < jobs_cnt; i++)
if(jobs[i].status == status)
ret |= kill(jobs[i].pid, signum);
return ret == 0 ? 0 : 1;
}
/* job_remove */
static int _job_remove(unsigned int id)
{
Job * p;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%u)\n", __func__, id);
#endif
if(id > jobs_cnt)
return 1;
if(id > 1)
{
free(jobs[id - 1].command);
memmove(&jobs[id - 1], &jobs[id], (jobs_cnt - id) * sizeof(*p));
if((p = realloc(jobs, sizeof(*p) * --jobs_cnt)) == NULL
&& jobs_cnt != 0)
return sh_error("malloc", 1);
jobs = p;
}
else /* FIXME check this code */
jobs_cnt--;
return 0;
}
/* job_list */
int job_list(int argc, char * argv[])
{
int i;
unsigned int j;
unsigned int id;
char * p;
if(argc == 0)
{
for(j = 0; j < jobs_cnt; j++)
_job_print(j+1, 'X', "FIXME");
return 0;
}
for(i = 1; i < argc; i++)
{
id = strtol(argv[i], &p, 10);
if(*(argv[i]) == '\0' || *p != '\0' || id < 1 || id >= jobs_cnt)
continue;
_job_print(id+1, 'X', "FIXME");
}
return 0;
}
/* job_pgids */
int job_pgids(int argc, char * argv[])
{
/* FIXME implement */
return 1;
}
/* job_print */
static void _job_print(unsigned int id, char c, char * state)
{
printf("[%u] %c %s %s\n", id, c, state, jobs[id - 1].command);
}
/* job_status */
int job_status(int argc, char * argv[])
{
/* FIXME ? */
job_list(1, NULL);
return 1;
}