2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #include <afs/procmgmt.h>
20 #include <afs/audit.h>
21 #include <afs/afsutil.h>
22 #include <afs/fileutil.h>
23 #include <opr/queue.h>
26 #include "bnode_internal.h"
27 #include "bosprototypes.h"
30 #define WCOREDUMP(x) ((x) & 0200)
33 #define BNODE_LWP_STACKSIZE (16 * 1024)
34 #define BNODE_ERROR_COUNT_MAX 16 /* maximum number of retries */
35 #define BNODE_ERROR_DELAY_MAX 60 /* maximum retry delay (seconds) */
37 static PROCESS bproc_pid
; /* pid of waker-upper */
38 static struct opr_queue allBnodes
; /**< List of all bnodes */
39 static struct opr_queue allProcs
; /**< List of all processes for which we're waiting */
40 static struct opr_queue allTypes
; /**< List of all registered type handlers */
42 static struct bnode_stats
{
46 extern const char *DoCore
;
47 extern const char *DoPidFiles
;
49 extern char **environ
; /* env structure */
52 int hdl_notifier(struct bnode_proc
*tp
);
54 /* Remember the name of the process, if any, that failed last */
56 RememberProcName(struct bnode_proc
*ap
)
58 struct bnode
*tbnodep
;
61 if (tbnodep
->lastErrorName
) {
62 free(tbnodep
->lastErrorName
);
63 tbnodep
->lastErrorName
= NULL
;
66 tbnodep
->lastErrorName
= strdup(ap
->coreName
);
69 /* utility for use by BOP_HASCORE functions to determine where a core file might
73 bnode_CoreName(struct bnode
*abnode
, char *acoreName
, char *abuffer
)
76 strcpy(abuffer
, DoCore
);
78 strcat(abuffer
, AFSDIR_CORE_FILE
);
80 strcpy(abuffer
, AFSDIR_SERVER_CORELOG_FILEPATH
);
82 strcat(abuffer
, acoreName
);
85 strcat(abuffer
, abnode
->name
);
89 /* save core file, if any */
91 SaveCore(struct bnode
*abnode
, struct bnode_proc
97 char *corefile
= NULL
;
98 #ifdef BOZO_SAVE_CORES
100 struct tm
*TimeFields
;
104 /* Linux always appends the PID to core dumps from threaded processes, so
105 * we have to scan the directory to find core files under another name. */
107 strcpy(tbuffer
, DoCore
);
108 strcat(tbuffer
, "/");
109 strcat(tbuffer
, AFSDIR_CORE_FILE
);
111 code
= stat(AFSDIR_SERVER_CORELOG_FILEPATH
, &tstat
);
116 const char *coredir
= AFSDIR_LOGS_DIR
;
121 logdir
= opendir(coredir
);
124 while ((file
= readdir(logdir
)) != NULL
) {
125 if (strncmp(file
->d_name
, "core.", 5) != 0)
127 pid
= atol(file
->d_name
+ 5);
128 if (pid
== aproc
->pid
) {
131 r
= asprintf(&corefile
, "%s/%s", coredir
, file
->d_name
);
132 if (r
< 0 || corefile
== NULL
) {
142 corefile
= strdup(tbuffer
);
147 bnode_CoreName(abnode
, aproc
->coreName
, tbuffer
);
148 #ifdef BOZO_SAVE_CORES
149 FT_GetTimeOfDay(&Start
, 0);
150 TimeFields
= localtime(&Start
.tv_sec
);
151 sprintf(FileName
, "%s.%d%02d%02d%02d%02d%02d", tbuffer
,
152 TimeFields
->tm_year
+ 1900, TimeFields
->tm_mon
+ 1, TimeFields
->tm_mday
,
153 TimeFields
->tm_hour
, TimeFields
->tm_min
, TimeFields
->tm_sec
);
154 strcpy(tbuffer
, FileName
);
156 rk_rename(corefile
, tbuffer
);
161 bnode_GetString(struct bnode
*abnode
, char *abuffer
,
164 return BOP_GETSTRING(abnode
, abuffer
, alen
);
168 bnode_GetParm(struct bnode
*abnode
, afs_int32 aindex
,
169 char *abuffer
, afs_int32 alen
)
171 return BOP_GETPARM(abnode
, aindex
, abuffer
, alen
);
175 bnode_GetStat(struct bnode
*abnode
, afs_int32
* astatus
)
177 return BOP_GETSTAT(abnode
, astatus
);
181 bnode_RestartP(struct bnode
*abnode
)
183 return BOP_RESTARTP(abnode
);
187 bnode_Check(struct bnode
*abnode
)
189 if (abnode
->flags
& BNODE_WAIT
) {
190 abnode
->flags
&= ~BNODE_WAIT
;
191 LWP_NoYieldSignal(abnode
);
196 /* tell if an instance has a core file */
198 bnode_HasCore(struct bnode
*abnode
)
200 return BOP_HASCORE(abnode
);
203 /* wait for all bnodes to stabilize */
207 struct opr_queue
*cursor
;
212 for (opr_queue_Scan(&allBnodes
, cursor
)) {
213 struct bnode
*tb
= opr_queue_Entry(cursor
, struct bnode
, q
);
216 code
= BOP_GETSTAT(tb
, &stat
);
221 if (stat
!= tb
->goal
) {
222 tb
->flags
|= BNODE_WAIT
;
232 /* wait until bnode status is correct */
234 bnode_WaitStatus(struct bnode
*abnode
, int astatus
)
242 code
= BOP_GETSTAT(abnode
, &stat
);
246 /* otherwise, check if we're done */
247 if (stat
== astatus
) {
248 bnode_Release(abnode
);
251 if (astatus
!= abnode
->goal
) {
252 bnode_Release(abnode
);
253 return -1; /* no longer our goal, don't keep waiting */
255 /* otherwise, block */
256 abnode
->flags
|= BNODE_WAIT
;
257 LWP_WaitProcess(abnode
);
262 bnode_ResetErrorCount(struct bnode
*abnode
)
264 abnode
->errorStopCount
= 0;
265 abnode
->errorStopDelay
= 0;
270 bnode_SetStat(struct bnode
*abnode
, int agoal
)
272 abnode
->goal
= agoal
;
274 BOP_SETSTAT(abnode
, agoal
);
275 abnode
->flags
&= ~BNODE_ERRORSTOP
;
280 bnode_SetGoal(struct bnode
*abnode
, int agoal
)
282 abnode
->goal
= agoal
;
288 bnode_SetFileGoal(struct bnode
*abnode
, int agoal
)
290 if (abnode
->fileGoal
== agoal
)
291 return 0; /* already done */
292 abnode
->fileGoal
= agoal
;
297 /* apply a function to all bnodes in the system */
299 bnode_ApplyInstance(int (*aproc
) (struct bnode
*tb
, void *), void *arock
)
301 struct opr_queue
*cursor
, *store
;
304 for (opr_queue_ScanSafe(&allBnodes
, cursor
, store
)) {
305 struct bnode
*tb
= opr_queue_Entry(cursor
, struct bnode
, q
);
306 code
= (*aproc
) (tb
, arock
);
314 bnode_FindInstance(char *aname
)
316 struct opr_queue
*cursor
;
318 for (opr_queue_Scan(&allBnodes
, cursor
)) {
319 struct bnode
*tb
= opr_queue_Entry(cursor
, struct bnode
, q
);
321 if (!strcmp(tb
->name
, aname
))
327 static struct bnode_type
*
328 FindType(char *aname
)
330 struct opr_queue
*cursor
;
332 for (opr_queue_Scan(&allTypes
, cursor
)) {
333 struct bnode_type
*tt
= opr_queue_Entry(cursor
, struct bnode_type
, q
);
335 if (!strcmp(tt
->name
, aname
))
342 bnode_Register(char *atype
, struct bnode_ops
*aprocs
, int anparms
)
344 struct opr_queue
*cursor
;
345 struct bnode_type
*tt
= NULL
;
347 for (opr_queue_Scan(&allTypes
, cursor
), tt
= NULL
) {
348 tt
= opr_queue_Entry(cursor
, struct bnode_type
, q
);
349 if (!strcmp(tt
->name
, atype
))
353 tt
= calloc(1, sizeof(struct bnode_type
));
354 opr_queue_Init(&tt
->q
);
355 opr_queue_Prepend(&allTypes
, &tt
->q
);
363 bnode_Create(char *atype
, char *ainstance
, struct bnode
** abp
, char *ap1
,
364 char *ap2
, char *ap3
, char *ap4
, char *ap5
, char *notifier
,
365 int fileGoal
, int rewritefile
)
367 struct bnode_type
*type
;
369 char *notifierpath
= NULL
;
372 if (bnode_FindInstance(ainstance
))
374 type
= FindType(atype
);
378 if (notifier
&& strcmp(notifier
, NONOTIFIER
)) {
379 /* construct local path from canonical (wire-format) path */
380 if (ConstructLocalBinPath(notifier
, ¬ifierpath
)) {
381 bozo_Log("BNODE-Create: Notifier program path invalid '%s'\n",
386 if (stat(notifierpath
, &tstat
)) {
387 bozo_Log("BNODE-Create: Notifier program '%s' not found\n",
393 tb
= (*type
->ops
->create
) (ainstance
, ap1
, ap2
, ap3
, ap4
, ap5
);
398 tb
->notifier
= notifierpath
;
402 /* The fs_create above calls bnode_InitBnode() which always sets the
403 ** fileGoal to BSTAT_NORMAL .... overwrite it with whatever is passed into
404 ** this function as a parameter... */
405 tb
->fileGoal
= fileGoal
;
407 bnode_SetStat(tb
, tb
->goal
); /* nudge it once */
409 if (rewritefile
!= 0)
416 bnode_DeleteName(char *ainstance
)
420 tb
= bnode_FindInstance(ainstance
);
424 return bnode_Delete(tb
);
428 bnode_Hold(struct bnode
*abnode
)
435 bnode_Release(struct bnode
*abnode
)
438 if (abnode
->refCount
== 0 && abnode
->flags
& BNODE_DELETE
) {
439 abnode
->flags
&= ~BNODE_DELETE
; /* we're going for it */
440 bnode_Delete(abnode
);
446 bnode_Delete(struct bnode
*abnode
)
451 if (abnode
->refCount
!= 0) {
452 abnode
->flags
|= BNODE_DELETE
;
456 /* make sure the bnode is idle before zapping */
458 code
= BOP_GETSTAT(abnode
, &temp
);
459 bnode_Release(abnode
);
462 if (temp
!= BSTAT_SHUTDOWN
)
465 /* all clear to zap */
466 opr_queue_Remove(&abnode
->q
);
467 free(abnode
->name
); /* do this first, since bnode fields may be bad after BOP_DELETE */
468 code
= BOP_DELETE(abnode
); /* don't play games like holding over this one */
473 /* function to tell if there's a timeout coming up */
475 bnode_PendingTimeout(struct bnode
*abnode
)
477 return (abnode
->flags
& BNODE_NEEDTIMEOUT
);
480 /* function called to set / clear periodic bnode wakeup times */
482 bnode_SetTimeout(struct bnode
*abnode
, afs_int32 atimeout
)
485 abnode
->nextTimeout
= FT_ApproxTime() + atimeout
;
486 abnode
->flags
|= BNODE_NEEDTIMEOUT
;
487 abnode
->period
= atimeout
;
488 IOMGR_Cancel(bproc_pid
);
490 abnode
->flags
&= ~BNODE_NEEDTIMEOUT
;
495 /* used by new bnode creation code to format bnode header */
497 bnode_InitBnode(struct bnode
*abnode
, struct bnode_ops
*abnodeops
,
500 /* format the bnode properly */
501 memset(abnode
, 0, sizeof(struct bnode
));
502 opr_queue_Init(&abnode
->q
);
503 abnode
->ops
= abnodeops
;
504 abnode
->name
= strdup(aname
);
507 abnode
->flags
= BNODE_ACTIVE
;
508 abnode
->fileGoal
= BSTAT_NORMAL
;
509 abnode
->goal
= BSTAT_SHUTDOWN
;
511 /* put the bnode at the end of the list so we write bnode file in same order */
512 opr_queue_Append(&allBnodes
, &abnode
->q
);
517 /* bnode lwp executes this code repeatedly */
524 struct opr_queue
*cursor
, *store
;
525 struct bnode_proc
*tp
;
526 int options
; /* must not be register */
532 /* first figure out how long to sleep for */
533 temp
= 0x7fffffff; /* afs_int32 time; maxint doesn't work in select */
535 for (opr_queue_Scan(&allBnodes
, cursor
)) {
536 tb
= opr_queue_Entry(cursor
, struct bnode
, q
);
537 if (tb
->flags
& BNODE_NEEDTIMEOUT
) {
538 if (tb
->nextTimeout
< temp
) {
540 temp
= tb
->nextTimeout
;
544 /* now temp has the time at which we should wakeup next */
548 temp
-= FT_ApproxTime(); /* how many seconds until next event */
554 code
= IOMGR_Select(0, 0, 0, 0, &tv
);
556 code
= 0; /* fake timeout code */
558 /* figure out why we woke up; child exit or timeouts */
559 FT_GetTimeOfDay(&tv
, 0); /* must do the real gettimeofday once and a while */
562 /* check all bnodes to see which ones need timeout events */
563 for (opr_queue_ScanSafe(&allBnodes
, cursor
, store
)) {
564 tb
= opr_queue_Entry(cursor
, struct bnode
, q
);
565 if ((tb
->flags
& BNODE_NEEDTIMEOUT
) && temp
> tb
->nextTimeout
) {
569 if (tb
->flags
& BNODE_NEEDTIMEOUT
) { /* check again, BOP_TIMEOUT could change */
570 tb
->nextTimeout
= FT_ApproxTime() + tb
->period
;
572 bnode_Release(tb
); /* delete may occur here */
577 /* signalled, probably by incoming signal */
580 code
= waitpid((pid_t
) - 1, &status
, options
);
581 if (code
== 0 || code
== -1)
582 break; /* all done */
583 /* otherwise code has a process id, which we now search for */
584 for (tp
= NULL
, opr_queue_Scan(&allProcs
, cursor
), tp
= NULL
) {
585 tp
= opr_queue_Entry(cursor
, struct bnode_proc
, q
);
595 /* count restarts in last 30 seconds */
596 if (temp
> tb
->rsTime
+ 30) {
597 /* it's been 30 seconds we've been counting */
603 if (WIFSIGNALED(status
) == 0) {
604 /* exited, not signalled */
605 tp
->lastExit
= WEXITSTATUS(status
);
608 tb
->errorCode
= tp
->lastExit
;
609 tb
->lastErrorExit
= FT_ApproxTime();
610 RememberProcName(tp
);
614 bozo_Log("%s:%s exited with code %d\n", tb
->name
,
615 tp
->coreName
, tp
->lastExit
);
617 bozo_Log("%s exited with code %d\n", tb
->name
,
620 /* Signal occurred, perhaps spurious due to shutdown request.
621 * If due to a shutdown request, don't overwrite last error
624 tp
->lastSignal
= WTERMSIG(status
);
626 if (tp
->lastSignal
!= SIGQUIT
627 && tp
->lastSignal
!= SIGTERM
628 && tp
->lastSignal
!= SIGKILL
) {
629 tb
->errorSignal
= tp
->lastSignal
;
630 tb
->lastErrorExit
= FT_ApproxTime();
631 RememberProcName(tp
);
634 bozo_Log("%s:%s exited on signal %d%s\n",
635 tb
->name
, tp
->coreName
, tp
->lastSignal
,
636 WCOREDUMP(status
) ? " (core dumped)" :
639 bozo_Log("%s exited on signal %d%s\n", tb
->name
,
641 WCOREDUMP(status
) ? " (core dumped)" :
645 tb
->lastAnyExit
= FT_ApproxTime();
648 bozo_Log("BNODE: Notifier %s will be called\n",
653 if (tb
->goal
&& tb
->rsCount
++ > 10) {
654 /* 10 in 30 seconds */
655 if (tb
->errorStopCount
>= BNODE_ERROR_COUNT_MAX
) {
656 tb
->errorStopDelay
= 0; /* max reached, give up. */
658 tb
->errorStopCount
++;
659 if (!tb
->errorStopDelay
) {
660 tb
->errorStopDelay
= 1; /* wait a second, then retry */
662 tb
->errorStopDelay
*= 2; /* ramp up the retry delays */
664 if (tb
->errorStopDelay
> BNODE_ERROR_DELAY_MAX
) {
665 tb
->errorStopDelay
= BNODE_ERROR_DELAY_MAX
; /* cap the delay */
668 tb
->flags
|= BNODE_ERRORSTOP
;
669 bnode_SetGoal(tb
, BSTAT_SHUTDOWN
);
671 ("BNODE '%s' repeatedly failed to start, perhaps missing executable.\n",
674 BOP_PROCEXIT(tb
, tp
);
676 bnode_Release(tb
); /* bnode delete can happen here */
677 opr_queue_Remove(&tp
->q
);
680 bnode_stats
.weirdPids
++;
688 SendNotifierData(int fd
, struct bnode_proc
*tp
)
690 struct bnode
*tb
= tp
->bnode
;
691 char buffer
[1000], *bufp
= buffer
, *buf1
;
695 * First sent out the bnode_proc struct
697 (void)sprintf(bufp
, "BEGIN bnode_proc\n");
698 bufp
+= strlen(bufp
);
699 (void)sprintf(bufp
, "comLine: %s\n", tp
->comLine
);
700 bufp
+= strlen(bufp
);
701 if (!(buf1
= tp
->coreName
))
703 (void)sprintf(bufp
, "coreName: %s\n", buf1
);
704 bufp
+= strlen(bufp
);
705 (void)sprintf(bufp
, "pid: %ld\n", afs_printable_int32_ld(tp
->pid
));
706 bufp
+= strlen(bufp
);
707 (void)sprintf(bufp
, "lastExit: %ld\n", afs_printable_int32_ld(tp
->lastExit
));
708 bufp
+= strlen(bufp
);
710 (void)sprintf(bufp
, "lastSignal: %ld\n", afs_printable_int32_ld(tp
->lastSignal
));
711 bufp
+= strlen(bufp
);
713 (void)sprintf(bufp
, "flags: %ld\n", afs_printable_int32_ld(tp
->flags
));
714 bufp
+= strlen(bufp
);
715 (void)sprintf(bufp
, "END bnode_proc\n");
716 bufp
+= strlen(bufp
);
717 len
= (int)(bufp
- buffer
);
718 if (write(fd
, buffer
, len
) < 0) {
723 * Now sent out the bnode struct
726 (void)sprintf(bufp
, "BEGIN bnode\n");
727 bufp
+= strlen(bufp
);
728 (void)sprintf(bufp
, "name: %s\n", tb
->name
);
729 bufp
+= strlen(bufp
);
730 (void)sprintf(bufp
, "rsTime: %ld\n", afs_printable_int32_ld(tb
->rsTime
));
731 bufp
+= strlen(bufp
);
732 (void)sprintf(bufp
, "rsCount: %ld\n", afs_printable_int32_ld(tb
->rsCount
));
733 bufp
+= strlen(bufp
);
734 (void)sprintf(bufp
, "procStartTime: %ld\n", afs_printable_int32_ld(tb
->procStartTime
));
735 bufp
+= strlen(bufp
);
736 (void)sprintf(bufp
, "procStarts: %ld\n", afs_printable_int32_ld(tb
->procStarts
));
737 bufp
+= strlen(bufp
);
738 (void)sprintf(bufp
, "lastAnyExit: %ld\n", afs_printable_int32_ld(tb
->lastAnyExit
));
739 bufp
+= strlen(bufp
);
740 (void)sprintf(bufp
, "lastErrorExit: %ld\n", afs_printable_int32_ld(tb
->lastErrorExit
));
741 bufp
+= strlen(bufp
);
742 (void)sprintf(bufp
, "errorCode: %ld\n", afs_printable_int32_ld(tb
->errorCode
));
743 bufp
+= strlen(bufp
);
744 (void)sprintf(bufp
, "errorSignal: %ld\n", afs_printable_int32_ld(tb
->errorSignal
));
745 bufp
+= strlen(bufp
);
747 (void) sprintf(bufp, "lastErrorName: %s\n", tb->lastErrorName);
748 bufp += strlen(bufp);
750 (void)sprintf(bufp
, "goal: %d\n", tb
->goal
);
751 bufp
+= strlen(bufp
);
752 (void)sprintf(bufp
, "END bnode\n");
753 bufp
+= strlen(bufp
);
754 len
= (int)(bufp
- buffer
);
755 if (write(fd
, buffer
, len
) < 0) {
762 hdl_notifier(struct bnode_proc
*tp
)
764 #ifndef AFS_NT40_ENV /* NT notifier callout not yet implemented */
768 if (stat(tp
->bnode
->notifier
, &tstat
)) {
769 bozo_Log("BNODE: Failed to find notifier '%s'; ignored\n",
770 tp
->bnode
->notifier
);
773 if ((pid
= fork()) == 0) {
775 struct bnode
*tb
= tp
->bnode
;
777 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI51_ENV)
779 #elif defined(AFS_DARWIN90_ENV)
781 #elif defined(AFS_LINUX20_ENV) || defined(AFS_AIX_ENV)
786 fout
= popen(tb
->notifier
, "w");
788 bozo_Log("BNODE: Failed to find notifier '%s'; ignored\n",
790 perror(tb
->notifier
);
793 SendNotifierData(fileno(fout
), tp
);
796 } else if (pid
< 0) {
797 bozo_Log("Failed to fork creating process to handle notifier '%s'\n",
798 tp
->bnode
->notifier
);
801 #endif /* AFS_NT40_ENV */
805 /* Called by IOMGR at low priority on IOMGR's stack shortly after a SIGCHLD
806 * occurs. Wakes up bproc do redo things */
808 bnode_SoftInt(void *param
)
810 /* int asignal = (int) param; */
812 IOMGR_Cancel(bproc_pid
);
816 /* Called at signal interrupt level; queues function to be called
817 * when IOMGR runs again.
820 bnode_Int(int asignal
)
822 if (asignal
== SIGQUIT
|| asignal
== SIGTERM
) {
823 IOMGR_SoftSig(bozo_ShutdownAndExit
, (void *)(intptr_t)asignal
);
825 IOMGR_SoftSig(bnode_SoftInt
, (void *)(intptr_t)asignal
);
830 /* intialize the whole system */
836 struct sigaction newaction
;
837 static int initDone
= 0;
842 opr_queue_Init(&allTypes
);
843 opr_queue_Init(&allProcs
);
844 opr_queue_Init(&allBnodes
);
845 memset(&bnode_stats
, 0, sizeof(bnode_stats
));
846 LWP_InitializeProcessSupport(1, &junk
); /* just in case */
848 code
= LWP_CreateProcess(bproc
, BNODE_LWP_STACKSIZE
,
849 /* priority */ 1, (void *) /* parm */ 0,
850 "bnode-manager", &bproc_pid
);
853 memset(&newaction
, 0, sizeof(newaction
));
854 newaction
.sa_handler
= bnode_Int
;
855 code
= sigaction(SIGCHLD
, &newaction
, NULL
);
858 code
= sigaction(SIGQUIT
, &newaction
, NULL
);
861 code
= sigaction(SIGTERM
, &newaction
, NULL
);
867 /* free token list returned by parseLine */
869 bnode_FreeTokens(struct bnode_token
*alist
)
871 struct bnode_token
*nlist
;
872 for (; alist
; alist
= nlist
) {
883 if (x
== 0 || x
== ' ' || x
== '\t' || x
== '\n')
890 bnode_ParseLine(char *aline
, struct bnode_token
**alist
)
895 struct bnode_token
*first
, *last
;
896 struct bnode_token
*ttok
;
899 inToken
= 0; /* not copying token chars at start */
900 first
= (struct bnode_token
*)0;
901 last
= (struct bnode_token
*)0;
904 if (tc
== 0 || space(tc
)) { /* terminating null gets us in here, too */
906 inToken
= 0; /* end of this token */
908 ttok
= malloc(sizeof(struct bnode_token
));
909 ttok
->next
= (struct bnode_token
*)0;
910 ttok
->key
= strdup(tbuffer
);
920 /* an alpha character */
925 if (tptr
- tbuffer
>= sizeof(tbuffer
))
926 return -1; /* token too long */
930 /* last token flushed 'cause space(0) --> true */
932 last
->next
= (struct bnode_token
*)0;
941 bnode_NewProc(struct bnode
*abnode
, char *aexecString
, char *coreName
,
942 struct bnode_proc
**aproc
)
944 struct bnode_token
*tlist
, *tt
;
946 struct bnode_proc
*tp
;
948 char *argv
[MAXVARGS
];
951 code
= bnode_ParseLine(aexecString
, &tlist
); /* try parsing first */
954 tp
= calloc(1, sizeof(struct bnode_proc
));
955 opr_queue_Init(&tp
->q
);
957 tp
->comLine
= aexecString
;
958 tp
->coreName
= coreName
; /* may be null */
959 abnode
->procStartTime
= FT_ApproxTime();
960 abnode
->procStarts
++;
962 /* convert linked list of tokens into argv structure */
963 for (tt
= tlist
, i
= 0; i
< (MAXVARGS
- 1) && tt
; tt
= tt
->next
, i
++) {
966 argv
[i
] = NULL
; /* null-terminated */
968 cpid
= spawnprocve(argv
[0], argv
, environ
, -1);
969 osi_audit(BOSSpawnProcEvent
, 0, AUD_STR
, aexecString
, AUD_END
);
971 if (cpid
== (pid_t
) - 1) {
972 bozo_Log("Failed to spawn process for bnode '%s'\n", abnode
->name
);
973 bnode_FreeTokens(tlist
);
977 bozo_Log("%s started pid %ld: %s\n", abnode
->name
, cpid
, aexecString
);
979 bnode_FreeTokens(tlist
);
980 opr_queue_Prepend(&allProcs
, &tp
->q
);
983 tp
->flags
= BPROC_STARTED
;
984 tp
->flags
&= ~BPROC_EXITED
;
985 BOP_PROCSTARTED(abnode
, tp
);
991 bnode_StopProc(struct bnode_proc
*aproc
, int asignal
)
994 if (!(aproc
->flags
& BPROC_STARTED
) || (aproc
->flags
& BPROC_EXITED
))
997 osi_audit(BOSStopProcEvent
, 0, AUD_STR
, (aproc
? aproc
->comLine
: NULL
),
1000 code
= kill(aproc
->pid
, asignal
);
1001 bnode_Check(aproc
->bnode
);