1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23/*	  All Rights Reserved  	*/
24
25/*
26 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 */
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <signal.h>
35#include "misc.h"
36#include "msgs.h"
37#include <sac.h>
38#include "structs.h"
39#include <sys/types.h>
40#include <unistd.h>
41#include "extern.h"
42
43
44/*
45 * read_table - read in SAC's administrative file and build internal
46 *		data structures
47 *
48 *	args:	startflag - flag to indicate if port monitor's should be
49 *			    started as a side effect of reading
50 */
51
52void
53read_table(startflag)
54int startflag;
55{
56	FILE *fp;		/* scratch file pointer */
57	int ret;		/* return code from check_version */
58	struct sactab *sp;	/* working pointer to move through PM info */
59
60# ifdef DEBUG
61	debug("in read_table");
62# endif
63
64/*
65 * make sure _sactab is ok
66 */
67
68	Nentries = 0;
69	if ((ret = check_version(VERSION, SACTAB)) == 1)
70		error(E_BADVER, EXIT);
71	else if (ret == 2)
72		error(E_SACOPEN, EXIT);
73	else if (ret == 3)
74		error(E_BADFILE, EXIT);
75	fp = fopen(SACTAB, "r");
76	if (fp == NULL)
77		error(E_SACOPEN, EXIT);
78
79/*
80 * mark all entries as invalid
81 */
82
83	for (sp = Sactab; sp; sp = sp->sc_next)
84		sp->sc_valid = 0;
85
86/*
87 * build internal structures
88 */
89
90	while (sp = read_entry(fp))
91		insert(sp, startflag);
92	purge();
93	(void) fclose(fp);
94}
95
96
97/*
98 * read_entry - read an entry from _sactab
99 *
100 *	args:	fp - file pointer referencing _sactab
101 */
102
103struct sactab *
104read_entry(fp)
105FILE *fp;
106{
107	register struct sactab *sp;	/* working pointer */
108	register char *p;		/* scratch pointer */
109	char buf[SIZE];			/* scratch buffer */
110
111/*
112 * retrieve a line from the file
113 */
114
115	do {
116		if (fgets(buf, SIZE, fp) == NULL)
117			return(NULL);
118		p = trim(buf);
119	} while (*p == '\0');
120
121/*
122 * allocate a list element for it and then parse the line, parsed
123 * info goes into list element
124 */
125
126	sp = (struct sactab *) calloc(1, sizeof(struct sactab));
127	if (sp == NULL)
128		error(E_MALLOC, EXIT);
129	sp->sc_sstate = sp->sc_lstate = sp->sc_pstate = NOTRUNNING;
130	(void) memset(sp->sc_utid, '\0', IDLEN);
131	parse(p, sp);
132	return(sp);
133}
134
135
136/*
137 * insert - insert a sactab entry into the linked list
138 *
139 *	args:	sp - entry to be inserted
140 *		startflag - flag to indicate if port monitor's should be
141 *			    started as a side effect of reading
142 */
143
144void
145insert(sp, startflag)
146register struct sactab *sp;
147int startflag;
148{
149	register struct sactab *tsp, *savtsp;	/* scratch pointers */
150	int ret;				/* strcmp return value */
151
152# ifdef DEBUG
153	debug("in insert");
154# endif
155	savtsp = tsp = Sactab;
156
157/*
158 * find the correct place to insert this element
159 */
160
161	while (tsp) {
162		ret = strcmp(sp->sc_tag, tsp->sc_tag);
163# ifdef DEBUG
164		(void) sprintf(Scratch, "sp->sc_tag <%s> tsp->sc_tag <%s>, ret is %d", sp->sc_tag, tsp->sc_tag, ret);
165		debug(Scratch);
166# endif
167		if (ret > 0) {
168			/* keep on looking */
169			savtsp = tsp;
170			tsp = tsp->sc_next;
171			continue;
172		}
173		else if (ret == 0) {
174
175/*
176 * found an entry for it in the list, either a duplicate or we're
177 * rereading the file.
178 */
179
180			if (tsp->sc_valid) {
181				/* this is a duplicate entry, ignore it */
182				(void) sprintf(Scratch, "Ignoring duplicate entry for <%s>", tsp->sc_tag);
183				log(Scratch);
184			}
185			else {
186				/* found a valid match, replace flags & restart max only */
187				tsp->sc_rsmax = sp->sc_rsmax;
188				tsp->sc_flags = sp->sc_flags;
189# ifdef DEBUG
190				(void) sprintf(Scratch, "replacing <%s>", sp->sc_tag);
191				debug(Scratch);
192# endif
193				/* this entry is "current" */
194				tsp->sc_valid = 1;
195				Nentries++;
196			}
197			free(sp->sc_cmd);
198			free(sp);
199			return;
200		}
201		else {
202			/* insert it here */
203			if (tsp == Sactab) {
204				sp->sc_next = Sactab;
205				Sactab = sp;
206			}
207			else {
208				sp->sc_next = savtsp->sc_next;
209				savtsp->sc_next = sp;
210			}
211# ifdef DEBUG
212			(void) sprintf(Scratch, "adding <%s>", sp->sc_tag);
213			debug(Scratch);
214# endif
215			Nentries++;
216			/* this entry is "current" */
217			sp->sc_valid = 1;
218			if (startflag && !(sp->sc_flags & X_FLAG))
219				(void) startpm(sp);
220			return;
221		}
222	}
223
224/*
225 * either an empty list or should put element at end of list
226 */
227
228	sp->sc_next = NULL;
229	if (Sactab == NULL)
230		Sactab = sp;
231	else
232		savtsp->sc_next = sp;
233# ifdef DEBUG
234	(void) sprintf(Scratch, "adding <%s>", sp->sc_tag);
235	debug(Scratch);
236# endif
237	++Nentries;
238	/* this entry is "current" */
239	sp->sc_valid = 1;
240	if (startflag && !(sp->sc_flags & X_FLAG))
241		(void) startpm(sp);
242}
243
244
245
246/*
247 * purge - purge linked list of "old" entries
248 */
249
250
251void
252purge()
253{
254	register struct sactab *sp;		/* working pointer */
255	register struct sactab *savesp, *tsp;	/* scratch pointers */
256	sigset_t cset;				/* for signal handling */
257	sigset_t tset;				/* for signal handling */
258
259# ifdef DEBUG
260	debug("in purge");
261# endif
262	/* get current signal mask */
263	(void) sigprocmask(SIG_SETMASK, NULL, &cset);
264	sp = savesp = Sactab;
265	while (sp) {
266		if (sp->sc_valid) {
267			savesp = sp;
268			sp = sp->sc_next;
269			continue;
270		}
271
272		/* element should be removed */
273		switch (sp->sc_sstate) {
274		case UNKNOWN:
275		case ENABLED:
276		case DISABLED:
277		case STARTING:
278			/* need to kill it */
279			tset = cset;
280			(void) sigaddset(&tset, SIGALRM);
281			(void) sigaddset(&tset, SIGCLD);
282			(void) sigprocmask(SIG_SETMASK, &tset, NULL);
283			if (sendsig(sp, SIGTERM))
284				(void) sprintf(Scratch, "could not send SIGTERM to <%s>", sp->sc_tag);
285			else
286				(void) sprintf(Scratch, "terminating <%s>", sp->sc_tag);
287			log(Scratch);
288			(void) sigdelset(&tset, SIGALRM);
289			(void) sigprocmask(SIG_SETMASK, &tset, NULL);
290			/* fall thru */
291		case STOPPING:
292			(void) close(sp->sc_fd);
293			/* fall thru */
294		case NOTRUNNING:
295		case FAILED:
296			cleanutx(sp);
297			tsp = sp;
298			if (tsp == Sactab) {
299				Sactab = sp->sc_next;
300				savesp = Sactab;
301			}
302			else
303				savesp->sc_next = sp->sc_next;
304# ifdef DEBUG
305			(void) sprintf(Scratch, "purging <%s>", sp->sc_tag);
306			debug(Scratch);
307# endif
308			sp = sp->sc_next;
309			free(tsp->sc_cmd);
310			free(tsp->sc_comment);
311			free(tsp);
312
313/*
314 * all done cleaning up, restore signal mask
315 */
316
317			(void) sigprocmask(SIG_SETMASK, &cset, NULL);
318			break;
319		}
320	}
321}
322
323
324/*
325 * dump_table - dump the internal SAC table, used to satisfy sacadm -l
326 */
327
328
329char **
330dump_table()
331{
332	register struct sactab *sp;	/* working pointer */
333	register char *p;		/* scratch pointer */
334	register int size;		/* size of "dumped" table */
335	char **info, **savinfo;		/* scratch pointers */
336
337# ifdef DEBUG
338	(void) sprintf(Scratch, "about to 'info' malloc %d entries", Nentries);
339	debug(Scratch);
340# endif
341
342/*
343 * get space for number of entries we have
344 */
345
346	if (Nentries == 0)
347		return(NULL);
348	if ((info = (char **) malloc(Nentries * sizeof(char *))) == NULL) {
349		error(E_MALLOC, CONT);
350		return(NULL);
351	}
352	savinfo = info;
353
354/*
355 * traverse the list allocating space for entries and formatting them
356 */
357
358	for (sp = Sactab; sp; sp = sp->sc_next) {
359		size = strlen(sp->sc_tag) + strlen(sp->sc_type) + strlen(sp->sc_cmd) + strlen(sp->sc_comment) + SLOP;
360		if ((p = malloc((unsigned) size)) == NULL) {
361			error(E_MALLOC, CONT);
362			return(NULL);
363		}
364		(void) sprintf(p, "%s:%s:%d:%d:%d:%s:%s\n", sp->sc_tag, sp->sc_type,
365			sp->sc_flags, sp->sc_rsmax, sp->sc_pstate, sp->sc_cmd, sp->sc_comment);
366		*info++ = p;
367# ifdef DEBUG
368		debug(*(info - 1));
369# endif
370	}
371	return(savinfo);
372}
373