| Version 2.11 | Feb 16, 1999 |
|---|
Mary Ann logs into Sybase every Monday morning. She does this by first selecting the URL to the Sybernet sign-on screen. She then enters her username and [Enigma] password. Then she selects the desired form screen from the Sybernet main menu. Now she enters her org number on this screen and clicks on the SUBMIT button. In a matter of only few seconds, her report appears on her screen.
There's a better solution: just send Mary Ann this report to her E-Mail address. Not only does this eliminate several redundant steps on her end, but also the job that does this can be scheduled when Sybase is not busy doing other work.
Unless you override the default Content-type, the results of your stored procedure are mailed with a Content-type of text/html. This means someone receiving this mail will want to have an E-mail program that recognizes this type. NetScape Navigator 3.0 and above is such a program.
The following example illustrates how EMAIL may be specified in a URL request:
The MacOS version of Sybernet does not allow EMAIL to be assigned in this fashion and
will ignore any attempts to do so.
The following columns are required to identify your stored procedure:
ROW_ID uniquely identifies rows in this table. ROW_ID is primarily for the declaration of
CRON_INDEX which allows sp_html_cron to declare a cursor for
update. It is also used by sp_cron_insert to determine
if a row is being updated (when not null) or inserted (when null).
ROW_ID also points to the parameters table, CRON_PARAMETERS. This table is used to pass
parameters to your stored procedure.
PROCNAME is the name of your stored procedure. To be compatible with the REGISTER table in
the HTTP database, PROCNAME should include db_name(), owner, and name. Owner should not be
implied. Specify dbo if that is what you mean.
One exception is stored procedures in sybsystemprocs. Those procedures should neither specify
db_name() nor owner.
PROCNAME may also be a UNIX executeable or interpreter file if
PROCNAME begins with either a period (.) or slash (/). Interpreter files are
assumed to begin with #!; anything else is assumed to an executeable.
Parameters to your C program are gotten from the table CRON_PARAMETERS, but instead of
creating NAME=VALUE pairs as is done for stored procedures, only the VALUE is passed in
the standard argv array. Parameters should also not include \n
since this is used to separate each parameter VALUE.
./Syberload is a built-in function that allows you to upload UNIX
files into Sybase.
TITLE allows you to specify a title for this procedure. TITLE
is used as the subject of your e-mail message. It also appears in the Sybercron Monitor.
DESCRIPTION is similar to TITLE except that it is suppose actually describe what this
procedure does.
GROUPTYPE helps Sybercron determine how to interpret E-Mail addresses in the GROUPS
table. If specified as "Y", Sybercron will recurse on each E-Mail address in the
GROUPS table, invoking the specified procedure once for each E-Mail address. Any other
value means that the same report is sent to the same E-Mail address.
EMAIL may be either an E-Mail address or a GROUPNAME from table GROUPS. Note that a
GROUPNAME does not actually have to exist in table GROUPS.
sp_html_cron will skip over any procedures that don't
actually have any addresses assigned. This allows you to add valid addresses at
a later time.
SENDER (or FROM) optionally specifies the sender of this E-Mail. If not specified,
the default value is Sybernet. Sybernet must be a valid alias in /etc/aliases.
SCRIPTNAME or EMAIL is required. If EMAIL is specified, SCRIPTNAME simply represents
the name of the temporary file that is created before sendmail is
called. If EMAIL is not specified, SCRIPTNAME represents the file name that is to be
created and saved. In general, SCRIPTNAME should include a path to your htdocs
directory; for example, ../htdocs/report1.
FORMAT determines the output format of your stored procedure. The default is NONE.
FILTER determines the filter option. The default is NULL, no filtering.
CONTENTTYPE determines the Mime Content-type. The default is text/html.
HOSTNAME is a server name in your interfaces file. This field is optional if all of
your procedures are executed at the same host because Sybercron
logs into Sybernet with a default server name.
If you specify HOSTNAME and do not specify USERCODE, a remote procedure call is invoked
by appending PROCNAME to HOSTNAME (i.e., exec server.database.owner.procname). The
remote server name must be valid and defined with sp_addserver.
You may optionally specify a USERCODE separate from the default username used by
Sybercron. If a usercode is specified, a valid HOSTNAME
and PASSWORD are also required.
PASSWORD is required if you specify a USERCODE.
PLATFORM specifies the name of the UNIX system that is to
invoke your procedure or script. PLATFORM corresponds to the identity value
passed to Sybercron in the -I option.
If you specify a value for PLATFORM that does not exist, your procedure or
script will never be executed.
The default value for PLATFORM is SPOCK.
TIMESTAMP determines the date and time that this procedure should next be executed.
The procedure sp_html_cron is the stored procedure called
from UNIX that determines what procedures are to be executed. This procedure uses a
Better Late Than Never approach in this determination. That is, if your stored
procedure is suppose to be executed on Monday's at 8 AM and the CRON job running from
UNIX was restarted on Wednesday, your procedure will be selected for execution.
If TIMESTAMP is NULL when inserted with sp_cron_insert,
the next execution date is automatically calculated based on your value of DATENAME.
If both TIMESTAMP and DATENAME are NULL, your
procedure is scheduled for immediate execution and is then discarded from the CRON table.
NULL values for TIMESTAMP are valid, but sp_html_cron will
not select any entries in the CRON table for execution if their TIMESTAMP is NULL.
STARTTIME represents the earliest date that this procedure may be executed. A NULL value
for STARTTIME means your procedure can be executed now.
STOPTIME represents the latest date that this procedure may be executed. A NULL value
for STOPTIME means your procedure can be executed forever.
The Better Late Than Never approach affects STOPTIME this way. If TIMESTAMP
(representing the next execution of this procedure) is less than or equal to STOPTIME,
the procedure is still executed as long as TIMESTAMP is less than or equal the current
date and time. This makes it possible (when TIMESTAMP and STOPTIME are equal) to
schedule a procedure that is executed only once.
DATENAME determines when your procedure is actually executed.
DATENAME is one of the following values:
Note that the list of valid DATENAMEs are stored in the table http..CRON_DATENAMES.
DAY corresponds to the day of the month. This value is meaningful only when DATENAME is
MONTH or corresponds to one of the months of they year.
HOUR represents the hour of the day.
MINUTE represents the minute of the day.
Email
EMAIL is a reserved word in Sybernet that may be read or written. If specified in a stored
procedure, it should either represent a valid E-mail address or a GROUPNAME in table GROUPS.
select '<A HREF="Sybase.cgi$http..sp_html_who?@EMAIL=%22nospam@nospams.com%22>Click</A>'
Similarly, you may specify EMAIL in a POST request:
select '<INPUT TYPE="TEXT" NAME="@EMAIL" VALUE="nospam@nospams.com">'
In addition to specifying EMAIL, you may optionally specify both the Subject and Sender of
this mail. Procedures which have been registered with the Sybercron register facility will
get the Subject automatically from TITLE in the CRON table. The Sender can be specified
manually using the keyword FROM or automatically from the CRON table from the SENDER field.Table Cron
The following declarations represent the tables and indicies that are required to execute
stored procedures on a recurring basis. You should not insert entries into table CRON
directly. Instead, you should call the procedure sp_cron_insert
to insert or update an entry in this table. Entries into the table GROUPS may be done safely
without intervention, however.
create table CRON
(
ROW_ID numeric(9,0) identity /* This allows us to update our cursor */
, PROCNAME varchar(92) not null /* Procedure Name (fully qualified) */
, TITLE varchar(255) null /* Procedure title (for subscriptions) */
, DESCRIPTION varchar(255) null /* Description (for subscriptions) */
, GROUPTYPE char(1) null /* "Y" if recurse on EMAIL in GROUPS. */
, EMAIL varchar(255) null /* E-Mail Address (or GROUPNAME) */
, SENDER varchar(255) null /* E-Mail Address of sender */
, SCRIPTNAME varchar(255) null /* Name of disk file (filename) */
, FORMAT varchar(30) null /* NONE,SUPPRESSED,RTF,EXCEL,TABULAR */
, FILTER varchar(30) null /* CGI,ECHO */
, CONTENTTYPE varchar(30) null /* Mime Content-type (ie, text/html) */
, HOSTNAME varchar(30) null /* Hostname (server name) */
, USERCODE varchar(30) null /* Username */
, PASSWORD varchar(30) null /* Password */
, PLATFORM varchar(30) null /* Platform name where Sybercron is running at */
, TIMESTAMP datetime null /* The NEXT time I should run this */
, STARTTIME datetime null /* When I can start running this procedure */
, STOPTIME datetime null /* When I can stop running procedure */
, DATENAME varchar(10) null /* Month/Weekday/HOUR/WEEKDAY/DAY/MONTH/PERIOD */
, DAY int null /* 1-31 (or 1-28) */
, HOUR int null /* 0-23 */
, MINUTE int null /* 0-59 */
)
create unique index CRON_INDEX on CRON (ROW_ID)
Table CRON is obviously the more complicated of these structures.
So complicated in fact that you should not attempt to insert entries into this table
directly. Failure to do so may cause your stored procedure to fail when executed.
Some columns are important for documentation:
Some of these columns are parameters passed to Sybernet:
Other columns determine when this procedure can be executed:
And the remaining columns determine how often your stored procedure should be executed:
Seems complicated, I know, but sp_cron_insert (described below)
will help you create entries in this table in a very easy manner. As I said, inserting into
this table directly is discouraged because your procedure may not run if the information in
this table is invalid.
Note that a NULL value for DATENAME will cause this entry in the CRON table to be deleted
after it has been selected for execution. Calling sp_cron_insert
with a NULL value for both TIMESTAMP and DATENAME is a convenient way to insert an entry for
immediate execution while also deleting that entry as soon as it is submitted.
Cron Parameters
The table CRON_PARAMETERS are the parameters (if any) that are passed to your procedure
when executed by Sybercron. Here's what this table looks like:
create table CRON_PARAMETERS
(
ROW_ID numeric(9,0) not null /* Identifies which procedure this goes with */
, NAME varchar(30) not null /* Parameter name */
, VALUE varchar(255) not null /* Parameter value */
)
Although you may not use sp_cron_insert to insert values into
this table, sp_html_cron_register will do this
automatically for you.You can safely add or delete entries in this table, but if you do, you'll want to make sure that ROW_ID, NAME, and VALUE are valid. An invalid ROW_ID will be ignored. An invalid NAME could cause the execution of your procedure to fail. All parameters, of course, must be either char or varchar.
declare @ROW_ID int
exec @ROW_ID = sp_cron_insert
@PROCNAME = "http.dbo.sp_getstatus"
, @EMAIL = "PUBLIC"
, @DATENAME = "MONTH"
if @ROW_ID != -1
insert CRON_PARAMETERS
(
ROW_ID
, NAME
, VALUE
)
values
(
@ROW_ID -- ROW_ID in table CRON
, "@ORGCODE" -- Parameter name
, "024" -- Parameter value
)
This example first inserts an entry in the CRON table. If the return result is not -1,
the appropriate parameter name and value is added to CRON_PARAMETERS. When this procedure
executes, @ORGCODE="024" is appended to its run statement.
Cron Groups
Table CRON_GROUPS is used for E-Mail aliases. It's very easy to use, but there are rules for adding
and deleting entries. First, let's take a look at its declaration.
create table CRON_GROUPS
(
GROUPNAME varchar(30) not null /* Name of group */
, EMAIL varchar(255) not null /* An E-Mail address (may not be a groupname) */
, TIMESTAMP datetime null /* The datetime this entry added to /etc/aliases */
)
The entries in this table must correspond to aliases in the UNIX file /etc/aliases. As such,
there must be some way to determine when /etc/aliases should be rewritten. The stored
procedure sp_html_cron examines this table for NULL values of
TIMESTAMP. NULL values mean this table has changed; therefore, you never want to insert
non-null values for this field.
GROUPNAME is the name of this group.
EMAIL is a valid E-Mail address or NULL when an entry is to be deleted.
TIMESTAMP is NULL if an entry is to be added to or deleted from /etc/aliases. If not NULL, TIMESTAMP is the date and time this entry was added to /etc/aliases.
insert GROUPS
(
GROUPNAME
, EMAIL
, TIMESTAMP
)
values
(
"group1" -- Name of group
, "nospam@nospams.com" -- E-Mail address
, null -- Must be null
)
You can also update entries in this table, but (again) you want to set TIMESTAMP to NULL
so that the /etc/aliases file can be rewritten.
update GROUPS
set GROUPNAME = "group2"
, TIMESTAMP = NULL
where EMAIL = "nospam@nospams.com"
And rows should never be deleted directly. Instead, simply set the EMAIL column to NULL
(to indicate that this row is to be deleted) and TIMESTAMP to NULL (to indicate that the
table has changed).
update GROUPS
set TIMESTAMP = NULL
, EMAIL = NULL
where EMAIL = "nospam@nospams.com"
When sp_html_cron runs and /etc/aliases is rewritten, this
procedure will delete rows that have null EMAIL and TIMESTAMP columns.It is also safe to set all TIMESTAMPs to NULL to force a rewrite of /etc/aliases.
sp_cron_insert allows you to specify only those columns that you are interested in. With
some intelligence, the remaining columns are calculated automatically! You can even update
entries in the CRON table with this procedure when ROW_ID is not null.
sp_cron_insert returns -1 if the insert failed or the ROW_ID of this entry if the insert
succeeded.
Let's take a look at a few examples.
The first example illustrates how you would insert an entry in table CRON that is executed
every Christmas at 8 o'clock in the morning:
Since TIMESTAMP and DATENAME were not specified, sp_cron_insert creates an entry in the
CRON table that will be executed immediately and then deleted.
Parameters to your C program are gotten from the table CRON_PARAMETERS. Each VALUE in
this table is passed to your program in its argv array. Parameter values
in CRON_PARAMETERS should also not contain \n because this character is
used to delimit these parameters when they are sent to Sybercron on UNIX.
It is important to specify an explicit path and filename when executing scripts in this fashion
because you do not know the path where Sybercron is executing from. Permissions are important
too; if Sybercron cannot read this file, it will be unable to execute this command.
./Syberload is a built-in function that allows you to upload UNIX
files into Sybase. Files uploaded with this mechnism may contain any Transact-SQL statements and may
be batched with the keyword GO.
The following example illustrates how to upload a Sybase script file:
The remaining arguments are optional. The second argument (arg2) can be either an e-mail address
or the name of a disk file. It's an e-mail address if it contains an at-sign in its value. If
it's a disk file name, the file is opened for append. If the second argument is not specified,
the results of your script are written to the Sybernet log file.
The third argument (arg3) allows you to specify the content-type (text/html or text/plain), and
the fourth argument (arg4) allows you to give a title for the subject of your e-mail.
All arguments are passed by order, not by name. You can't specify a Content-type unless you
also specify a e-mail address, for example.
NOTE: Versions 2.18 and below of Sybercron do not recognize the
optional attributes documented here.
The ability to insert directly into CRON_PARAMETERS has not been removed.
It is now possible to call Sybercron and wait for its return result by calling
the stored procedure sp_cron_wait. sp_cron_wait expects the ROW_ID returned from
sp_cron_insert (and also the the ROW_ID passed to sp_cron_insert_parmater) as
its only parameter; for example, the example above could be modified as follows:
Remember that your browser will timeout after 5 minutes without any response. Calling
sp_cron_wait so that you can display this result is not always practical.
When sp_html_cron_register is invoked, three windows are built on your screen.
They are the Directory Window, the Input Window, and the Output Window:
At the top of this list is a hypertext link that identifies the current database.
To change the current database simply click on this link. A menu of all databases
on the system is displayed in this window. Just click on the database you want and
a new directory will be created.
If there are any registered procedures in the current database, they will appear in this
window. You can edit an existing entry by clicking on its hyper-text link. You can create
a new entry by selecting a procedure name from the list that follows. You
can also create a new entry by editing one of the registered procedures and clicking on the
COPY button.
Clicking on the hyper-text link of a registered procedure will do one of two things: If
the procedure name is unique--in other words, it appears in the CRON table only once--,
selecting that procedure will take you to the detail edit for that procedure. If the
procedure name is not unique, a summary window is invoked sorted by E-Mail address which
displays the parameters passed to each invocation. Simply find the one you want to edit
and click on its hyper-text link.
UPDATE appears if this procedure has already been registered. You can change any
values on this form (except the procedure name) and modify this entry by clicking
on this button.
CREATE appears if this procedure has not been registered. That is, you selected a
procedure name from the directory window that was not followed by a ROW_ID. Use
this button to add a entry to the CRON Table.
Use the DELETE button to remove an entry from the CRON table.
The COPY button duplicates the current entry. You can then change one or
more columns and press CREATE to add a new entry, leaving the original
untouched.
The REPORT button will generate a report of all entries in the CRON Table.
It will also generate a hyper-text link for each procedure that, when clicked,
will allow you edit the entries for that procedure.
This report will also make sure that information in the CRON table is valid. This
includes checking that your procedure actually exists, that parameter names to this
procedure are still valid, and whether or not the URLEncoded form of some parameters
do not exceed 255 characters. Any errors in this regard are displayed in red and
the summary at the bottom of this page will reflect these errors.
The REPORT button only reports on registered procedures in the current database.
The GROUPS button will generate a report of all entries in the GROUPS Table.
It will also generate a hyper-text link for each group name that, when clicked,
will allow you to edit the entries in that group.
If an E-Mail address appears to be a group name, a hyper-text link is also
created for that group name that may be similarly edited.
The GROUP (or alias) editor displays 10 entries from this table at a time. An
entry is deleted by simply setting that field to NULL. Clicking on the buttons
SAVE, NEXT, or PREV will update the current page (regardless of whether you've
added or deleted an entry) and perform the required action.
If you scroll to the end (or more quickly click on PREV from page 1), you will
see one or more fields for adding new addresses to this group. You may specify
any E-Mail address, and if that address also exists in PDS, the employee
corresponding to the employee will be shown as well.
The RELOAD button rebuilds your directory window. This is convenient when you
have deleted or added a procedure.
The first thing this procedure does it look for any TIMESTAMPs in table GROUPS that
are in a NULL state. A NULL value for TIMESTAMP in any entry in table GROUPS means
that the alias file (/etc/aliases) needs to be rewritten. If this is the case, a
current list of aliases is returned to Sybercron.
If any procedures are ready for execution, its next TIMESTAMP is calculated and updated,
and the run statement for this procedure is built. If for some reason the execution
of this procedure should fail or an error result was returned by Sybase, it will not
be re-executed until its next scheduled date is reached.
Sybercron was written before Sybernet was multi-tasking. This meant that Sybercron would
distribute tasks among the available servers. Sybercron now takes advantage of Sybernet's
multi-tasking ability and will initiate as many tasks as there are connections available.
Whereas the load used to be distributed, Sybercron now initiates tasks from the same port
that Sybercron is suppose to listen at.
The previous limit for the number of asynchronous tasks initiated by Sybercron was 5 (the
number of servers minus one). The current limit is now the maximum number of connections
minus the number of active connections minus one. During peek periods, the average number
of user connections (per server) is between 20 and 30. During unpeak periods, Sybercron
now has the ability to execute about 60 tasks simultaneously.
Sybercron resides in your cgi-bin directory and recognizes the following command line
arguments:
Username is your Sybase username. If not specified, the current value for
LOGINNAME (an environment variable) is used.
Password is your Sybase password. If not specified, it will be prompted from
stdin.
Hostname is the name of your Sybase data server. Your DSQUERY environment
variable will be used if not specified.
Identity corresponds to PLATFORM in the CRON
table. This option makes it possible to run Sybercron from several different
UNIX hosts. The default value for Identity is SPOCK.
seconds determines the number of seconds between each iteration. That is,
Sybercron calls sp_html_cron successfully until there is nothing left
to do, then it waits for the number of seconds specifed by seconds.
The default is 300 seconds (or 5 minutes) between iterations.
If seconds is 0, Sybercron will exit after processing the first batch.
This make it possible to call this program from another application; for
example, you may prefer to use the UNIX cron facility to call Sybercron.
This option allows you to specify the starting socket number of the Sybernet server.
Normally, Sybercron gets this information from the configuration file. To allow
Sybercron to run without interrupting or impacting real users, you may wish to
dedicate one or more servers for this facility.
The -D option turns on debugging. This writes all output destined for the
log file to stdout as well.
This option starts Sybercron with defaults for all of the above.
If a procedure is ready to execute, its run statement is returned and submitted
for execution as a separate, asynchronous process. Sybercron will continue to
call sp_html_cron until there are no more procedures ready to run.
C programs, on the other hand, are executed in the main thread. Future calls to
sp_html_cron will not occur until that program has exited.
After all procedures ready for execution have been submitted, Sybercron sleeps
until the next iteration.
The safest way to terminate Sybercron is by sending a -QUIT signal; for
example,
GROUPTYPE helps Sybercron determine how to interpret E-Mail addresses in the GROUPS
table. If specified as "Y", Sybercron will recurse on each E-Mail address in the
CRON_GROUPS table, invoking the specified procedure once for each E-Mail address.
Pretend that the next three procedures have been registered with a GROUPTYPE of
Y. These procedures will be executed once for each E-Mail address
in the GROUPS table, and that E-Mail address is also passed to these procedures.
The E-Mail address passed to these procedures determines a range of orgcodes that
this user is allowed see.
Note: This method of sending reports (however cool) is very insecure!
sp_print is a stored procedure in sybsystemprocs that allows you to create a disk file and
then print that file to a true printer device. It does all of this in one procedure call.
Here is the prototype of sp_print:
SHELLSCRIPT is the name of the shell script that will print
the output result of your stored procedure. You may write your own shell script
or use one of the scripts already provided for this purpose:
FILENAME is the name of the disk file that is created. If not
specified, a unique filename will be invented.
DEVICENAME must be a valid device name from the table
CRON_DEVICENAMES in the http database. Currently, the following
device names are recognized:
All of the above scripts will remove your file as soon as it has been
scheduled to print with lpr. LANDSCAPE.csh and
PORTRAIT.csh are available on KIRK
only.
The procedure that actually creates the HTML would need two parameters:
BUTTON which tells it what to do and EMPLNO
which tells it who to do it to.
A cursor, a while loop, and a call to sp_print is about all you will need to
accomplish this:
Waiting on the ROW_ID returned from sp_print will
wait for the completion status of the stored procedure. It does not
wait on the completion status of HTML2PS.csh, however.
While useful in its own right, sp_print is also a great example on how to
perform multiple tasks with Sybercron.
sp_Syberscript in the http database is a stored procedure that invokes a shell
script. Simply register this procedure and pass the name of your script and
any parameters to the parameters of this procedure. Sybercron will schedule it
for repeated execution just like any other stored procedure.
The prototype for sp_sendmail is as follows:
The prototype for sp_writetape is as follows:
This procedure can be used to save and restore permissions on any object
in your database. It was specifically designed for restoring permissions
on a stored procedure after it has been dropped and recreated, but can
also be used on any object.
Normally, permissions in the database are maintained by Dorothy Sloma
This means she will both grant and revoke permissions as requests are made.
When a programmer makes a change to a stored procedure, the procedure must
be dropped before it can be recreated. Dropping a procedure means
you lose all permissions on this object. When the permissions are
not restored, this makes Dorothy extremely unhappy (not to mention the
user who wants to execute this application). sp_permissions was designed
to eliminate this problem.
Here is the prototype for sp_permissions:
create procedure sp_permissions
BUTTON is one of SAVE or RESTORE.
SAVE causes the current permissions to be captured.
RESTORE applies those permissions back again.
OBJECTNAME is the name of this object in your database.
In your script that recreates a stored procedure you would invoke this
procedure at the beginning of your script to save this procedure's permissions
and at the end of your script to restore them.
If your procedure does not compile, you do not need to do anything special.
The next time you call sp_permissions with BUTTON=SAVE,
the procedure will detect that your procedure does not exist and will hold
on to the last permissions that were valid.
The test on object_id is not required. If your procedure did not
compile, sp_permissions will know this and not do anything.
Note too sp_permissions calls sp_cron_wait to wait for Sybercron to
complete. It then displays the complete list of users or groups who
have been granted execute permission on your stored procedure.
This problem has been corrected.
It is interesting to note that this particular bug has only of late become problematic. There
are now more tasks being initiated and the chances that two or more finished at the same
time has simply aggravated the situation.
This problem has been corrected.
If you have not guessed, only Sybercron attempts to connect, issue a command
and create e-mail in one fell swoop.
This problem has been corrected.
sp_cron_insert
sp_cron_insert is a stored procedure that allows you to create valid entires in the CRON
table. Its use is encouraged over inserting entries in the CRON table directly.
exec sp_cron_insert
@PROCNAME = "http.dbo.sp_html_xmas"
, @EMAIL = "nospam@nospams.com"
, @DATENAME = "DECEMBER"
, @DAY = "25"
, @HOUR = "8"
The next example runs sp_html_who every Monday at noon. This example also specifies both
a STARTTIME and STOPTIME that limits the execution of this procedure for the year 1997
only.
exec sp_cron_insert
@PROCNAME = "http.dbo.sp_html_who"
, @EMAIL = "nospam@nospams.com"
, @STARTTIME = "JANUARY 1, 1997"
, @STOPTIME = "DECEMBER 31, 1997"
, @DATENAME = "MONDAY"
, @HOUR = "12"
The next example runs the same procedure every day at 8:45 AM. Notice that in this
example TIMESTAMP is specified (and not calculated automatically). This allows us to run
the procedure immediately (assuming TIMESTAMP is less than or equal to getdate()).
exec sp_cron_insert
@PROCNAME = "http.dbo.sp_html_who"
, @EMAIL = "nospam@nospams.com"
, @TIMESTAMP = "December 24, 1996"
, @DATENAME = "DAY"
, @HOUR = "8"
, @MINUTE = "45"
PROCNAME may also be a UNIX executeable or interpreter file.
Sybercron distinguishes these names from stored procedure because they begin with either a period (.)
or a slash (/); for example to
execute the C program HelloWorld in your cgi-bin directory you could
use the following statement:
exec sp_cron_insert
@PROCNAME = "./HelloWorld" -- A C program
, @SCRIPTNAME = "../htdocs/datafile" -- required
Notice that SCRIPTNAME was specified in this example. Sybercron will not execute any
procedures or C programs unless you specify either an E-Mail address (EMAIL) or a file
name (SCRIPTNAME). Specifying an E-Mail address doesn't make any sense in this example
because executing a C program and sending mail are mutually exclusive. You could argue,
I supppose, that the output from stdout should be mailed to the specified address, but
this is not how it works. If you want to send mail in your C program, call sendmail. begin transaction
exec @ROW_ID = http..sp_cron_insert
@PROCNAME = "./Syberload" -- The built-in function Syberload.
, @SCRIPTNAME = "/dev/null" -- I need to give it some name
, @PLATFORM = "SPOCK" -- From where should this be executed.
if @ROW_ID != -1
insert http..CRON_PARAMETERS
(
ROW_ID
, NAME
, VALUE
)
values
(
@ROW_ID
, "arg1"
, "/home/denis/sybase/scriptfile" -- Name of Sybase script file.
)
if @ROW_ID != -1
insert http..CRON_PARAMETERS
(
ROW_ID
, NAME
, VALUE
)
values
(
@ROW_ID
, "arg2"
, "nospam@nospams.com" -- An e-mail address or filename for sending the results to.
)
if @ROW_ID != -1
insert http..CRON_PARAMETERS
(
ROW_ID
, NAME
, VALUE
)
values
(
@ROW_ID
, "arg3"
, "text/html" -- Content-type (if arg2 is an e-mail address).
)
if @ROW_ID != -1
insert http..CRON_PARAMETERS
(
ROW_ID
, NAME
, VALUE
)
values
(
@ROW_ID
, "arg4"
, "Here are your results" -- Subject of e-mail (if arg2 is an e-mail address).
)
commit transaction
return @ROW_ID -- Success if > -1.
It is important to specify an explicit path and filename when executing scripts in this fashion
because you do not know the path where Sybercron is executing from. Permissions are important
too; if Sybercron cannot read this file, it will be unable to execute this command.sp_cron_insert_parameter
Inserts into the CRON table have always been discouraged while inserts into CRON_PARAMETERS
was the only method available to pass parameters to your stored procedure or script. This
procedure performs that ability. The advantage is that sp_cron_insert_parameter will update
the VALUE part for the same NAME and
ROW_ID rather than creating a new row. The disadvantage
is that execute statements are not as flexible as insert statements; for example, it is not
possible to create string expressions when calling a stored procedure. exec sp_cron_insert_parameter
@ROW_ID = @ROW_ID
, @NAME = "EMPLID"
, @VALUE = substring(user_name(),2,5)
While tempting, such a construct is not allowed. Instead, you will need to create a
temporary variable for VALUE: declare @VALUE varchar(30)
select @VALUE = substring(user_name(),2,5)
exec sp_cron_insert_parameter
@ROW_ID = @ROW_ID
, @NAME = "EMPLID"
, @VALUE = @VALUE
If the call is successful, sp_cron_insert_parameter returns ROW_ID; otherwise,
-1 is returned.sp_cron_wait
Sybercron is inherently an asynchronous operation. You call Sybercron (whether
directly by calling sp_cron_insert or with the Sybercron Register which also
calls sp_cron_insert) and then wait for it to do its thing. declare @ROW_ID int
declare @RESULT int
begin transaction
exec @ROW_ID = http..sp_cron_insert
@PROCNAME = "./shell2.csh"
, @PLATFORM = "SPOCK"
, @SENDER = "nospam@nospams.com"
, @EMAIL = "nospam@nospams.com"
if ( @ROW_ID != -1 )
exec @ROW_ID = http..sp_cron_insert_parameter
@ROW_ID
, "argv1"
, "nospam@nospams.com"
if ( @ROW_ID != -1 )
exec @ROW_ID = http..sp_cron_insert_parameter
@ROW_ID
, "argv2"
, "ade-lj4"
if ( @ROW_ID != -1 )
commit transaction
else
rollback transaction
exec @RESULT = http..sp_cron_wait @ROW_ID
if @RESULT >= 0
select "Success! Your job completed successfully!"
else
select "Oops! Your job failed!"
Note that if you pass an invalid ROW_ID to sp_cron_wait, that ROW_ID will be
returned back. In the example above, if the insert into CRON or CRON_PARAMETERS
failed, sp_cron_wait would have returned -1.Example
A more practical use of this facility might be used to control a batch job
initiated from Sybercron; for example, suppose you wanted to execute 3 stored
procedures. The first two could be run asynchronously, but the third is
dependent upon the successful completion of the first two. Here is how you would
do that:
exec @X1 = http..sp_cron_insert @PROCNAME = "sp_task_1"
exec @X2 = http..sp_cron_insert @PROCNAME = "sp_task_2"
exec @R1 = http..sp_cron_wait @X1
exec @R2 = http..sp_cron_wait @X2
if ( @R1 >= 0 and @R2 >=0 )
exec sp_task_3
Some of the "details" have been omitted, but you get the idea.Sybercron Register
sp_html_cron_register is a form-based utility that you may use to register your procedure
in the CRON table. This procedure provides a convenient and safe way to add entries since
it too calls sp_cron_insert to make sure that the columns specified are valid.The Directory Window
The Directory Window contains a list of hypertext links of all procedures in your database.
This list is sorted by name and grouped by owner.The Input Window
The Input Window is where you register your procedure. You need to select a procedure name
from the Directory Window before it can be registered. That name should appear on the input
form. The fields on this form are described above. The buttons on this form correspond to
the following functions:
Except for the RELOAD button which updates the directory window, all results are
sent to the input window.The Output Window
The Output Window shows the results of any changes you've made including any error
messages. If a procedure was successfully registered, its next execution date will
be displayed.sp_html_cron
sp_html_cron is called on a regular bases from UNIX, currently every 5 minutes. This
procedures scans the CRON table looking for procedures that should be executed. This
procedure uses a Better Late Than Never approach in this determination.Sybercron
Sybercron is a UNIX daemon that periodically looks in Sybase for
things to do. It does this by executing the procedure sp_html_cron.
The results of this procedure will determine if
/etc/aliases needs to be rewritten or a stored procedure is ready to execute. As long
as any non-OK result is returned, Sybercron will continue to call this procedure
until there are no more procedures to execute.
After successfully logging on to Sybase, Sybercron calls sp_html_cron. If the
table CRON_GROUPS has been modified since it was last called, that information is
returned and Sybercron will rewrite the alias file (/etc/aliases).
More Examples
Group Type
So far all of these examples addressed the problem of executing a stored procedure whose
output is sent to one or more E-Mail address, but this only works when the output of
that procedure is the same for each user. In practice, this may not be the case because
each recipient should get a report tailored just for them or, more precisely, their
E-Mail address.sp_html_envelope_1
create procedure sp_html_envelope_1(@EMAIL_ADDRESS varchar(255) = NULL)
as
declare
@ts_dt varchar(10) -- (current) week ending date
, @org_id varchar(10) -- org id
declare orgs cursor for select
select org_id
from http.dbo.CRON_EMAILS
, deltek.deltek.USER_REPORTING_PRIVILEGE
where NAME = login_name and ADDRESS = @EMAIL_ADDRESS
/*
** Get the current week ending date
*/
select @ts_dt = convert(varchar,dateadd(weekday,-datepart(weekday,getdate())-7,getdate()),101)
/*
** Step through our cursor for each org I can see and run report.
*/
open orgs
fetch orgs into @org_id
if @@sqlstatus = 2
begin
select '<HTML>'
select '<BODY>'
select '<H2>I''m sorry...</H2>'
select 'You are not listed to receive any Sold Time reports.<P>'
if exists(select * from http.dbo.CRON_EMAILS where ADDRESS = @EMAIL_ADDRESS)
begin
select 'Although your E-Mail address and username in Sybase is valid, '
select 'you have not been granted access to see any orgs.<P>'
end else
begin
select 'You must have a valid username in Sybase that maps to your '
select 'E-Mail address. This is not the case so no reports can be '
select 'created.<P>'
end
select '</BODY>'
select '</HTML>'
end
while @@sqlstatus = 0
begin
exec http.dbo.run_sold_time_report @org_id, @ts_dt
fetch orgs into @org_id
end
close orgs
deallocate cursor orgs
return
sp_html_envelope_1 simply executes Sold_Time_Report for each orgcode that is allowed
for this user. The result is one E-Mail message containing those reports.sp_html_envelope_2
create procedure sp_html_envelope_2(@EMAIL_ADDRESS varchar(255) = NULL)
as
declare
@ts_dt varchar(10) -- (current) week ending date
, @org_id varchar(10) -- org id
, @ROW_ID int -- ROW_ID from insert.
declare orgs cursor for
select org_id
from http.dbo.CRON_EMAILS
, deltek.deltek.USER_REPORTING_PRIVILEGE
where NAME = login_name and ADDRESS = @EMAIL_ADDRESS
/*
** Get the current week ending date
*/
select @ts_dt = convert(varchar,dateadd(weekday,-datepart(weekday,getdate())-7,getdate()),101)
select '<HTML>'
select '<HEAD><TITLE>Sold Time Report Scheduler</TITLE></HEAD>'
select '<BODY>'
/*
** Step through our cursor for each org I can see and run report.
*/
open orgs
fetch orgs into @org_id
if @@sqlstatus = 2
begin
select '<H1>I''m sorry...</H1>'
select 'You are not listed to receive any reports.<P>'
if exists(select * from http.dbo.CRON_EMAILS where ADDRESS = @EMAIL_ADDRESS)
begin
select 'Although your E-Mail address and username in Sybase is valid, '
select 'you have not been granted access to see any orgs.<P>'
end else
begin
select 'You must have a valid username in Sybase that maps to your '
select 'E-Mail address. This is not the case so no reports can be '
select 'created.<P>'
end
end else
begin
select '<H2>Your Sold Time Reports are being scheduled now.</H2>'
select '<OL>'
end
while @@sqlstatus = 0
begin
exec @ROW_ID = http.dbo.sp_cron_insert
@PROCNAME = "http.dbo.run_sold_time_report" -- name of procedure
, @EMAIL = @EMAIL_ADDRESS -- where it goes
/*
** And put the parameters in the CRON_PARAMETERS table.
*/
if ( @ROW_ID != -1 )
exec @ROW_ID = http..cron_insert_parameters
@ROW_ID = @ROW_ID
, @NAME = "org_id"
, @VALUE = @org_id
if ( @ROW_ID != -1 )
exec @ROW_ID = http..cron_insert_parameters
@ROW_ID = @ROW_ID
, @NAME = "ts_dt"
, @VALUE = @ts_dt
select '<LI>Org ID ' + @org_id + ' (' + @ts_dt + ')'
fetch orgs into @org_id
end
close orgs
deallocate cursor orgs
select '</OL>'
select '</BODY>'
select '</HTML>'
return
sp_html_enevlope_2 causes each report to be delivered as a separate E-Mail message. It
does this by creating an entry in the CRON table that is submitted for immediate execution
and deleted from the CRON table after it has been submitted.sp_html_envelope_3
create procedure sp_html_envelope_3(@EMAIL_ADDRESS varchar(255) = NULL)
as
declare
@ts_dt varchar(12) -- (current) week ending date
, @org_id varchar(10) -- org id
, @ROW_ID int -- ROW_ID from insert.
, @SCRIPTNAME varchar(63) -- Output filename.
declare orgs cursor for
select org_id
from http.dbo.CRON_EMAILS
, deltek.deltek.USER_REPORTING_PRIVILEGE
where NAME = login_name and ADDRESS = @EMAIL_ADDRESS
/*
** Get the current week ending date
*/
select @ts_dt = convert(varchar,dateadd(weekday,-datepart(weekday,getdate())-7,getdate()),101)
select '<HTML>'
select '<HEAD><TITLE>Sold Time Report Scheduler</TITLE></HEAD>'
select '<BODY>'
/*
** Step through our cursor for each org I can see and run report.
*/
open orgs
fetch orgs into @org_id
if @@sqlstatus = 2
begin
select '<H1>I''m sorry...</H1>'
select 'You are not listed to receive any reports.<P>'
if exists(select * from http.dbo.CRON_EMAILS where ADDRESS = @EMAIL_ADDRESS)
begin
select 'Although your E-Mail address and username in Sybase is valid, '
select 'you have not been granted access to see any orgs.<P>'
end else
begin
select 'You must have a valid username in Sybase that maps to your '
select 'E-Mail address. This is not the case so no reports can be '
select 'created.<P>'
end
end else
begin
select '<H2>Your Sold Time Reports are being scheduled now.</H2>'
select 'You may select these reported by pointing your browser '
select 'to any of the following URLs.<P>'
select '<UL>'
end
while @@sqlstatus = 0
begin
select @SCRIPTNAME = "../htdocs/" + @EMAIL_ADDRESS + @org_id + '.html'
exec @ROW_ID = http.dbo.sp_cron_insert
@PROCNAME = "http.dbo.run_sold_time_report" -- name of procedure
, @SCRIPTNAME = @SCRIPTNAME -- name of file.
/*
** And put the parameters in the CRON_PARAMETERS table.
*/
if ( @ROW_ID != -1 )
exec @ROW_ID = http..cron_insert_parameters
@ROW_ID = @ROW_ID
, @NAME = "org_id"
, @VALUE = @org_id
if ( @ROW_ID != -1 )
exec @ROW_ID = http..cron_insert_parameters
@ROW_ID = @ROW_ID
, @NAME = "ts_dt"
, @VALUE = @ts_dt
select '<LI><A HREF="HTTP://mis.sri.com/' + @EMAIL_ADDRESS + @org_id + '.html">'
select 'ORG ' + @org_id
select '</A>'
fetch orgs into @org_id
end
close orgs
deallocate cursor orgs
select '</UL>'
select '</BODY>'
select '</HTML>'
return
sp_html_enevelope_3 submits each report for immediate execution. Instead of sending the
output to an E-Mail address, this example directs the output to a disk file. The name of
each file is used to construct a hyper-text link to the location of that file. The user
receives one E-Mail that allows them to pick and choose which report they actually want
to see.
Sybercron Utilities
sp_print
Sybercron is not the easiest process to explain. The fact that it happens behind the scenes
only complicates its explanation. If you are familiar with Sybercron, you know that it can
send e-mail, create files, and run shell scripts, but it is not capable of doing more than
one of these tasks at a time. But it is possible, however, to accomplish this feat by
having Sybercron schedule itself in your stored procedure. sp_print is such a procedure. create procedure sp_print
( @PROCNAME varchar(92) -- This is your stored procedure.
, @PARAM1 varchar(255) = NULL -- 1st unnamed parameter (optional)
, @PARAM2 varchar(255) = NULL -- 2nd unnamed parameter (optional)
, @PARAM3 varchar(255) = NULL -- 3rd unnamed parameter (optional)
, @SHELLSCRIPT varchar(255) = "lpr.csh" -- Name of shell script.
, @FILENAME varchar(255) = NULL -- Name of disk file (optional).
, @DEVICENAME varchar(30) -- Printer name.
, @SENDER varchar(255) -- Your e-mail address.
)
PROCNAME is the name of your stored procedure. This procedure
would either create HTML or plain text. PARAM1, PARAM2 and
PARAM3 are 3 unnamed parameters that are optionally passed
to your stored procedure. Do whatever you want with them.
Note that the html2ps converter is incapable of printing more than about 10 pages.
It is also very sensitive to missing tags in your HTML; for example, omitting the
ending cell tag (</TD>) in an HTML table will cause this routine to fail.
SENDER is your e-mail address. Sybercron and the above
scripts use this name to send e-mail in case your stored procedure fails or
there is something wrong with your print file. This parameter is required.Example
Assume we have a procedure that displays Hello World in HTML:
create procedure sp_HelloWorld
as
select '<HTML>'
, '<BODY BGCOLOR=WHITE>'
, '<H1>Hello World</H1>'
, '</BODY>'
, '</HTML>'
return 0
We can use sp_print to send the output of this procedure to the printer in
AD136 with the following statement: exec sp_print
@PROCNAME = "sp_HelloWorld"
, @SHELLSCRIPT = "HTML2PS.csh"
, @DEVICENAME = "hp5ad136"
, @SENDER = "nospam@nospams.com"
Example
Something like Personal Action Reprints would be a good candidate for this
facility, and since each print file is no more than a couple of pages, the
html2ps converter would be a convenient facility to print these directly
to a printer. create procedure sp_schedule_PA_Reprints (@EFFDT datetime)
as
declare @EMPLID char(12)
declare people cursor for
select EMPLID
from PS_JOB_CURRENT
where EFFDT >= @EFFDT
open people
fetch people into @EMPLID
while @@sqlstatus = 0
begin
exec sp_print
@PROCNAME = "HRPRD.dbo.sp_html_reprint"
, @PARAM1 = "REPORT" -- corresponds to BUTTON.
, @PARAM2 = @EMPLID -- corresponds to EMPLNO.
, @SHELLSCRIPT = "HTML2PS.csh"
, @DEVICENAME = "hp4mv-ad236"
, @SENDER = "yamini@unix.sri.com"
fetch people into @EMPLID
end
close people
deallocate cursor people
return 0
You would want to make certain that BUTTON and
EMPLNO are the first two parameters to your stored
procedure since these values are passed as unnamed string parameters.sp_Syberscript
The Sybercron Register only has the ability to schedule stored procedures. Until
now, it has not been possible to register shell scripts because those are not
stored procedures.Example
You can also call sp_Syberscript from a stored
procedure. This is a convenient way to run a script without worrying about
all the rules when calling sp_cron_insert. create procedure sp_StartScript
as
exec sp_Syberscript
@SHELLSCRIPT = "./updateDirectoryServer.csh"
, @PLATFORM = "SPOCK"
, @ARG1 = "ldif.update"
, @ARG2 = "ldif.result"
select '<HTML>'
, '<BODY BGCOLOR=WHITE>'
, '<H1>Your shell script has been started!</H1>'
, '</BODY>'
, '</HTML>'
return 0
This example simply runs the shell script called updateDirectoryServer.csh
on SPOCK and passes two parameters to it. sp_Syberscript calls sp_cron_insert
and exits immediately with the ROW_ID returned by that
procedure; it does not wait for the script to complete. You can
wait yourself, however, by calling sp_cron_wait.sp_sendmail
sp_sendmail provides a convenient mechanism for sending a "simple" e-mail
message. Most of the time you will probably need something more elaborate
than what is provided here, but for those instances when one or two lines
will suffice, sp_sendmail will do the job. create procedure sp_sendmail
( @SUBJECT varchar(255) -- Subject:
, @TO varchar(255) -- To:
, @FROM varchar(255) -- From:
, @MESSAGE varchar(255) -- Body:
, @CONTENTTYPE varchar(30) = "text/plain" -- text/plain or text/html.
, @TIMESTAMP datetime = NULL -- When to deliver (NULL if now).
)
The first four parameters should be obvious enough. CONTENTTYPE
can be either "text/plain" or "text/html." Use the latter if you want to send
HTML in your MESSAGE. TIMESTAMP allows
you to defer the delivery of your e-mail message.Example
The following example sends a "simple" plain-text message to myself: exec sp_sendmail
@FROM = "nospam@nospams.com"
, @TO = "nospam@nospams.com"
, @SUBJECT = "This is some mail from sp_sendmail"
, @MESSAGE = "Can you read this?"
sp_writetape
sp_writetape sends e-mail to operators@unix.sri.com and gives them instructions
for creating a tape. Sybercron certainly has the ability to run a shell script
that calls writetape, but operator intervention is required to mount a tape.
Sending e-mail is the safest solution. create procedure sp_writetape
( @SHELLSCRIPT varchar(255) -- Name of shell script.
, @SENDER varchar(64) -- Your e-mail address.
)
SHELLSCRIPT is the name of the shell script that the
operator is to execute, and SENDER is your e-mail address
so Sybercron can send you mail in the event of failure or the operator can
send you mail when the tape has successfully been created.Example
The following example is how the Vision Service Plan tape is created: exec sp_writetape
@SHELLSCRIPT = "/usr/local/home/operator/vsptape.csh"
, @SENDER = "kenneth.bailey@sri.com"
The stored procedure that invokes this command does so after creating a disk
file with Sybercron. The rest is up to the operator who receives the following
e-mail: Subject: PLEASE HANG SCRATCH TAPE ON ASTRO TO WRITE
From: kenneth.bailey@sri.com
To: operators@unix.sri.com
Please mount a scratch tape on Astro to write!
Instructions:
1. Mount a scratch tape and note the serial number.
2. /usr/local/home/operator/vsptape.csh BXXXXX
where BXXXXX is the serial number of the tape.
Then please send me a reply saying the tape was successfully written.
Thanks from kenneth.bailey@sri.com.
The specified shell script uses writetape to write the tape. Note that the
return status from writetape is interrogated, and the operator is instructed
to restart this script if writing to the tape fails: #!/bin/csh
# $1 serialno
if ( $1 == "" ) then
echo usage: $0 serialno
echo Error: serialno expected
exit 1
endif
cd /Sybernet
#
# Initialize globals...
#
set email = kenneth.bailey@sri.com
set LABELTYPE = standard
set SERIALNO = $1
set MAXRECSIZE = 242
set BLOCKSIZE = 242
set UNITS = characters
set EXTMODE = ebcdic
set INTMODE = ascii
set VID = SRI
set FILENAME = /Sybernet/document/vsptape.out
umask 0
set PROMPT = "nothing"
echo ""
echo "#PLEASE MOUNT SCRATCH TAPE ["$SERIALNO"] THEN ENTER OK TO TO GO"
read $PROMPT
echo "#WRITING "$FILENAME" TO TAPE..."
/usr/local/bin/writetape \
-LABELTYPE=$LABELTYPE \
-SERIALNO=$SERIALNO \
-MAXRECSIZE=$MAXRECSIZE \
-BLOCKSIZE=$BLOCKSIZE \
-UNITS=$UNITS \
-EXTMODE=$EXTMODE \
-INTMODE=$INTMODE \
-V=$VID \
$FILENAME
if ( $status == "0" ) then
echo ""
echo "*******************************************************"
echo " SUCCESS"
echo "*******************************************************"
echo ""
/usr/ucb/mail -s 'Tape was successfully created' $email < /dev/null
else
echo ""
echo "********************************************************"
echo " WARNING - TAPE NOT CREATED"
echo "********************************************************"
echo ""
echo "#PLEASE RESTART IF PROBLEM WAS WITH TAPE DEVICE"
echo ""
/usr/ucb/mail -s 'OOPS - tape not created' $email < /dev/null
endif
sp_permissions
(
@BUTTON varchar(30)
, @OBJECTNAME varchar(92)
)
Example
use HRPRD
go
exec sp_permissions @BUTTON = "SAVE", @OBJECTNAME = "sp_html_example"
go
drop procedure sp_html_example
go
create procedure sp_html_example
as
/*
** Main body of procedure.
*/
return 0
go
if object_id("sp_html_example") != NULL
begin
select "<BR>Restoring permissions:<P>"
select "<SEND_PARTIAL>"
exec sp_permissions @BUTTON = "RESTORE", @OBJECTNAME = "sp_html_example"
end
go
Sybercron Tables
Program Notes
Deadlocks
Sybercron would sometimes cause a deadlock situation when updating the table CRON_HISTORY. This
resulted in your stored procedure failing to execute, and instead of delivering the output results
of your stored procedure, the user would get a message saying that they were chosen as a dead-lock
victim and should attempt to re-run your stored procedure.Zombies
When one or more tasks completed at the same time, Sybercron would sometimes fail to recognize
that all had finished and other tasks could be initiated. In some cases, Sybercron would not
initiate any tasks until it was restarted. Other times, Sybercron might run only one task at a
time.Empty Files
If a request to Sybernet attempted to connect a user, issue a command, and
send mail or create a disk file all in one fell swoop, Sybernet would accidently
create a zero-length file in /var/tmp. Previously, this error could go as long
as 6 months before this directory needed to be purged. With the addition of the
online PSR's, this problem as been aggravated with the
numerous e-mail messages sent every Monday morning.
Sybernet is a trademark of SRI International.
Copyright © 1996-1999 SRI International. All Rights Reserved.
Denis D. Workman / http://Sybernet.sri.com/