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/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include	"uucp.h"
34
35#define USAGE	"[-xNUM] [-uNUM]"
36#define MAXGRADE	52
37
38struct m {
39	char	mach[15];
40	char	jgrade[2*MAXGRADE+1];
41} M[UUSTAT_TBL+2];
42
43short Uopt;
44void cleanup(), exuucico();
45
46void logent(){}		/* to load ulockf.c */
47
48int
49main(argc, argv, envp)
50int argc;
51char *argv[];
52char **envp;
53{
54	struct m *m, *machine();
55	DIR *spooldir, *subdir, *gradedir;
56	char f[256], g[256], fg[256], subf[256];
57	int numgrade;
58	char *gradelist, *gradeptr[MAXGRADE+1];
59	short num, snumber;
60	char lckname[MAXFULLNAME];
61	struct limits limitval;
62	int i, maxnumb;
63	FILE *fp;
64
65	Uopt = 0;
66	Env = envp;
67
68	(void) strcpy(Progname, "uusched");
69	while ((i = getopt(argc, argv, "u:x:")) != EOF) {
70		switch(i){
71		case 'x':
72			Debug = atoi(optarg);
73			if (Debug <= 0) {
74				fprintf(stderr,
75				"WARNING: %s: invalid debug level %s ignored, using level 1\n",
76				Progname, optarg);
77				Debug = 1;
78			}
79#ifdef SMALL
80			fprintf(stderr,
81			"WARNING: uusched built with SMALL flag defined -- no debug info available\n");
82#endif /* SMALL */
83			break;
84		case 'u':
85			Uopt = atoi(optarg);
86			if (Uopt <= 0) {
87				fprintf(stderr,
88				"WARNING: %s: invalid debug level %s ignored, using level 1\n",
89				Progname, optarg);
90				Uopt = 1;
91			}
92			break;
93		default:
94			(void) fprintf(stderr, "\tusage: %s %s\n",
95			    Progname, USAGE);
96			cleanup(1);
97		}
98	}
99	if (argc != optind) {
100		(void) fprintf(stderr, "\tusage: %s %s\n", Progname, USAGE);
101		cleanup(1);
102	}
103
104	DEBUG(9, "Progname (%s): STARTED\n", Progname);
105	if (scanlimit("uusched", &limitval) == FAIL) {
106	    DEBUG(1, "No limits for uusched in %s\n", LIMITS);
107	    maxnumb = -1;
108	} else {
109	    maxnumb = limitval.totalmax;
110	    if (maxnumb < 0) {
111		DEBUG(4, "Non-positive limit for uusched in %s\n", LIMITS);
112		DEBUG(1, "No limits for uusched\n%s", "");
113	    } else {
114		DEBUG(4, "Uusched limit %d -- ", maxnumb);
115		i = cuantos(S_LOCKPRE, X_LOCKDIR);
116		if (i >= maxnumb) {
117			DEBUG(4, "found %d -- cleaning up\n", i);
118			cleanup(0);
119		}
120		DEBUG(4, "continuing\n", maxnumb);
121	    }
122	}
123
124	if (chdir(SPOOL) != 0 || (spooldir = opendir(SPOOL)) == NULL)
125		cleanup(101);		/* good old code 101 */
126	while (gdirf(spooldir, f, SPOOL) == TRUE) {
127	    subdir = opendir(f);
128	    ASSERT(subdir != NULL, Ct_OPEN, f, errno);
129	    while (gdirf(subdir, g, f) == TRUE) {
130		(void) sprintf(fg, "%s/%s", f, g);
131		gradedir = opendir(fg);
132		ASSERT(gradedir != NULL, Ct_OPEN, g, errno);
133		while (gnamef(gradedir, subf) == TRUE) {
134		    if (subf[1] == '.') {
135		        if (subf[0] == CMDPRE) {
136			    /* Note - we can break now, since we
137			     * have found a job grade with at least
138			     * one C. file.
139			    */
140			    (void) strncat(machine(f)->jgrade, g, strlen(g));
141			    break;
142			}
143		    }
144		}
145		closedir(gradedir);
146	    }
147	    closedir(subdir);
148	}
149
150	/* Make sure the overflow entry is null since it may be incorrect */
151	M[UUSTAT_TBL].mach[0] = NULLCHAR;
152
153	/* count the number of systems */
154	for (num=0, m=M; m->mach[0] != '\0'; m++, num++) {
155	    DEBUG(5, "machine: %s, ", M[num].mach);
156	    DEBUG(5, "job grade list: %s\n", M[num].jgrade);
157	}
158	DEBUG(5, "Execute num=%d \n", num);
159	while (num > 0) {
160	    /*
161	     * create lock file once we have work to do
162	     * (but only if there is a job limit)
163	     */
164	    if (maxnumb > 0) {
165	    	    for (i = 0; i < maxnumb; i++) {
166			    (void) sprintf(lckname, "%s.%d", S_LOCK, i);
167			    if (mklock(lckname) == SUCCESS)
168			    	    break;
169		    }
170		    if (i == maxnumb) {
171			    DEBUG(4, "found %d -- cleaning up\n", i);
172			    cleanup(0);
173		    }
174	    }
175	    snumber = (time((time_t *) 0) % num);  /* random num */
176	    (void) strcpy(Rmtname, M[snumber].mach);
177	    gradelist = M[snumber].jgrade;
178	    DEBUG(5, "num=%d, ", num);
179	    DEBUG(5, "snumber=%d, ", snumber);
180	    DEBUG(5, "Rmtname=%s, ", Rmtname);
181	    DEBUG(5, "job grade list= %s\n", gradelist);
182
183	    numgrade = getargs(gradelist, gradeptr, MAXGRADE);
184	    for (i=0; i<numgrade; i++) {
185		(void) sprintf(lckname, "%s.%s.%s", LOCKPRE, Rmtname, gradeptr[i]);
186		if (cklock(lckname) != FAIL && callok(Rmtname) == 0) {
187		    /* no lock file and status time ok */
188		    DEBUG(5, "call exuucico(%s)\n", Rmtname);
189		    exuucico(Rmtname);
190		    break;
191		}
192		else {
193		    /* job grade locked - look for the next one */
194		    DEBUG(5, "job grade %s locked or inappropriate status\n",
195			gradeptr[i]);
196		}
197	    }
198
199	    M[snumber] = M[num-1];
200	    num--;
201	}
202	cleanup(0);
203
204	/* NOTREACHED */
205	return (0);
206}
207
208struct m	*
209machine(name)
210char	*name;
211{
212	struct m *m;
213	size_t	namelen;
214
215	namelen = strlen(name);
216	DEBUG(9, "machine(%s) called\n", name);
217	for (m = M; m->mach[0] != '\0'; m++)
218		/* match on overlap? */
219		if (EQUALSN(name, m->mach, MAXBASENAME)) {
220			/* check for job grade */
221			if (m->jgrade[0] != NULLCHAR)
222				(void) strncat(m->jgrade, " ", 1);
223
224			/* use longest name */
225			if (namelen > strlen(m->mach))
226				(void) strcpy(m->mach, name);
227			return(m);
228		}
229
230	/*
231	 * The table is set up with 2 extra entries
232	 * When we go over by one, output error to errors log
233	 * When more than one over, just reuse the previous entry
234	 */
235	if (m-M >= UUSTAT_TBL) {
236	    if (m-M == UUSTAT_TBL) {
237		errent("MACHINE TABLE FULL", "", UUSTAT_TBL,
238		__FILE__, __LINE__);
239	    }
240	    else
241		/* use the last entry - overwrite it */
242		m = &M[UUSTAT_TBL];
243	}
244
245	(void) strcpy(m->mach, name);
246	m->jgrade[0] = NULLCHAR;
247	return(m);
248}
249
250void
251exuucico(name)
252char *name;
253{
254	char cmd[BUFSIZ];
255	int status;
256	pid_t pid, ret;
257	char uopt[5];
258	char sopt[BUFSIZ];
259
260	(void) sprintf(sopt, "-s%s", name);
261	if (Uopt)
262	    (void) sprintf(uopt, "-x%.1d", Uopt);
263
264	if ((pid = vfork()) == 0) {
265	    if (Uopt)
266	        (void) execle(UUCICO, "UUCICO", "-r1", uopt, sopt, (char *) 0, Env);
267	    else
268	        (void) execle(UUCICO, "UUCICO", "-r1", sopt, (char *) 0, Env);
269
270	    cleanup(100);
271	}
272	while ((ret = wait(&status)) != pid)
273	    if (ret == -1 && errno != EINTR)
274		break;
275
276	DEBUG(3, "ret=%ld, ", (ret == pid ? (long) status : (long) ret));
277	return;
278}
279
280
281void
282cleanup(code)
283int	code;
284{
285	rmlock(CNULL);
286	exit(code);
287}
288