These instructions apply to all levels of AIX.
This backend was written as a starting point for other backends.
The backend receives print jobs, logs information about the job,
and requeues the job to another queue. A few of the qprt flags
are supported as a starting example.
You can also include the following:
/* Example include statements */ #include <stdio.h> #include <IN/backend.h> #include <IN/standard.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <stdlib.h> |
This program is designed to expect the first argument passed to be the new queue to which the program will requeue the data. This queue will be passed to the program from the /etc/qconfig line that specifies the backend. For example:
backend = /usr/local/bin/baseback newqueue
The queue daemon passes other flags to AIX as command line
arguments. Flags that are specific to enq are received
with special libqb backend function calls.
Because there will be command line arguments, use the main function with argc and argv variables common to C programmers. This should be nothing new. For example:
main(argc,argv) unsigned argc; char **argv; { /* Pluck off the command line the new queue name */ /* The /etc/qconfig line should be */ /* backend = /full_path/baseback new_queue */ strcpy(newq,argv[1]); |
The variable declarations are left out. See the Example Program for details.
Next, call a subroutine to parse a few of the other non-enq flags for an example.
/* Parse the print command arguments */ flgarg = ++argv; /* I need this to get rid of queue name */ /* Call routine flag_opts to parse arguments */ cmrc = flag_opts(argc-1, flgarg); ... /* Excerpt from the flag_opts routine */ /* This routine is designed to take the command line arguments and turn them into flags for the enq print command */ /* Current version really only supports the -p qprt flag and */ /* the -z qprt flag, but the general structure applies */ /* This routine builds the enq output flags that will be */ /* needed when enq'ing to the next queue. */ int flag_opts(argc, argv) int argc; char **argv; { int c,i; char tflags[40]; int ndex; strcpy(flagout,""); while ((c = getopt(argc, argv, "A:p:z:") ) !=EOF) { switch (c) { case 'A': printf("debug opt"); break; case 'p': sprintf(tflags," -o -p -o %s",optarg); strcat(flagout,tflags); break; case 'z': sprintf(tflags," -o -z -o %s",optarg); strcat(flagout,tflags); default: ndex = optind; printf ("unknown opt. ch:%c opt:%s ind:%d\n",c,optarg,optind); break; } } strcpy(filelst,""); /* Blank out file names */ filecnt = 0; /* Now generate a list of files since we fell through getopt */ /* The rest of the arguments should be files */ for (i=optind; i<argc; i++) { filecnt++; strcat(filelst," "); strcat(filelst,argv[i]); if (filecnt == 1) pfile = argv[i]; } } /* End of function flag_opts */ |
The printf statements are for debug purposes, and will write to the file specified in the /etc/qconfig line. The file must exist before using the queue. touch /dev/lpx. In /etc/qconfig:
The flags that are valid for enq (man enq) do not show up as command line arguments, but are available as functions. For more details, see info - queue library backend routines. To compile with these routines requires that you link with -lqb. This provides all the information that you would need to write your own header page routines. They can also be used for flags needed when requeuing the jobs to the new queue.
If the code is to be tested from the command line (without a queue), you may want to call a routine to find if this is a backend. The routine that is useful is get_backend(). Example:
The lib backend routines are illustrated by example. Remember that you can use printf to write these to stdout, and they will go to the file = /dev/lpx file for debugging. You should recognize most of these without explanation as either values from man enq, or from the header page information.
/* See if this is being run as a backend program */ if (isbackend) { /* Some of the standard backend subroutine calls are */ /* used here. These require link with libqb (-lqb) */ /* during the compile of this program. */ qdate = get_qdate(); /* When job was queued */ to = get_to(); /* Output goes to whom */ strcpy(touser,to); /* This contains user */ /* name and system */ strcpy(tosys,""); /* It is useful to have the system of the user to send */ /* mail about job completion or error messages */ to1 = strchr(touser,'@'); if (to1 != 0) { to1 = strtok(touser,"@"); acnt = strlen(touser); sysuser = to + acnt + 1; strcpy (tosys,sysuser); } /* enq -Ttitle option */ title = get_title(); /* Usually the print file name */ qname = get_queue_name(); /* This queues name */ qdname = get_device_name(); /* queue device name */ from = get_from(); /* Submitting user */ /* If you don't want those messages to the screen you can */ /* resubmit the new job as mail only. This tells how this */ /* job was submitted. enq -C option used? */ mail_only = get_mail_only(); /* Mail only or not */ /* Job number could be useful for logging */ jobnum = get_job_number(); /* This will give /etc/qconfig header =, unless -Bxx flag used */ heder = get_header(); if (heder == 0) strcpy(hedstr,"nn"); else strcpy(hedstr,"an"); /* This cmdline actually contains hostname and user who sent the job. You should parse this */ cmdline = get_cmd_line(); } /* End of backend only routines */ /* Just a little code so this will run without a queue */ else /* When run from the command line for testing */ { strcpy(hedstr,"nn"); strcpy(ctitle, pfile); strcpy(cfrom,"only_you"); printf("hed: %s %s %s\n",hedstr, ctitle, cfrom); } |
This job requeues the data, but it could actually submit the job to any other program to run.
From the main routine, call the do_data subroutine as follows:
The subroutine to send the data is as follows:
/* The do_data routine creates the command string that is sent */ /* to the shell with the pipeit routine. Some basic ENQ flags */ /* are supported in this section from the libqb input */ int do_data (dtype) int dtype; { int w, land, port, irc; char tmptst[300]; char *str1; strcpy(queue,newq); if (dtype) /* from a queue use */ /* The basic enq flags used are -T Title, -Bnn Header, -Z touser*/ /* The qprt flags -z and -p are sent with flagout */ /* The job names are sent with filelst */ sprintf(cmd,"enq -B%2s -c -P%s -T%s -Z%s %s %s\n",hedstr,queue, title, from, flagout, filelst); else /* If not a backend program then use */ sprintf(cmd,"enq -B%2s -c -P%s -T%s -Z%s %s %s\n",hedstr,queue, ctitle, cfrom, flagout, filelst); /* Pipeit routine actually forks and execs the print job */ irc = pipeit(cmd); if (irc != 0) errcode = errcode + 2; } /* Finally this routine actually forks a process to run the */ /* print command. If you uncomment the printf line, it will */ /* also send the command line to the file in 'file = ' of */ /* /etc/qconfig for debugging purposes */ char trapit[20]="trap \"\" 15;\n"; int pipeit(s) char *s; { int prc, pid, w; int loopture; void (*istat)(), (*qstat)(); char outstr[300]; strcpy(outstr,trapit); strcat(outstr,s); /* Uncomment this for debugging printf("sending to queue with\n %s\n",outstr); */ if((pid = fork()) == 0) { setpgrp(); /* set group id */ execl("/bin/ksh", "ksh", "-c", outstr, 0); /* ERREXIT(0, MSG_EXECFAIL, NULL, NULL, errno); */ } sleep(5); /* Let the files get copied */ } |
An environment variable is used to pass the log file
to the backend. This could just as easily be an argument
passed on the backend = line of /etc/qconfig, but this
illustrates another method of passing data.
The environment variable can be set up in /etc/environment, or in a users .profile, or simply from the command line with:
The program only logs data if the AQLOG environment variable is set. The following code shows how logging is implemented in a simple case. The file size is logged, as opposed to counting pages or lines.
/*This gives us the capability to log files to user defined file */ /*If the user defines a value for AQLOG, then logging will occur */ aqlog = getenv("AQLOG"); /* Get user log file */ if (strlen(aqlog) == 0) log = 0; else { log = 1; strcpy(aqlogf,aqlog); } if (log == 1) /* If logging turned on, write to file */ { /* This statement is to get the file size of the file */ lstat(pfile, &attrs); /* Open the log file based on the name passed in AQLOG */ /* This open should append to the file, not overwrite */ fd = fopen(aqlog,"a"); /* Treat this different if not acting as a backend */ if (isbackend) { fprintf(fd,"%3d, %20s, %7s, %7s," ,jobnum,qdate,qname,queue); fprintf(fd," %12s,",to); fprintf(fd," %6d ",attrs.st_size); if (dt == 3) fprintf(fd,", %s, %d\n",title,heder); if (errcode != 0) fprintf(fd,", ERROR = %d\n",errcode); } else fprintf(fd,"queuename: %s file: %s size: %6d\n",newq, pfile,attrs.st_size); /* Close the file */ fclose(fd); |
The following smit page is from AIX 4, but a similar screen
appears at AIX 3.2 when you are adding a queue with smitty spooler.
other User Defined Backend
* Name of QUEUE to add [testq] * Name of QUEUE DEVICE to add [testd] * BACKEND PROGRAM pathname [/usr/local/bin/subque q.log] ACTIVATE the queue? yes Should this become the DEFAULT queue? no Queuing DISCIPLINE first come first serve ACCOUNTING FILE pathname [] HOSTNAME of remote server [] Name of QUEUE on remote server [] Pathname of the SHORT FORM FILTER for queue [] status output Pathname of the LONG FORM FILTER for queue [] status output BACKEND OUTPUT FILE pathname [/dev/testl] |
/* This is baseback backend */ /* Copyright IBM Corporation Inc, 1996 */ /* Author: John Tesch, IBM AIX Systems Center */ /* Code may be used and distributed, but must maintain original */ /* Copyright and references. */ /* Compile with cc -o baseback -lqb baseback.c */ /* This program is designed to show the basics of writing a */ /* Simple AIX Print Backend - Stage one */ /* */ /* This program simply re-queues a job to another queue */ /* */ #include <stdio.h> #include <IN/backend.h> #include <IN/standard.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <stdlib.h> /* I'm over generous with the use of global variables - sorry */ char *qdate; char* pfile; char *cmdline; char *to; char *devname; char *title; char *aqlog; char newq[14]; char *qname; char queue[24]; char *qdname; char *from; char ctitle[90]; char cfrom[15]; char errmsg[80]; char filelst[256]; int filecnt; char cmd[255]; char o_flags[80]; char flagout[80]; char touser[40]; char tosys[40]; char aqlogf[40]; char hedstr[6]; int mail_only; int jobnum,log; int linecnt, pagecnt, widecnt; int rflag; /* Remove file flag - make copy? */ int errcode; int isbackend; FILE *fd; FILE *fn; /* Define libq backend routines */ extern char *get_qdate(); extern char *get_to(); extern char *get_from(); extern char *get_title(); extern char *get_queue_name(); extern char *get_device_name(); extern char *get_cmd_line(); main(argc,argv) unsigned argc; char **argv; { int rc, i, c, w, dt, cmrc, acnt; int itmp; unsigned int heder; char* myuser; char* sysuser; char* str1; char myout[80]; char test[80]; char* to1; FILE *pf; struct stat attrs; char **flgarg; /* Pluck off the command line the new queue name */ /* The /etc/qconfig line should be */ /* backend = /full_path/baseback new_queue */ strcpy(newq,argv[1]); /* Parse the print command arguments */ flgarg = ++argv; cmrc = flag_opts(argc-1, flgarg); /* Test to see if this is being run as queue backend or from cmd line */ isbackend = get_backend(); /* This will be set to 0 if not run as queue */ errcode = 0; /* This gives us the capability to log files to user defined file */ /* If the user defines a value for AQLOG, then logging will occur */ aqlog = getenv("AQLOG"); /* Get user log file */ if (strlen(aqlog) == 0) { log = 0; } else { log = 1; strcpy(aqlogf,aqlog); } rc = 0; if (isbackend) /* Only call log_init if this is a backend */ /* This is an obligatory routine for getting access to all the other routines - log_init */ rc = log_init(); if (rc == -1) { exit(1); } if (isbackend) { /* Some of the standard backend subroutine calls are */ /* used here. These require link with libqb (-lqb) */ /* during the compile of this program. */ qdate = get_qdate(); to = get_to(); strcpy(touser,to); strcpy(tosys,""); to1 = strchr(touser,'@'); if (to1 != 0) { to1 = strtok(touser,"@"); acnt = strlen(touser); sysuser = to + acnt + 1; strcpy (tosys,sysuser); } title = get_title(); qname = get_queue_name(); qdname = get_device_name(); from = get_from(); mail_only = get_mail_only(); jobnum = get_job_number(); heder = get_header(); if (heder == 0) strcpy(hedstr,"nn"); else strcpy(hedstr,"an"); /* This cmdline actually contains hostname and user who sent the job. I'll leave it for you to parse this */ cmdline = get_cmd_line(); } /* End of backend only routines */ else /* When run from the command line for testing */ { strcpy(hedstr,"nn"); strcpy(ctitle, pfile); strcpy(cfrom,"only_you"); printf("hed: %s %s %s\n",hedstr, ctitle, cfrom); } /* Now to get the data to print */ /* And pass it on to the printer - FILE = is stdout */ /* The values here are non valid enq flags */ /* strcpy(o_flags,""); if (argc > 1) for (acnt = 1; acnt < argc-1; acnt++) { strcat(o_flags," -o "); strcat(o_flags,argv[acnt]); } printf("O_FLAGS: %s\n"); */ /* This calls routine that also prints the file */ rc = do_data(isbackend); if (log == 1) /* If logging turned on, write to file */ { /* This statement is to get the file size of the file for our log */ lstat(pfile, &attrs); fd = fopen(aqlog,"a"); if (isbackend) { fprintf(fd,"%3d, %20s, %7s, %7s," ,jobnum,qdate,qname,queue); fprintf(fd," %12s,",to); fprintf(fd," %6d ",attrs.st_size); if (dt == 3) fprintf(fd,", %s, %d\n",title,heder); if (errcode != 0) fprintf(fd,", ERROR = %d\n",errcode); } else fprintf(fd,"queuename: %s file: %s size: %6d\n",newq,pfile,attrs.st_size); fclose(fd); exit(0); } } /* The do_data routine creates the command string that is sent */ /* To the shell with the pipeit routine. Some basic ENQ flags */ /* are supported in this section from the libqb input */ int do_data (dtype) int dtype; { int w, land, port, irc; char tmptst[300]; char *str1; strcpy(queue,newq); if (dtype) sprintf(cmd,"enq -B%2s -c -P%s -T%s -Z%s %s %s\n",hedstr,queue, title, from, flagout, filelst); else sprintf(cmd,"enq -B%2s -c -P%s -T%s -Z%s %s %s\n",hedstr,queue, ctitle, cfrom, flagout, filelst); irc = pipeit(cmd); if (irc != 0) errcode = errcode + 2; } /* This routine is designed to take the command line arguments and turn them into flags for the enq print command */ /* Current version really only supports the -p qprt flag and */ /* The -z qprt flag, but the general structure applies */ int flag_opts(argc, argv) int argc; char **argv; { int c,i; char tflags[40]; int ndex; strcpy(flagout,""); while ((c = getopt(argc, argv, "A:p:z:") ) !=EOF) { switch (c) { case 'A': printf("debug opt"); break; case 'p': sprintf(tflags," -o -p -o %s",optarg); strcat(flagout,tflags); break; case 'z': sprintf(tflags," -o -z -o %s",optarg); strcat(flagout,tflags); case '+': printf ("+ arg: %s\n",optarg); break; default: ndex = optind; printf ("unknown opt. ch:%c opt:%s ind:%d\n",c,optarg,optind); break; } } strcpy(filelst,""); /* Blank out file names */ filecnt = 0; for (i=optind; i<argc; i++) { filecnt++; strcat(filelst," "); strcat(filelst,argv[i]); if (filecnt == 1) pfile = argv[i]; } } /* Finally this routine actually forks a process to run the */ /* print command. If you uncomment the printf line, it will */ /* also send the command line to the file in 'file = ' of */ /* /etc/qconfig for debugging purposes */ char trapit[20]="trap \"\" 15;\n"; int pipeit(s) char *s; { int prc, pid, w; int loopture; void (*istat)(), (*qstat)(); char outstr[300]; strcpy(outstr,trapit); strcat(outstr,s); /* Uncomment this for debugging printf("sending to queue with\n %s\n",outstr); */ if((pid = fork()) == 0) { setpgrp(); /* set group id */ execl("/bin/ksh", "ksh", "-c", outstr, 0); /* ERREXIT(0, MSG_EXECFAIL, NULL, NULL, errno); */ } sleep(5); /* Let the files get copied */ }