|
|
1.1 root 1: /* D.L.Buck and Associates, Inc. - 8/27/84
2: *
3: * COPYRIGHT NOTICE:
4: * Copyright c 8/27/84 - An unpublished work by
5: * D.L.Buck and Associates, Inc.
6: *
7: * PROPRIETARY RIGHTS NOTICE:
8: * All rights reserved. This document and program contains
9: * proprietary information of D.L.Buck and Associates,Inc.
10: * of San Jose, California, U.S.A., embodying confidential
11: * information, ideas, and expressions, no part of which
12: * may be reproduced, or transmitted in any form or by any
13: * means, electronic, mechanical, or otherwise, without
14: * the written permission of D.L.Buck and Associates, Inc.
15: *
16: * NAME
17: * bscbatch - BISYNC batch job submission and query
18: *
19: * SYNOPSIS
20: * bscbatch [-to=hostname] [-copy] [-mail] [-transp] [file ... ]
21: * bscbatch -q[=hostname] [-t=hh[mm]] [-l=lines]
22: *
23: * DESCRIPTION
24: * bscbatch submits files to the BISYNC daemon (bscd) for transmission to
25: * a host, and searches among files received from a specific host for a
26: * particular user.
27: *
28: * ALGORITHM
29: * I.Initialize:
30: * A. set default values
31: * B. get user id from /etc/passwd
32: * C. get current directory's path name
33: * D. get command line options
34: * E. if queuing operation
35: * 1. get host parameters
36: * 2. check command line options against host parameters
37: * II. If queuing operation:
38: * A. open AUDIT file (if audit trail is being kept)
39: * B. if command line is exhausted:
40: * 1. get file to queue from stdin
41: * 2. make "C" (queue control) file name
42: * 3. make "D" (file copy) file name
43: * 4. make a copy of stdin file in "D" file name
44: * 5. make the queue control file
45: * C. if command line isn't exhausted:
46: * 1. while not at end of command line:
47: * a. make sure file's name is full path name
48: * b. check that it exists
49: * c. make "C" (queue control) file name
50: * d. if -copy option set:
51: * i. make "D" (file copy) file name
52: * ii. make a copy of file in "D" file name
53: * e. make the queue control file
54: * D. if an audit trail is being kept:
55: * 1. close the audit file
56: * III. If query operation:
57: * A. change to host spool directory
58: * B. open host spool directory
59: * C. while not finished reading directory and file read has
60: * an inode > 0:
61: * 1. if file's name has PR or PU in it (print or punch
62: * file):
63: * a. if -age parameter was set:
64: * i. get file's age
65: * ii. if file's age < age wanted:
66: * continue
67: * b. open file
68: * c. display file's name, when it was received,
69: * and its size
70: * d. while lines displayed <= -lines parameter:
71: * i. display a line from the file,
72: * one character at a time; if
73: * character isn't printable, display
74: * it in hex, enclosed in angular
75: * brackets (<%x>).
76: * e. close the file
77: * f. display "Rename? (Y/N): " message
78: * g. get reply
79: * h. if Y, get user's input for renamimg
80: * i. try to open new name
81: * ii. if new name is an existing file,
82: * let user choose whether or not to
83: * overwrite it
84: * iii. if not an existing file, or okay to
85: * overwrite, use system call ("mv")
86: * to rename the file
87: * i. display "Press Return to Continue" message
88: * D. close directory
89: */
90:
91: #include <stdio.h>
92: #include <pwd.h>
93: #include <sys/types.h>
94: #include <sys/dir.h>
95: #include <sys/stat.h>
96: #include <ctype.h>
97: #include "local.h"
98: #if defined BSD42
99: #include <sys/time.h>
100: #else
101: #include <time.h>
102: #endif
103:
104: #define YES 1
105: #define NO 0
106: #define PATH "/usr/spool/bscbatch/"
107: #define LIB "/usr/lib/bscbatch/"
108:
109: #ifndef lint
110: static char sccsid[] = "@(#)bscbatch.c 1.14 REL";
111: #endif
112:
113: int mail = NO; /* send mail only if problems occur */
114: int copy = NO; /* copy file to send before sending? */
115: int transp = NO; /* can host receive transparent data? */
116: int delete = NO; /* delete file after sending? */
117: int queue = YES; /* queuing or query mode? */
118: int lines; /* number of lines to display in query mode */
119: int pid; /* contains process id for this process; used to
120: give unique names to control and copy files */
121: int alpha_ctr; /* alpha array index; unique letter is part of control
122: and copy file names */
123: int age; /* hhmm ; minimum age of received files to display */
124: int host_transp = YES; /* can host receive transp data? */
125:
126: long atol(); /* function converts ascii to long */
127: long minspace; /* minimum free blocks required to receive host
128: files or copy files to be sent */
129: long freespace; /* # of free blocks left on file system /u */
130: long time(); /* function returns current time */
131:
132: FILE *fopen(); /* function opens files */
133: FILE *fptr; /* fopen's all-purpose file pointer */
134: FILE *popen(); /* function creates a pipe between bscbatch and a
135: command to be submitted to the shell for execution.
136: It returns a stream pointer which can be used to
137: read from the command's standard output or write to
138: its standard input. In bscbatch, it'll be used to
139: read in the # of free blocks available, returned by
140: the df command. */
141: FILE *pptr; /* the pointer returned by popen */
142: FILE *aud; /* the AUDIT file pointer */
143:
144: char *strcpy(); /* copies strings into specified vars */
145: char *index(); /* returns a pointer to positions of specified string
146: in specified variable */
147: char *pos; /* pointer that index returns */
148: char *devptr; /* use to get device for doing minspace check on */
149: char *strcat(); /* concatenate function */
150: char *gets(); /* get a string from stdin */
151: void exit();
152:
153: char line[300]; /* all-purpose string recepticle */
154: char dname[15]; /* contains name of device for minspace check */
155: char sys_string[50]; /* construct commands to submit to the shell via the
156: system command in here */
157: char pwd[50]; /* contains pathname to this directory */
158: char path[50]; /* contains host spool directory pathname */
159:
160: char alpha[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* index string for unique
161: spool file names */
162: char *user; /* contains user name */
163: char hostname[20]; /* contains host name */
164: char libpath[50]; /* path to host's configuration file */
165:
166: struct stat s; /* returns pointer to stat structure */
167:
168: main(argc,argv)
169: int argc;
170: char *argv[];
171: {
172: int i = 0; /* convenient index */
173:
174: struct passwd *getpwuid(); /* function returns a pointer to a
175: structure containing /etc/passwd
176: data */
177: struct passwd *uid; /* pointer that getpwuid() returns */
178: char *getlogin(); /* returns pointer to the login name */
179: /* set default values */
180: strcpy(hostname,"default"); /* host default */
181:
182: /* get user id number from /etc/passwd file. getlogin() returns
183: a pointer to the login name in user; getpwuid returns a pointer to the
184: structure containing the broken-out field of the login name's entry in
185: /etc/passwd */
186: user = getlogin();
187: if (user == NULL) {
188: if ((uid = getpwuid(getuid())) == NULL) {
189: fprintf(stderr,"bscbatch: don't know who you are!\n");
190: exit(1);
191: }
192: user = uid->pw_name;
193: }
194:
195: /* get this directory's pathname */
196: fptr = popen("pwd","r");
197: fgets(pwd,sizeof pwd-1,fptr);
198: pwd[strlen(pwd)-1] = '\0';
199:
200: /* get options from command line */
201: while (++i < argc && argv[i][0] == '-') {
202: /* copy option -- if this is YES, a copy of the file to be transmitted
203: is to be made. That copy will be transmitted to the host, rather
204: than the original. */
205: if (strcmp(argv[i],"-copy") == 0) {
206: copy = YES;
207: continue;
208: }
209:
210: /* mail option -- if this is YES, user is to receive mail whether
211: transmission was successful or not */
212: if (strcmp(argv[i],"-mail") == 0) {
213: mail = YES;
214: continue;
215: }
216:
217: /* transparent mode option */
218: if (strcmp(argv[i],"-transp") == 0) {
219: transp = YES;
220: continue;
221: }
222:
223: /* time option */
224: if(strncmp(argv[i],"-t=",3) == 0) {
225: if (argv[i][3] >= '0' && argv[i][3] <= '9')
226: age = atoi(&argv[i][3]);
227: else {
228: fprintf(stderr,
229: "bscbatch: not a number <%s>\n",argv[i]);
230: exit(1);
231: }
232: if (age < 100)
233: age *= 100;
234: continue;
235: }
236:
237: /* number of lines to display while searching (lines option) */
238: if (strncmp(argv[i],"-l=",3) == 0) {
239: if (argv[i][3] >= '0' && argv[i][3] <= '9')
240: lines = atoi(&argv[i][3]);
241: else {
242: fprintf(stderr,
243: "bscbatch: not a number <%s>\n",argv[i]);
244: exit(1);
245: }
246: continue;
247: }
248:
249: /* host to queue files for, or query spool directory of */
250: if (strncmp(argv[i],"-to",3) == 0 ||
251: strncmp(argv[i],"-q",2) == 0) {
252: if ((pos=index(argv[i],'=')) != NULL) {
253: ++pos;
254: strcpy(hostname,pos);
255: }
256: queue = (strncmp(argv[i],"-q",2)==0)?NO:YES;
257: continue;
258: }
259:
260: /* if this is a flag, it's gotta be an unrecognized one */
261: if (argv[i][0] == '-') {
262: fprintf(stderr,
263: "bscbatch: unrecognized option <%s>\n",argv[i]);
264: exit(1);
265: }
266: }
267:
268: /* check that all flags are valid with the option chosen */
269: if (!queue && (copy || mail || transp)) {
270: fprintf(stderr,
271: "bscbatch: options -copy, -mail, and -transp can't be used with -q\n");
272: exit(1);
273: }
274:
275: if (queue && (lines || age)) {
276: fprintf(stderr,
277: "bscbatch: options -l and -t can't be used with -to\n");
278: exit(1);
279: }
280: /* set-up host options/parameters */
281: set_host();
282:
283: /* do queuing or query */
284: queue?do_queue(argc,i,argv):do_query();
285: }
286:
287: /* process a file */
288: char audname[80]; /* temp audit pathname goes here */
289: char new_audnm[80]; /* real audit pathname goes here */
290: char auditlock[80]; /* audit lockfile name goes here */
291:
292: do_queue(args,i,argv)
293: int args,i;
294: char *argv[];
295: {
296: FILE *cptr; /* fopen's general purpose file pointer */
297:
298: char fname[100]; /* contains the full data file name */
299: char cpyname[100]; /* contains the "D" file name for copy */
300: char ctlname[100]; /* queue control file name */
301:
302:
303: pid = getpid(); /* get process id and put in pid */
304:
305: /* open the audit file; if unable to, audit trail not being kept */
306: sprintf(audname,"%s/%s",path,"AUDIT");
307: if (access(audname,0) >= 0) {
308: sprintf(auditlock,"%s/%s",path,"auditlock");
309: if (creat(auditlock,0) < 0)
310: bsc_audnm();
311: else
312: aud = fopen(audname,"a");
313: }
314:
315: if (i>=args) /* command line used up; get files from stdin */
316: {
317: cptr = stdin;
318: sprintf(ctlname,"%s/C%c%d",path,alpha[alpha_ctr],pid);
319:
320: /* make a copy of stdin in D<alpha><process_id> */
321: sprintf(cpyname,"%s/D%c%d",path,alpha[alpha_ctr],pid);
322: delete = YES;
323: do_copy(cptr,cpyname);
324: mkctl(mail,transp,delete,cpyname,ctlname);
325: }
326: else
327: {
328: for (;i<args;++i)
329: {
330: if(argv[i][0] != '/')
331: sprintf(fname,"%s/%s",pwd,argv[i]);
332: else
333: strcpy(fname,argv[i]);
334:
335: if ((cptr = fopen(fname,"r")) == NULL)
336: { fprintf(stderr,
337: "bscbatch: file <%s> not found\n",fname);
338: continue;
339: }
340:
341: sprintf(ctlname,"%s/C%c%d",path,alpha[alpha_ctr],pid);
342: if (copy)
343: { sprintf(cpyname,"%s/D%c%d",path,alpha[alpha_ctr],pid);
344: delete = YES;
345: do_copy(cptr,cpyname);
346: strcpy(fname,cpyname);
347: }
348: mkctl(mail,transp,delete,fname,ctlname);
349: fclose(cptr);
350: delete = NO;
351: ++alpha_ctr;
352: }
353: }
354:
355: go_away();
356: }
357:
358: /* do clean-up type stuff and go away */
359: go_away()
360: {
361: if (aud != NULL) {
362: fclose(aud);
363: if (link(audname,new_audnm) >= 0)
364: unlink(audname);
365: else
366: unlink(auditlock);
367: }
368: exit(1);
369: }
370:
371: /* query: display all PR and PU files which are in this directory */
372: do_query()
373: {
374: #if defined BSD42
375: DIR *fd; /* Spool Directory */
376: struct direct *d; /* Ptr to Spool directory entry */
377: #else
378: int fd; /* Spool Directory */
379: struct direct d; /* Spool Directory Entry */
380: #endif
381: int cctr = 0; /* count # of chars on this line so far */
382: int c; /* temp place in which to test *lptr for
383: isprint and isspace */
384: int counter = 0; /* tracks lines already displayed */
385: int fage; /* age of file to display */
386: long fday,currday;
387: register char *lptr; /* for displaying one char at a time */
388:
389: struct stat t; /* function returns a structure which
390: contains the inode data for the specified
391: file. */
392: struct tm *lt,*localtime();
393:
394: char tstring[21]; /* results of ctime go in here */
395: char ans[20]; /* all-purpose answer place */
396: char *ctime();
397:
398: /* change to directory */
399: chdir(path);
400:
401: /* open it */
402: #if defined BSD42
403: #define DNAME d->d_name
404: fd = opendir(".");
405: while ((d = readdir(fd)) != NULL) {
406: #else
407: #define DNAME d.d_name
408: fd = open(".",0);
409: while (read(fd,&d,sizeof d) == sizeof d) {
410: if (d.d_ino == 0)
411: continue;
412: #endif
413:
414: if (strncmp(DNAME,"PR",2) == 0 ||
415: strncmp(DNAME,"PU",2) == 0)
416: {
417: stat(DNAME,&t);
418: if (age) {
419: lt = localtime(&t.st_ctime);
420: fage = ((lt->tm_hour) * 100) + (lt->tm_min);
421:
422: fday = ((lt->tm_mon) *100L) + (lt->tm_mday);
423: lt = localtime((long*)0);
424: currday = ((lt->tm_mon) * 100L) + (lt->tm_mday);
425: if (fage < age)
426: continue;
427: }
428: /* set default number of lines to display if none specified */
429: if (!lines) lines = 20;
430:
431: if ((fptr = fopen(DNAME,"r")) == NULL)
432: { fprintf(stderr,
433: "bscbatch: can't open <%s/%s>\n",
434: path,DNAME);
435: exit(1); }
436:
437: strcpy(tstring,ctime(&t.st_ctime));
438: tstring[19] = '\0';
439:
440: /* display file name */
441: fprintf(stdout,
442: ">>>>> File: %s/%s <<<<<\n",path,DNAME);
443: fprintf(stdout,
444: ">>>>> Received: %s ..... Size: %ld bytes <<<<<\n",
445: tstring,t.st_size);
446: while(fgets(line,sizeof line-1,fptr) != NULL &&
447: counter < lines) {
448: /* display lines from file, one character at a time;
449: skip line[0] and line[1] if line[0] is ESC; means
450: a special print instruction is at line[1]. Print
451: no more than 80 characters on a line. If character
452: isn't printable, display it in hex enclosed in
453: angular brackets. */
454: lptr = &line[0];
455: if (line[0] == '\033' ) /* 033 is ESC */
456: lptr = &line[2];
457: while (*lptr != '\n' && cctr < 80) {
458: c = *lptr;
459: if (!isprint(c) && !isspace(c)) {
460: c &= 0xff;
461: printf("<%x>",c);
462: }
463: else
464: putc(*lptr,stdout);
465: ++lptr;
466: ++cctr;
467: }
468: putc('\n',stdout);
469: cctr = 0;
470: ++counter;
471: }
472:
473: fclose(fptr);
474:
475: /* get response from user before continuing */
476: fputs("\n>>>> Rename? (Y/N) :",stdout);
477: gets(ans);
478: if (ans[0] == 'Y' || ans[0] == 'y')
479: rename(DNAME);
480: fputs("\n>>>> Press RETURN to continue <<<<",stdout);
481: getc(stdin);
482:
483: counter = 0;
484: }
485: }
486: #if defined BSD42
487: closedir(fd);
488: #else
489: close(fd); /* close directory */
490: #endif
491: }
492:
493: /* rename -- rename a received file */
494: rename(oldname)
495: char *oldname;
496: {
497: FILE *nptr; /* new file's file pointer */
498: char testnm[80]; /* get new file name here */
499: char newname[80]; /* new name for received file built here */
500: char systr[100]; /* string to submit to shell for execution */
501: char ans[20]; /* all-purpose reply variable */
502:
503: fputs("\n>>>> Enter New File Name: ",stdout);
504: gets(testnm);
505:
506: if (testnm[0] != '/') /* put file into user's original directory */
507: sprintf(newname,"%s/%s",pwd,testnm);
508: else
509: strcpy(newname, testnm);
510:
511: /* try to open newname; if you can, warn the user */
512: if ((nptr = fopen(newname,"r")) != NULL) {
513: fclose(nptr);
514: fprintf(stderr,"bscbatch: file <%s> exists\n",newname);
515: fputs("Overwrite? (Y/N): ",stdout);
516: gets(ans);
517: if (ans[0] == 'N' || ans[0] == 'n')
518: return;
519: }
520:
521: sprintf(systr,"mv %s %s\n",oldname,newname);
522: fprintf(stdout, "\n>>>> Verify move %s to %s (y/n): ", oldname,newname);
523: gets(ans);
524: if (ans[0] == 'y' || ans[0] == 'Y')
525: system(systr);
526:
527: return;
528: }
529:
530: /* create queue control files */
531: mkctl(ml,trnsp,del,fname,ctlname)
532: int ml,trnsp,del;
533: char fname[],ctlname[];
534: {
535: FILE *ctlptr;
536: char cline[50];
537: char msg[100]; /* message going into audit file */
538:
539: long time();
540: long currtime;
541:
542: struct tm *t;
543: struct tm *localtime();
544:
545: /* all files queued during this session will have the same process id number
546: attached to their q-ctl names; use letters of the alphabet to make each
547: name unique if open for write not allowed because file name already exists */
548: do
549: sprintf(ctlname,"%s/C%c%d",path,alpha[alpha_ctr],pid);
550: while ((ctlptr = fopen(ctlname,"w")) == NULL && alpha_ctr < 26);
551:
552: if (ctlptr == NULL)
553: { fprintf(stderr,
554: "bscbatch: can't create <%s>\n",ctlname);
555: go_away();
556: }
557:
558: sprintf(msg,"Queued <%s>, option(s): ",fname);
559:
560: /* mail option set -- force mail to be sent to user when file successfully
561: transmitted */
562: if (ml)
563: { sprintf(cline,"M=%s\n",user);
564: fputs(cline,ctlptr);
565: strcat(msg,"<mail> ");
566: }
567:
568: /* transp option set -- force file to be sent in transparent mode */
569: if (trnsp)
570: { sprintf(cline,"T %s\n",fname);
571: fputs(cline,ctlptr);
572: strcat(msg,"<transparent> ");
573: }
574:
575: else
576: { sprintf(cline,"S %s\n",fname);
577: fputs(cline,ctlptr);
578: }
579:
580: if (del)
581: { sprintf(cline,"D %s\n",fname);
582: fputs(cline,ctlptr);
583: strcat(msg,"<copy> ");
584: }
585:
586: /* update the audit file if audit trail being kept */
587: if (aud) {
588: if (!transp && !mail && !copy && !del)
589: strcat(msg," <none>");
590:
591: currtime = time((long *)0);
592: t = localtime(&currtime);
593:
594: fprintf(aud,
595: "%s %s %02d%02d%02d%02d%02d %s\n",
596: user,"Q",t->tm_year,(t->tm_mon)+1,
597: t->tm_mday,t->tm_hour,t->tm_min,msg);
598: }
599:
600: fclose(ctlptr);
601: }
602:
603: /* create a copy of the file to send */
604: do_copy(fileptr,cpyname)
605: FILE *fileptr;
606: char cpyname[];
607: {
608: FILE *dptr;
609:
610: char cline[100];
611:
612: if ((dptr = fopen(cpyname,"w")) == NULL)
613: { fprintf(stderr,
614: "bscbatch: can't create <%s>\n",cpyname);
615: go_away();
616: }
617:
618: while (fgets(cline,100,fileptr) != NULL)
619: fputs(cline,dptr);
620:
621: fclose(dptr);
622: }
623:
624: /* set_host() - do host set-up and option/parameter checking */
625: set_host()
626: {
627: int linect = 0; /* keeps track of line being read
628: from host config file */
629:
630: /* get transparent and minimum space parameters from host config file */
631: strcpy(libpath,LIB);
632: strcat(libpath,hostname);
633:
634: if ((fptr = fopen(libpath,"r")) == NULL) {
635: fprintf(stderr,"bscbatch: host <%s> not known\n",hostname);
636: exit(1);
637: }
638:
639: while (fgets(line,sizeof line,fptr) != NULL) {
640: /* loop to get transparent and minspace parameters */
641: ++linect;
642: if (strncmp(line,"TRANSPARENT=",12) == 0) {
643: pos = &line[12];
644: host_transp = strncmp(pos,"YES",3)?NO:YES;
645: continue;
646: }
647: if (strncmp(line,"MINSPACE=",9) == 0) {
648: if ((pos = index(line,',')) == NULL) {
649: fprintf(stderr,
650: "bscbatch: Incorrect parameter usage, line %d in <%s>\n",
651: linect,libpath);
652: exit(1);
653: }
654: ++pos;
655: minspace = atol(pos);
656: pos = &line[9];
657: devptr = &dname[0];
658: while (*pos != ',')
659: *devptr++ = *pos++;
660: *devptr = '\0';
661: continue;
662: }
663: }
664:
665: /* check that, if host cannot receive transparent date, the transparent
666: option hasn't been set */
667: if (transp && (host_transp == NO)) {
668: fprintf(stderr,
669: "bscbatch: host <%s> cannot receive transparent files\n",
670: hostname);
671: exit(1);
672: }
673:
674: /* check space left in file system / (user area):
675: the df command prints the # of free blocks and inodes available on the
676: entire system. Since all that's needed here is the # of free blocks in
677: /, the flag -f is used and / is specified. popen creates a pipe between
678: bscbatch and the df command, returning a file pointer (pptr) to df's output.
679: fgets can then be used to read the string df returns into line and
680: the number of free blocks is then extracted. */
681: if (queue && minspace)
682: { sprintf(sys_string,"df -f %s\n",dname);
683: pptr = popen(sys_string,"r");
684: fgets(line,100,pptr);
685: freespace = atol(&line[25]);
686: }
687:
688: /* check that, if copy option specified and minspace is set, freespace is
689: at least 150% of minspace */
690: if (copy && minspace && (freespace < (minspace * 1.5))) {
691: fprintf(stderr,
692: "bscbatch: can't copy your files -- file system too full\n");
693: exit(1);
694: }
695:
696: /* construct spool pathname, change to it to check validity */
697: strcpy(path,PATH);
698: strcat(path,hostname);
699: stat(path,&s);
700: if ((s.st_mode & S_IFMT)!= S_IFDIR) {
701: fprintf(stderr,"bscbatch: <%s> has no spool directory\n",
702: hostname);
703: exit(1);
704: }
705: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.