/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "uucp.h" #include #define G_EXT 0 #define G_INT 1 #define G_RES 2 #define G_ACT 3 #define G_IDF 4 #define G_MAX 512 /* max number of fields in the Grades file line */ #define SMBUF 128 #define TYPE 0 #define FILE1 1 #define FILE2 2 #define USER 3 #define OPTS 4 #define FILE3 5 extern int rdfulline(), jsize(), gdirf(), gnamef(); extern void wfcommit(); static void mailAdmin(); /* Send mail to administrator. */ /* * chkgrp - checks to see the group has permission * to use a service grade queue. * * returns * * SUCCESS - if the group has permissions * FAIL - if group does not * */ static int chkgrp(carray,na) char **carray; int na; { struct group *grp; int i; gid_t gid; gid = getgid(); grp = getgrgid(gid); for (i = G_IDF; i < na; i++) if (EQUALS(carray[i], grp->gr_name)) return(SUCCESS); return(FAIL); } /* * chkusr - checks the permission fields of the Grades file * to determine if the user can queue to a particular service grade. * * returns * * SUCCESS - if the user can queue to the service grade. * FAIL - if the user can not queue to this service grade. * */ static int chkusr(carray, na) char **carray; int na; { int i; /* * start at the point where the users are supposed to be in the * Grades file. Loop thru until the end of the user list is * found or the user name is found. If the user name is found then * return TRUE. If the end of the list is found, return FAIL. */ DEBUG(9, "User (%s)\n", User); /* check for any user and return if so */ if (EQUALS(carray[G_IDF], "Any")) return(SUCCESS); DEBUG(9, "Members of administrator defined service grade (%s)\n", carray[G_EXT]); for (i = G_IDF; i < na; i++) { DEBUG(9, "%s\n", carray[i]); if (EQUALS(User, carray[i])) return(SUCCESS); } return(FAIL); } /* * fgrade - finds the appropiate queue to queue a job into * * returns * SUCCESS -> found a queue * FAIL -> can't find a queue */ int fgrade(scfile) struct cs_struct *scfile; { char fdgrade(); FILE *cfd; char line[BUFSIZ]; char *carray[G_MAX]; long climit; /* Check for the default service grade first */ if (strcmp(scfile->sgrade, "default") == 0) { scfile->grade = fdgrade(); return(SUCCESS); } /* open grades file to begin a linear for the grade requested */ cfd = fopen(GRADES, "r"); /* loop until the file is empty or we find the grade we want */ while (rdfulline(cfd, line, BUFSIZ) != 0) { (void) getargs(line, carray, G_MAX); /* check to see if this is the grade we want */ if (!EQUALS(scfile->sgrade, carray[G_EXT])) continue; if (jsize(scfile, carray[G_RES], &climit) != FAIL) { (void) fclose(cfd); scfile->grade = *carray[G_INT]; return(SUCCESS); } } (void) fclose(cfd); (void) fprintf(stderr, gettext("Job size (%ld bytes)" " exceeds maximum number of bytes (%ld bytes)" " allowed into this service grade (%s).\n" "Job queued to default grade.\n"), scfile->jsize, climit, scfile->sgrade); scfile->grade = fdgrade(); return(SUCCESS); } /* * fdgrade - finds the default queue for this system * * returns * a one char name for the default queue * */ char fdgrade() { FILE *cfd; char line[BUFSIZ]; char *carray[G_MAX]; /* Check for the default grade first */ cfd = fopen(GRADES, "r"); /* loop until the end of the file is read */ for (; rdfulline(cfd, line, BUFSIZ) != 0;) { /* parse the fields of this line */ (void) getargs(line, carray, G_MAX); /* check to see if the administrator has defined * a default grade for the machine. */ if (strcmp(carray[G_EXT], "default") != 0) continue; /* default must be defined in the file * close the file, get the queue name, and return. */ (void) fclose(cfd); return(*carray[G_INT]); } /* no default defined in this file. close file. * get our default queue and return. */ (void) fclose(cfd); return(D_QUEUE); } /* * job_size - determines the size of a job * * returns * * SUCCESS - if the size of the job can be determined * FAIL - otherwise */ int job_size(scfile) struct cs_struct *scfile; { extern int Dfileused; struct stat s; FILE *fp; char line[BUFSIZ]; char *carray[G_MAX]; int na; int nodfile = FALSE; int ret; scfile->jsize = 0; fp = fopen(scfile->file, "r"); if (fp == NULL) { toCorrupt(scfile->file); errent(Ct_OPEN, scfile->file, errno, __FILE__, __LINE__); } while (fgets(line, BUFSIZ, fp) != NULL) { na = getargs(line, carray, G_MAX); if (na < 6) { (void) fclose(fp); toCorrupt(scfile->file); errent("BAD NUMBER OF ARGUMENTS", scfile->file, 0, __FILE__, __LINE__); } /* if the type of a transfer is not a push * then don't try to determine the size of * the data file, because you can't. */ if (*carray[TYPE] == 'R') continue; /* find the data dile that is to be transferred */ if ((ret = stat(carray[FILE3], &s)) != 0) { if (errno == ENOENT) { nodfile = TRUE; ret = stat(carray[FILE1], &s); } } else Dfileused = TRUE; /* * check to see if the return code from stat was 0 * if return code was not 0, write message to error * log and quit. Otherwise, add size of file to job * size and continue looping. */ if (ret != 0) { (void) fclose(fp); errent(Ct_STAT, nodfile ? carray[FILE1] : carray[FILE3], errno, __FILE__, __LINE__); } nodfile = FALSE; scfile->jsize += s.st_size; } (void) fclose(fp); return(SUCCESS); } static void lcase(); /* * jsize - determines whether if a job is small enough to * be placed in the appropiate queue. * * returns * * SUCCESS - if the size of the job is less than or * equal to the number of bytes in the restriction * of the GRADES file. * * FAIL - otherwise */ int jsize(scfile, climit, nlimit) struct cs_struct *scfile; char *climit; long *nlimit; { #define ONE_K (1024) #define ONE_MEG ((1024)*(1024)) char rest[SMBUF]; char msg[BUFSIZ], *p; if (EQUALS(climit, "Any")) return(SUCCESS); lcase(climit, rest, SMBUF); if (!(p = strchr(rest, 'k')) && (!(p = strchr(rest, 'm')))) { for(p = climit; *p; ++p) { if (isdigit(*p)) continue; /* corrupt restriction field in the Grades file. * report it to the uucp administrator. */ snprintf(msg, sizeof (msg), gettext("Error encountered in the" " restrictions field of the Grades file." " Field contents (%s)."), climit); mailAdmin(msg); return(SUCCESS); } *nlimit = atol(climit); } else if (*p == 'k') { *p = '\0'; *nlimit = (long) (atof(rest) * ONE_K); } else { *p = '\0'; *nlimit = (long) (atof(rest) * ONE_MEG); } if (scfile->jsize <= *nlimit) return(SUCCESS); else return(FAIL); } static void lcase(s, t, lim) char s[], t[]; int lim; { char *p; int i; p = s; for (i = 0; i < lim-1 && *p; i++) if (isupper(*p)) t[i] = tolower(*p++); else t[i] = *p++; t[i] = '\0'; return; } /* * mailAdmin - mail a message to the uucp administrator. * * returns: * * nothing */ static void mailAdmin (msg) char * msg; { char cmd[BUFSIZ]; /* Place to build mail command. */ FILE * mail; /* Channel to write mail on. */ (void) sprintf(cmd, "%s %s %s", PATH, MAIL, "uucp"); if ((mail = popen(cmd, "w")) != (FILE *) NULL) { (void) fprintf(mail, "To: uucp\nSubject: %s\n\n%s\n", gettext("Grades file problem"), msg); (void) pclose(mail); } /* * Ignore popen failure. There is not much that we can do if * it fails, since we are already trying to notify the administrator * of a problem. */ return; } /* * putdfiles - moves any and all of the D. to the spool directory for * a C. file. * * returns * * nothing */ void putdfiles(scfile) struct cs_struct scfile; { FILE *fp; char line[BUFSIZ]; char *carray[G_MAX]; int na; struct stat s; fp = fopen(scfile.file, "r"); if (fp == NULL) { toCorrupt(scfile.file); errent(Ct_OPEN, scfile.file, errno, __FILE__, __LINE__); } while (fgets(line, BUFSIZ, fp) != NULL) { na = getargs(line, carray, G_MAX); if (na < 6) { (void) fclose(fp); toCorrupt(scfile.file); errent("BAD NUMBER OF ARGUMENTS", scfile.file, 0, __FILE__, __LINE__); } if (*carray[TYPE] == 'R') continue; /* move D. file to the spool area */ if (stat(carray[FILE3], &s) != -1) wfcommit(carray[FILE3], carray[FILE3], scfile.sys); } (void) fclose(fp); return; } /* * reads a line from a file and takes care of comment lines * and continuations (\) in last column. * * return: * the number of chars that are placed in line. */ int rdfulline(fd, line, lim) FILE *fd; char *line; int lim; { register char *p, *c; char buf[BUFSIZ]; size_t blr, btox; p = line; for (;fgets(buf, BUFSIZ, fd) != NULL;) { /* check to see if it is a comment */ if (buf[0] == '#') continue; /* remove trailing white space */ c = &buf[strlen(buf)-1]; while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') ) *c-- = NULLCHAR; if (buf[0] == '\n' || buf[0] == NULLCHAR) continue; blr = lim - 1 - (p - line); btox = blr < strlen(buf) ? blr : strlen(buf); if (btox <= 0) break; (void) strncpy(p, buf, btox); p += btox - 1; if ( *(p-1) == '\\') p--; else break; } *++p = '\0'; return(p-line-1); } /* upermit - checks to determine if the user has permissions * to use administrator defined service grade. * * returns * SUCCESS -> if the user can queue to this service grade. * FAIL -> if the user cannot queue to this service grade. */ int upermit(carray, na) char **carray; int na; { #define G_USR "user" #define G_NUSR "non-user" #define G_GRP "group" #define G_NGRP "non-group" char actn[SMBUF]; char ufld[SMBUF]; char msg[BUFSIZ]; (void) strcpy(actn, carray[G_ACT]); lcase(actn, ufld, SMBUF); if (EQUALS(ufld, G_USR)) return(chkusr(carray,na)); if (EQUALS(ufld, G_NUSR)) return((chkusr(carray, na) != SUCCESS) ? SUCCESS : FAIL); if (EQUALS(ufld, G_GRP)) return(chkgrp(carray, na)); if (EQUALS(ufld, G_NGRP)) return((chkgrp(carray, na) != SUCCESS) ? SUCCESS : FAIL); (void) snprintf(msg, sizeof (msg), gettext("Error encountered in action field of" " the Grades file. Field contents (%s)."), carray[G_ACT]); mailAdmin(msg); return(FAIL); } /* * vergrd - verify if the grade name is a valid administrator * defined service grade name and if the user has the * appropiate permission to use this grade. * * returns * SUCCESS -> grade is valid and user is * permitted to use this grade. * FAIL -> otherwise * */ int vergrd(grade) char *grade; { FILE *cfd; char line[BUFSIZ]; char *carray[G_MAX]; int na; /* Check for the default grade first */ if (EQUALS(grade, "default")) return(SUCCESS); /* open grades file to begin a linear for the grade requested */ cfd = fopen(GRADES, "r"); /* loop until the file is empty or we find the grade we want */ while (rdfulline(cfd, line, BUFSIZ) != 0) { na = getargs(line, carray, G_MAX); /* check to see if this is the grade we want */ if (!EQUALS(grade, carray[G_EXT])) continue; /* check for the permission on this grade */ if (upermit(carray, na) != FAIL) { (void) fclose(cfd); return(SUCCESS); } else { (void) fclose(cfd); (void) fprintf(stderr, gettext("User does not have" " permission to use this service grade (%s).\n" "Job has not been queued.\n" "Use (uuglist) to find which service grades" " you can queue to.\n"), grade); return(FAIL); } } (void) fclose(cfd); (void) fprintf(stderr, gettext( "Service grade (%s) does not exist on this machine." " Job not queued.\n" "Use (uuglist) to find which service grades are available on" " this machine.\n"), grade); return(FAIL); } /* * wfremove - removes a C. file from the Workspace directory and all of its * D. files. */ void wfremove(file) char *file; { FILE *fp; char line[BUFSIZ]; char *carray[G_MAX]; int na; struct stat s; fp = fopen(file, "r"); if (fp == NULL) { toCorrupt(file); errent(Ct_OPEN, file, errno, __FILE__, __LINE__); } while (fgets(line, BUFSIZ, fp) != NULL) { na = getargs(line, carray, G_MAX); if (na < 6) { (void) fclose(fp); toCorrupt(file); errent("BAD NUMBER OF ARGUMENTS", file, 0, __FILE__, __LINE__); } if (*carray[TYPE] == 'R') continue; /* remove D. file */ DEBUG(4, "Removing data file (%s)\n", carray[FILE3]); if ((stat(carray[FILE3], &s) != -1) && (unlink(carray[FILE3]) != 0)) { (void) fclose(fp); toCorrupt(file); toCorrupt(carray[FILE3]); errent(Ct_UNLINK, carray[FILE3], errno, __FILE__, __LINE__); } } (void) fclose(fp); DEBUG(4, "Removing work file (%s)\n", file); if (unlink(file) != 0) { toCorrupt(file); errent(Ct_UNLINK, file, errno, __FILE__, __LINE__); } return; } /* * findgrade - finds the highest priority job grade that is not locked * and that has jobs. * * job grade name is null, if no job grade is found. */ void findgrade(dir, jobgrade) char *dir, *jobgrade; { char prevgrade[MAXBASENAME+1], curgrade[MAXBASENAME+1], gradedir[MAXBASENAME+1]; char lockname[MAXFULLNAME]; char Cfile[MAXBASENAME+1]; DIR *p, *q; *prevgrade = NULLCHAR; p = opendir(dir); ASSERT(p != NULL, Ct_OPEN, dir, errno); while (gdirf(p, gradedir, dir) == TRUE) { (void) sprintf(lockname, "%s.%.*s.%s", LOCKPRE, SYSNSIZE, Rmtname, gradedir); if (cklock(lockname) == FAIL) continue; q = opendir(gradedir); ASSERT(q != NULL, Ct_OPEN, gradedir, errno); while (gnamef(q, Cfile) == TRUE) { if (Cfile[0] == CMDPRE) { if (*prevgrade == NULLCHAR) { (void) strcpy(prevgrade, gradedir); break; } (void) strcpy(curgrade, gradedir); if (strcmp(curgrade, prevgrade) < 0) (void) strcpy(prevgrade, curgrade); } } closedir(q); } closedir(p); (void) strncpy(jobgrade, prevgrade, MAXBASENAME); jobgrade[MAXBASENAME] = NULLCHAR; return; }