xref: /illumos-gate/usr/src/cmd/bnu/grades.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 (c) 2000 by Sun Microsystems, Inc.
27  * All rights reserved.
28  */
29 
30 #ident	"%Z%%M%	%I%	%E% SMI"	/* from SVR4 bnu:grades.c 1.7 */
31 
32 #include "uucp.h"
33 #include <grp.h>
34 
35 #define G_EXT	0
36 #define	G_INT	1
37 #define	G_RES	2
38 #define	G_ACT	3
39 #define	G_IDF	4
40 #define	G_MAX	512	/* max number of fields in the Grades file line */
41 #define	SMBUF	128
42 
43 #define	TYPE	0
44 #define FILE1	1
45 #define	FILE2	2
46 #define	USER	3
47 #define	OPTS	4
48 #define	FILE3	5
49 
50 extern int rdfulline(), jsize(), gdirf(), gnamef();
51 extern void wfcommit();
52 
53 static void	mailAdmin();		/* Send mail to administrator. */
54 
55 /*
56  * chkgrp - checks to see the group has permission
57  *		to use a service grade queue.
58  *
59  * returns
60  *
61  *	SUCCESS - if the group has permissions
62  *	FAIL - if group does not
63  *
64  */
65 
66 static int
67 chkgrp(carray,na)
68 char **carray;
69 int na;
70 {
71 	struct group *grp;
72 	int i;
73 	gid_t gid;
74 
75 	gid = getgid();
76 	grp = getgrgid(gid);
77 
78 	for (i = G_IDF; i < na; i++)
79 			if (EQUALS(carray[i], grp->gr_name))
80 				return(SUCCESS);
81 
82 	return(FAIL);
83 }
84 
85 /*
86  * chkusr - checks the permission fields of the Grades file
87  *	    to determine if the user can queue to a particular service grade.
88  *
89  * returns
90  *
91  *	SUCCESS - if the user can queue to the service grade.
92  *	FAIL - if the user can not queue to this service grade.
93  *
94  */
95 
96 static int
97 chkusr(carray, na)
98 char **carray;
99 int na;
100 {
101 	int i;
102 
103 	/*
104 	 * start at the point where the users are supposed to be in the
105 	 * Grades file. Loop thru until the end of the user list is
106 	 * found or the user name is found. If the user name is found then
107 	 * return TRUE. If the end of the list is found, return FAIL.
108 	 */
109 
110 	DEBUG(9, "User (%s)\n", User);
111 
112 	/* check for any user and return if so */
113 
114 	if (EQUALS(carray[G_IDF], "Any"))
115 		return(SUCCESS);
116 
117 	DEBUG(9, "Members of administrator defined service grade (%s)\n", carray[G_EXT]);
118 
119 	for (i = G_IDF; i < na; i++) {
120 		DEBUG(9, "%s\n", carray[i]);
121 		if (EQUALS(User, carray[i]))
122 			return(SUCCESS);
123 	}
124 
125 	return(FAIL);
126 }
127 
128 /*
129  *	fgrade - finds the appropiate queue to queue a job into
130  *
131  *	returns
132  *		SUCCESS	-> found a queue
133  *		FAIL	-> can't find a queue
134  */
135 
136 int
137 fgrade(scfile)
138 struct cs_struct *scfile;
139 {
140 	char fdgrade();
141 	FILE *cfd;
142 	char line[BUFSIZ];
143 	char *carray[G_MAX];
144 	long climit;
145 
146 	/* Check for the default service grade first */
147 
148 	if (strcmp(scfile->sgrade, "default") == 0) {
149 		scfile->grade = fdgrade();
150 		return(SUCCESS);
151 	}
152 
153 	/* open grades file to begin a linear for the grade requested */
154 
155 	cfd = fopen(GRADES, "r");
156 
157 	/* loop until the file is empty or we find the grade we want */
158 
159 	while (rdfulline(cfd, line, BUFSIZ) != 0) {
160 		(void) getargs(line, carray, G_MAX);
161 
162 		/* check to see if this is the grade we want */
163 
164 		if (!EQUALS(scfile->sgrade, carray[G_EXT]))
165 			continue;
166 
167 		if (jsize(scfile, carray[G_RES], &climit) != FAIL) {
168 			(void) fclose(cfd);
169 			scfile->grade = *carray[G_INT];
170 			return(SUCCESS);
171 		}
172 	}
173 
174 	(void) fclose(cfd);
175 
176 	(void) fprintf(stderr, gettext("Job size (%ld bytes)"
177 	    " exceeds maximum number of bytes (%ld bytes)"
178 	    " allowed into this service grade (%s).\n"
179 	    "Job queued to default grade.\n"),
180 	    scfile->jsize, climit, scfile->sgrade);
181 
182 	scfile->grade = fdgrade();
183 	return(SUCCESS);
184 }
185 
186 /*
187  *	fdgrade - finds the default queue for this system
188  *
189  *	returns
190  *		a one char name for the default queue
191  *
192  */
193 
194 char
195 fdgrade()
196 {
197 	FILE *cfd;
198 	char line[BUFSIZ];
199 	char *carray[G_MAX];
200 
201 	/* Check for the default grade first */
202 
203 		cfd = fopen(GRADES, "r");
204 
205 		/* loop until the end of the file is read */
206 
207 		for (; rdfulline(cfd, line, BUFSIZ) != 0;) {
208 
209 			/* parse the fields of this line */
210 
211 			(void) getargs(line, carray, G_MAX);
212 
213 			/* check to see if the administrator has defined
214 			 * a default grade for the machine.
215 			 */
216 
217 			if (strcmp(carray[G_EXT], "default") != 0)
218 				continue;
219 
220 			/* default must be defined in the file
221 			 *  close the file, get the queue name, and return.
222 			 */
223 
224 			(void) fclose(cfd);
225 			return(*carray[G_INT]);
226 		}
227 
228 		/* no default defined in this file. close file.
229 		 * get our default queue and return.
230 		 */
231 
232 		(void) fclose(cfd);
233 		return(D_QUEUE);
234 }
235 
236 /*
237  * job_size - determines the size of a job
238  *
239  * returns
240  *
241  *	SUCCESS - if the size of the job can be determined
242  *	FAIL	- otherwise
243  */
244 
245 int
246 job_size(scfile)
247 struct cs_struct *scfile;
248 {
249 	extern int Dfileused;
250 	struct stat s;
251 	FILE *fp;
252 	char line[BUFSIZ];
253 	char *carray[G_MAX];
254 	int na;
255 	int nodfile = FALSE;
256 	int ret;
257 
258 	scfile->jsize = 0;
259 
260 	fp = fopen(scfile->file, "r");
261 
262 	if (fp == NULL) {
263 		toCorrupt(scfile->file);
264 		errent(Ct_OPEN, scfile->file, errno, __FILE__,  __LINE__);
265 	}
266 
267 	while (fgets(line, BUFSIZ, fp) != NULL) {
268 		na = getargs(line, carray, G_MAX);
269 
270 		if (na < 6) {
271 			(void) fclose(fp);
272 			toCorrupt(scfile->file);
273 			errent("BAD NUMBER OF ARGUMENTS", scfile->file, 0,
274 				__FILE__, __LINE__);
275 		}
276 
277 		/* if the type of a transfer is not a push
278 		 * then don't try to determine the size of
279 		 * the data file, because you can't.
280 		 */
281 
282 		if (*carray[TYPE] == 'R')
283 			continue;
284 
285 		/* find the data dile that is to be transferred */
286 
287 		if ((ret = stat(carray[FILE3], &s)) != 0) {
288 			if (errno == ENOENT) {
289 				nodfile = TRUE;
290 				ret = stat(carray[FILE1], &s);
291 			}
292 		}
293 		else
294 			Dfileused = TRUE;
295 
296 		/*
297 		 * check to see if the return code from stat was 0
298 		 * if return code was not 0, write message to error
299 		 * log and quit. Otherwise, add size of file to job
300 		 * size and continue looping.
301 		 */
302 
303 		if (ret != 0) {
304 			(void) fclose(fp);
305 			errent(Ct_STAT, nodfile ?
306 				carray[FILE1] : carray[FILE3], errno,
307 				__FILE__, __LINE__);
308 		}
309 
310 		nodfile = FALSE;
311 		scfile->jsize += s.st_size;
312 	}
313 	(void) fclose(fp);
314 	return(SUCCESS);
315 }
316 
317 /*
318  * jsize - determines whether if a job is small enough to
319  * 	   be placed in the appropiate queue.
320  *
321  * returns
322  *
323  *	SUCCESS - if the size of the job is less than or
324  *		  equal to the number of bytes in the restriction
325  *		  of the GRADES file.
326  *
327  *	FAIL	- otherwise
328  */
329 
330 int
331 jsize(scfile, climit, nlimit)
332 struct cs_struct *scfile;
333 char *climit;
334 long *nlimit;
335 {
336 #define ONE_K (1024)
337 #define ONE_MEG ((1024)*(1024))
338 
339 	static void lcase();
340 	char rest[SMBUF];
341 	char msg[BUFSIZ], *p;
342 
343 	if (EQUALS(climit, "Any"))
344 		return(SUCCESS);
345 
346 	lcase(climit, rest, SMBUF);
347 
348 	if (!(p = strchr(rest, 'k')) && (!(p = strchr(rest, 'm')))) {
349 
350 		for(p = climit; *p; ++p) {
351 			if (isdigit(*p))
352 				continue;
353 
354 			/* corrupt restriction field in the Grades file.
355 			 * report it to the uucp administrator.
356 			 */
357 
358 			snprintf(msg, sizeof (msg),
359 			    gettext("Error encountered in the"
360 			    " restrictions field of the Grades file."
361 			    "  Field contents (%s)."), climit);
362 			mailAdmin(msg);
363 			return(SUCCESS);
364 		}
365 
366 		*nlimit = atol(climit);
367 	}
368 	else if (*p == 'k') {
369 		*p = '\0';
370 		*nlimit = (long) (atof(rest) * ONE_K);
371 	}
372 	else {
373 		*p = '\0';
374 		*nlimit = (long) (atof(rest) * ONE_MEG);
375 	}
376 
377 	if (scfile->jsize <= *nlimit)
378 		return(SUCCESS);
379 	else
380 		return(FAIL);
381 }
382 
383 static void
384 lcase(s, t, lim)
385 char s[], t[];
386 int lim;
387 {
388 	char *p;
389 	int i;
390 
391 
392 	p = s;
393 
394 	for (i = 0; i < lim-1 && *p; i++)
395 		if (isupper(*p))
396 			t[i] = tolower(*p++);
397 		else
398 			t[i] = *p++;
399 
400 	t[i] = '\0';
401 	return;
402 }
403 
404 /*
405  * mailAdmin - mail a message to the uucp administrator.
406  *
407  * returns:
408  *
409  *	nothing
410  */
411 
412 static void
413 mailAdmin (msg)
414 
415 char *	msg;
416 
417 {
418 	char	cmd[BUFSIZ];		/* Place to build mail command. */
419 	FILE *	mail;			/* Channel to write mail on. */
420 
421 	(void) sprintf(cmd, "%s %s %s", PATH, MAIL, "uucp");
422 	if ((mail = popen(cmd, "w")) != (FILE *) NULL)
423 	{
424 		(void) fprintf(mail, "To: uucp\nSubject: %s\n\n%s\n",
425 		    gettext("Grades file problem"), msg);
426 		(void) pclose(mail);
427 	}
428 
429 	/*
430 	 * Ignore popen failure.  There is not much that we can do if
431 	 * it fails, since we are already trying to notify the administrator
432 	 * of a problem.
433 	 */
434 	return;
435 }
436 
437 /*
438  * putdfiles - moves any and all of the D. to the spool directory for
439  * 	       a C. file.
440  *
441  * returns
442  *
443  *	nothing
444  */
445 
446 void
447 putdfiles(scfile)
448 struct cs_struct scfile;
449 {
450 	FILE *fp;
451 	char line[BUFSIZ];
452 	char *carray[G_MAX];
453 	int na;
454 	struct stat s;
455 
456 	fp = fopen(scfile.file, "r");
457 
458 	if (fp == NULL) {
459 		toCorrupt(scfile.file);
460 		errent(Ct_OPEN, scfile.file, errno, __FILE__, __LINE__);
461 	}
462 
463 	while (fgets(line, BUFSIZ, fp) != NULL) {
464 
465 		na = getargs(line, carray, G_MAX);
466 		if (na < 6) {
467 			(void) fclose(fp);
468 			toCorrupt(scfile.file);
469 			errent("BAD NUMBER OF ARGUMENTS", scfile.file, 0,
470 				__FILE__, __LINE__);
471 		}
472 
473 		if (*carray[TYPE] == 'R')
474 			continue;
475 
476 	    	/* move D. file to the spool area */
477 
478 		if (stat(carray[FILE3], &s) != -1)
479 			wfcommit(carray[FILE3], carray[FILE3], scfile.sys);
480 	}
481 
482 	(void) fclose(fp);
483 	return;
484 }
485 
486 /*
487  * reads a line from a file and takes care of comment lines
488  * and continuations (\) in last column.
489  *
490  * return:
491  *	the number of chars that are placed in line.
492  */
493 
494 int
495 rdfulline(fd, line, lim)
496 FILE *fd;
497 char *line;
498 int lim;
499 {
500 	register char *p, *c;
501 	char buf[BUFSIZ];
502 	size_t blr, btox;
503 
504 	p = line;
505 	for (;fgets(buf, BUFSIZ, fd) != NULL;) {
506 		/* check to see if it is a comment */
507 
508 		if (buf[0] == '#')
509 			continue;
510 
511 		/* remove trailing white space */
512 		c = &buf[strlen(buf)-1];
513 		while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') )
514 			*c-- = NULLCHAR;
515 
516 		if (buf[0] == '\n' || buf[0] == NULLCHAR)
517 			continue;
518 
519 		blr = lim - 1 - (p - line);
520 		btox = blr < strlen(buf) ? blr : strlen(buf);
521 
522 		if (btox <= 0)
523 			break;
524 
525 		(void) strncpy(p, buf, btox);
526 		p += btox - 1;
527 
528 		if ( *(p-1) == '\\')
529 			p--;
530 		else
531 			break;
532 	}
533 
534 	*++p = '\0';
535 	return(p-line-1);
536 }
537 
538 /*	upermit - checks to determine if the user has permissions
539  *	to use administrator defined service grade.
540  *
541  *	returns
542  *		SUCCESS -> if the user can queue to this service grade.
543  *		FAIL -> if the user cannot queue to this service grade.
544  */
545 
546 int
547 upermit(carray, na)
548 char **carray;
549 int na;
550 {
551 #define G_USR "user"
552 #define G_NUSR "non-user"
553 #define G_GRP "group"
554 #define G_NGRP "non-group"
555 
556 	static void lcase();
557 	char actn[SMBUF];
558 	char ufld[SMBUF];
559 	char msg[BUFSIZ];
560 
561 	(void) strcpy(actn, carray[G_ACT]);
562 
563 	lcase(actn, ufld, SMBUF);
564 
565 	if (EQUALS(ufld, G_USR))
566 		return(chkusr(carray,na));
567 
568 	if (EQUALS(ufld, G_NUSR))
569 		return((chkusr(carray, na) != SUCCESS) ? SUCCESS : FAIL);
570 
571 	if (EQUALS(ufld, G_GRP))
572 		return(chkgrp(carray, na));
573 
574 	if (EQUALS(ufld, G_NGRP))
575 		return((chkgrp(carray, na) != SUCCESS) ? SUCCESS : FAIL);
576 
577 	(void) snprintf(msg, sizeof (msg),
578 	    gettext("Error encountered in action field of"
579 	    " the Grades file. Field contents (%s)."), carray[G_ACT]);
580 	mailAdmin(msg);
581 	return(FAIL);
582 }
583 
584 /*
585  *	vergrd - verify if the grade name is a valid administrator
586  *		 defined service grade name and if the user has the
587  *		 appropiate permission to use this grade.
588  *
589  *	returns
590  *		SUCCESS	-> grade is valid and user is
591  *			   permitted to use this grade.
592  *		FAIL	-> otherwise
593  *
594  */
595 
596 int
597 vergrd(grade)
598 char *grade;
599 {
600 	FILE *cfd;
601 	char line[BUFSIZ];
602 	char *carray[G_MAX];
603 	int na;
604 
605 	/* Check for the default grade first */
606 
607 	if (EQUALS(grade, "default"))
608 		return(SUCCESS);
609 
610 	/* open grades file to begin a linear for the grade requested */
611 
612 	cfd = fopen(GRADES, "r");
613 
614 	/* loop until the file is empty or we find the grade we want */
615 
616 	while (rdfulline(cfd, line, BUFSIZ) != 0) {
617 		na = getargs(line, carray, G_MAX);
618 
619 		/* check to see if this is the grade we want */
620 
621 		if (!EQUALS(grade, carray[G_EXT]))
622 			continue;
623 
624 		/* check for the permission on this grade */
625 
626 		if (upermit(carray, na) != FAIL) {
627 			(void) fclose(cfd);
628 			return(SUCCESS);
629 		}
630 		else {
631 			(void) fclose(cfd);
632 			(void) fprintf(stderr, gettext("User does not have"
633 			    " permission to use this service grade (%s).\n"
634 			    "Job has not been queued.\n"
635 			    "Use (uuglist) to find which service grades"
636 			    " you can queue to.\n"), grade);
637 			return(FAIL);
638 		}
639 	}
640 
641 	(void) fclose(cfd);
642 
643 	(void) fprintf(stderr, gettext(
644 	    "Service grade (%s) does not exist on this machine."
645 	    "  Job not queued.\n"
646 	    "Use (uuglist) to find which service grades are available on"
647 	    " this machine.\n"), grade);
648 	return(FAIL);
649 }
650 
651 /*
652  * wfremove - removes a C. file from the Workspace directory and all of its
653  * D. files.
654  */
655 
656 void
657 wfremove(file)
658 char *file;
659 {
660 	FILE *fp;
661 	char line[BUFSIZ];
662 	char *carray[G_MAX];
663 	int na;
664 	struct stat s;
665 
666 	fp = fopen(file, "r");
667 
668 	if (fp == NULL) {
669 		toCorrupt(file);
670 		errent(Ct_OPEN, file, errno, __FILE__, __LINE__);
671 	}
672 
673 	while (fgets(line, BUFSIZ, fp) != NULL) {
674 		na = getargs(line, carray, G_MAX);
675 
676 		if (na < 6) {
677 			(void) fclose(fp);
678 			toCorrupt(file);
679 			errent("BAD NUMBER OF ARGUMENTS", file, 0,
680 				__FILE__, __LINE__);
681 		}
682 
683 		if (*carray[TYPE] == 'R')
684 			continue;
685 
686 	    	/* remove D. file */
687 
688 	    	DEBUG(4, "Removing data file (%s)\n", carray[FILE3]);
689 
690 		if ((stat(carray[FILE3], &s) != -1) && (unlink(carray[FILE3]) != 0)) {
691 			(void) fclose(fp);
692 			toCorrupt(file);
693 			toCorrupt(carray[FILE3]);
694 			errent(Ct_UNLINK, carray[FILE3], errno, __FILE__,
695 				__LINE__);
696 		}
697 	}
698 
699 	(void) fclose(fp);
700 
701 	DEBUG(4, "Removing work file (%s)\n", file);
702 
703 	if (unlink(file) != 0) {
704 		toCorrupt(file);
705 		errent(Ct_UNLINK, file, errno, __FILE__, __LINE__);
706 	}
707 	return;
708 }
709 
710 /*
711  * findgrade - finds the highest priority job grade that is not locked
712  * and that has jobs.
713  *
714  * job grade name is null, if no job grade is found.
715  */
716 
717 void
718 findgrade(dir, jobgrade)
719 char *dir, *jobgrade;
720 {
721 	char prevgrade[MAXBASENAME+1], curgrade[MAXBASENAME+1],
722 	     gradedir[MAXBASENAME+1];
723 	char lockname[MAXFULLNAME];
724 	char Cfile[MAXBASENAME+1];
725 	DIR *p, *q;
726 
727 	*prevgrade = NULLCHAR;
728 	p = opendir(dir);
729 	ASSERT(p != NULL, Ct_OPEN, dir, errno);
730 
731 	while (gdirf(p, gradedir, dir) == TRUE) {
732 		(void) sprintf(lockname, "%s.%.*s.%s", LOCKPRE, SYSNSIZE,
733 		    Rmtname, gradedir);
734 		if (cklock(lockname) == FAIL)
735 			continue;
736 		q = opendir(gradedir);
737 		ASSERT(q != NULL, Ct_OPEN, gradedir, errno);
738 		while (gnamef(q, Cfile) == TRUE) {
739 			if (Cfile[0] == CMDPRE) {
740 				if (*prevgrade == NULLCHAR) {
741 					(void) strcpy(prevgrade, gradedir);
742 					break;
743 				}
744 				(void) strcpy(curgrade, gradedir);
745 				if (strcmp(curgrade, prevgrade) < 0)
746 					(void) strcpy(prevgrade, curgrade);
747 			}
748 		}
749 		closedir(q);
750 	}
751 	closedir(p);
752 	(void) strncpy(jobgrade, prevgrade, MAXBASENAME);
753 	jobgrade[MAXBASENAME] = NULLCHAR;
754 	return;
755 }
756