blob: d62d4e803960933a020b986df8b7e2b0565f42d5 [file] [log] [blame]
/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/* $Id: zoolib.c,v 1.3 2001/02/28 17:42:00 nstraz Exp $ */
#include <stdlib.h> /* for getenv */
#include <string.h>
#include "zoolib.h"
#ifdef __linux__
/* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */
extern int sighold (int __sig);
extern int sigrelse (int __sig);
#endif
#define A_BUF_SZ 100
static char Errmsg[500];
char *
zoo_active()
{
char *fname = "active";
static char *active = NULL;
char *zoo;
if( active == NULL ){
zoo = getenv( "ZOO" );
if( zoo != NULL ){
active = (char*)malloc( strlen(zoo) + 1 +
strlen(fname) + 1 );
sprintf( active, "%s/%s", zoo, fname );
}
}
return active;
}
FILE *
open_file( char *file, char *mode, char **errmsg )
{
FILE *fp;
if( errmsg != NULL )
*errmsg = Errmsg;
if( strcmp( mode, "r+" ) == 0 ){
/* make sure there's a file */
if( (fp = fopen( file, "a" )) == NULL ){
sprintf(Errmsg, "Unable to create file '%s'. %s/%d errno:%d %s\n",
file, __FILE__, __LINE__, errno, strerror(errno));
return(NULL);
}
else
fclose( fp );
}
if( (fp = fopen( file, mode )) == NULL ){
sprintf(Errmsg, "Unable to open(%s,%s). %s/%d errno:%d %s\n",
file, mode, __FILE__, __LINE__, errno, strerror(errno));
return(NULL);
}
return fp;
}
int
seek_file( FILE *fp, long int offset, int whence, char **errmsg )
{
if( errmsg != NULL )
*errmsg = Errmsg;
if( (whence != SEEK_SET) && (whence != SEEK_END) ){
sprintf(Errmsg, "whence is bad. %s/%d\n", __FILE__, __LINE__ );
return(-1);
}
if( fseek( fp, offset, whence ) != 0 ){
sprintf(Errmsg,"fseek(%ld,%s) failed. %s/%d errno:%d %s\n",
offset,
whence == SEEK_SET ? "SEEK_SET" : "SEEK_END",
__FILE__, __LINE__,
errno, strerror(errno));
return(-1);
}
return whence;
}
int
lock_file( FILE *fp, short ltype, char **errmsg )
{
struct flock flk;
int ret=1;
if( errmsg != NULL )
*errmsg = Errmsg;
if( (ltype != F_WRLCK) && (ltype != F_UNLCK) ){
sprintf(Errmsg, "bad ltype, %s/%d\n", __FILE__, __LINE__ );
return(-1);
}
flk.l_whence = flk.l_start = flk.l_len = 0;
flk.l_type = ltype;
/* XXX it's time to upgrade this code for sigaction */
sighold(SIGINT);
sighold(SIGTERM);
sighold(SIGHUP);
sighold(SIGUSR1);
sighold(SIGUSR2);
if( fcntl( fileno(fp), F_SETLKW, &flk ) == -1 ){
sprintf(Errmsg, "fcntl(%s) failed. %s/%d errno:%d %s\n",
ltype == F_WRLCK ? "F_WRLCK" : "F_UNLCK",
__FILE__, __LINE__,
errno, strerror(errno));
ret=-1;
}
sigrelse(SIGINT);
sigrelse(SIGTERM);
sigrelse(SIGHUP);
sigrelse(SIGUSR1);
sigrelse(SIGUSR2);
return(ret);
}
int
write_active( FILE *fp, char *name, char **errmsg )
{
pid_t pid = getpid();
char *emsg;
if( fp == NULL )
return(1);
if( errmsg != NULL )
*errmsg = Errmsg;
if( lock_file( fp, F_WRLCK, &emsg ) == -1 )
return(-1);
if( seek_file( fp, 0, SEEK_END, &emsg ) == -1 )
return(-1);
/* Write pid first so update_active() can find it quickly.
* update_active() will probably be used far more often than any
* process that needs to search by name anyway.
*/
fprintf( fp, "%d,%s\n", pid, name );
fflush( fp );
if( lock_file( fp, F_UNLCK, &emsg ) == -1 )
return(-1);
return(1);
}
/*
* Write a command to the active file, with arguments.
* Uses a "first fit" algorithm to take the first available line
* Inactive commandlines are assumed to start with a "#"
*/
int
write_active_args( FILE *fp, pid_t pid, char *name, int argc,
char **argv, char **errmsg )
{
char *args, *cat_args();
char active[81]; /* max length.. */
int len, l2, found;
long int pos;
char buf[A_BUF_SZ];
char *emsg;
if( fp == NULL )
return(1);
if( errmsg != NULL )
*errmsg = Errmsg;
if( (args = cat_args(argc, argv, &emsg)) == NULL )
return(-1);
len = sprintf(active, "%d,%s,", pid, name);
strncat(active, args, 80 - len);
len = strlen(active);
free(args);
if( lock_file( fp, F_WRLCK, &emsg ) == -1 )
return(-1);
if( seek_file( fp, 0, SEEK_SET, &emsg ) == -1 )
return(-1);
found=0;
while(1) {
pos = ftell( fp );
if( fgets( buf, A_BUF_SZ - 1, fp ) == NULL )
break;
if( buf[0] == '#' ) {
/* "First Fit" */
if( (l2=strlen(buf)) > len ) { /* can rewrite this one */
if( seek_file( fp, pos, SEEK_SET, &emsg ) == -1 )
return(-1);
fprintf( fp, "%s%*.*s\n", active, l2-len-1, l2-len-1,
"|");
found=1;
break;
}
}
}/* while */
if(!found) {
if( seek_file( fp, 0, SEEK_END, &emsg ) == -1 )
return(-1);
/* Write pid first so update_active() can find it quickly.
* update_active() will probably be used far more often than any
* process that needs to search by name anyway.
*/
fprintf( fp, "%s\n", active );
}
fflush( fp );
if( lock_file( fp, F_UNLCK, &emsg ) == -1 )
return(-1);
return(1);
}
int
clear_active( FILE *fp, pid_t me, char **errmsg )
{
char buf[A_BUF_SZ];
int pid;
long int pos;
int found = 0;
char *emsg;
if( fp == NULL )
return(1);
if( lock_file( fp, F_WRLCK, &emsg ) == -1 )
return(-1);
if( seek_file( fp, 0, SEEK_SET, &emsg ) == -1 )
return(-1);
while(1){
pos = ftell( fp );
if( fgets( buf, A_BUF_SZ - 1, fp ) == NULL )
break;
if( buf[0] == '#' )
continue;
/* is pid me? */
pid = atoi( buf );
if( pid != me )
continue;
if( seek_file( fp, pos, SEEK_SET, &emsg ) == -1 )
return(-1);
fprintf( fp, "#" );
found++;
break;
}/* while */
fflush( fp );
if( lock_file( fp, F_UNLCK, &emsg ) == -1 )
return(-1);
if( ! found ){
sprintf(Errmsg, "clear_active() did not find pid(%d). %s/%d\n",
me, __FILE__, __LINE__ );
return(0);
}
return(1);
}
void
wait_handler( int sig )
{
static int lastsent = 0;
if( sig == 0 ){
lastsent = 0;
}
else {
rec_signal = sig;
if( sig == SIGUSR2 )
return;
if( lastsent == 0 )
send_signal = sig;
else if( lastsent == SIGUSR1 )
send_signal = SIGINT;
else if( lastsent == sig )
send_signal = SIGTERM;
else if( lastsent == SIGTERM )
send_signal = SIGHUP;
else if( lastsent == SIGHUP )
send_signal = SIGKILL;
lastsent = send_signal;
}
}
char *
cat_args(int argc, char **argv, char **errmsg)
{
int a, size;
char *cmd;
for(size=a=0;a<argc;a++) {
size += strlen(argv[a]);
size++;
}
if( (cmd = (char *)malloc(size)) == NULL ) {
sprintf(Errmsg, "Malloc Error, %s/%d", __FILE__, __LINE__);
return(NULL);
}
*cmd='\0';
for(a=0;a<argc;a++) {
if(a != 0)
strcat(cmd, " ");
strcat(cmd, argv[a]);
}
return(cmd);
}