huntstop.sas
/*
* Richard A. DeVenezia, 4/7/95
*
* Hunt out users who have a lock on a dataset and
* stop their SAS processes from accessing the SAS server
* Also, send them e-mail that they were stopped.
*
* mod
* 5/22/95 rad Change all X commands to be filename PIPEs to
* ensure memory problems do not occur.
* (X forks with a full process copy, while filename PIPEs
* fork with a minimum process copy (see Observations 1st Q 1995.)
* 5/17/99 rad add dfltsrvr and hostlist at top
*/
%* These must be filled in for your situation;
%let DFLTSRVR=HOST.SAS-SHARE-SERVICE-NAME;
%let HOSTLIST=HOST HOST2 HOST3 HOST4; %* hosts from which users connect to Share server;
*******************************************************************************;
%macro showuser (USERID, SERVER=&DFLTSRVR);
proc operate server=&SERVER;
display user &USERID;
run;
%mend;
*******************************************************************************;
%macro stopuser (USERID, UNIXID, DSN, SERVER=&DFLTSRVR);
proc operate server=&SERVER;
stop user &USERID;
run;
* now e-mail a message to the user who was stopped;
*-----------------------------------------------------------;
* find out if a list of mail addresses needs to be made;
%local rc;
%let rc=0;
filename TEST pipe 'test -r /tmp/log-mail.address; echo $?';
data _null_;
infile TEST;
input rc $;
call symput ('rc', rc);
run;
filename TEST;
%if &rc ^= 0 %then %do;
%* do not have a mailing address file, need to create one;
data _null_;
* write a script, mail.who, to look at all the host cpus and users;
* and create a user to mailing address cross-reference file,
* mail.address;
file '/tmp/log-mail.who';
put 'echo getting addresses `date +%c` >> /tmp/log-getaddress.log';
put "hosts=""&HOSTLIST""";
put "for host in $hosts";
put "do";
put " remsh $host cat /etc/passwd \";
put " | cut -d':' -f1 \";
put " | awk '{print $1"" ""$1""@xxxxxx""}' \";
put " | sed s/xxxxxx/$host/ \";
put " | grep -v '^\+' \";
put " | grep -v '^\#' \";
put " | grep -v uucp \";
put " | grep -v lp \";
put " | grep -v tftp \";
put " ";
put "done";
stop;
run;
%* run the script by using a filename pipe that is touched within
%* a data null;
filename GETADDR pipe
'chmod +x /tmp/log-mail.who; /tmp/log-mail.who > /tmp/log-mail.address';
data _null_;
infile GETADDR;
stop;
run;
filename GETADDR;
%end;
%* search the addresses for the user being stopped;
%let UNIXID=%lowcase(&UNIXID);
%* remove previous mail notification script;
filename RMNOTIFY pipe
'rm -f /tmp/log-notify';
data _null_;
infile RMNOTIFY;
stop;
run;
filename RMNOTIFY;
%* send a notification message to each unix acccount
%* that apparently matches the user id returned by proc operate ;
data _null_;
infile "/tmp/log-mail.address" end=EOF;
length unixid $40 mailaddr $100 ;
do while ("&UNIXID" ^= unixid and not EOF);
input unixid mailaddr;
end;
file '/tmp/log-stopmail.lst' mod;
date=date();
time=time();
put date mmddyy8. +1 time time8. " stopuserid=&UNIXID " unixid= mailaddr=;
* put _infile_;
* put '---';
file '/tmp/log-notify';
if unixid = "&UNIXID" then do;
put "echo ""You had &DSN open.";
put "You were disconnected from SAS server '&SERVER'";
put "so a data update could occur."" \";
put "| mailx -s 'SAS server disconnect' " mailaddr;
put ;
put "echo ""&UNIXID stopped for &DSN at `date +" '%c' '`" \';
put "| mailx -s '&UNIXID stopped for &DSN' root";
end;
stop;
run;
filename SENDMAIL pipe "chmod +x /tmp/log-notify; /tmp/log-notify";
data _null_;
infile SENDMAIL;
stop;
run;
filename SENDMAIL;
%mend;
*******************************************************************************;
%macro huntstop (DSN, SERVER=&DFLTSRVR);
%local LINESIZE NOTES MPRINT SOURCE CENTER LOG;
data _null_;
set SASHELP.VOPTION;
if OPTNAME in ('LINESIZE' 'NOTES' 'MPRINT' 'SOURCE' 'CENTER') then
call symput (OPTNAME, trim(SETTING));
run;
* Note: setting ls to less than 130 could result in improper parsing
* of lock information output from lock statement and proc operate;
options ls=130 nonotes nocenter ; *nomprint nosource;
*options notes source mprint mlogic symbolgen;
%let LIB=%upcase(%scan(&DSN,1,.));
%let DS =%upcase(%scan(&DSN,2,.));
*---------------------------------------------------------------------------;
* stop any user that has a LOCK on the dataset (locked by LOCK statement);
*---------------------------------------------------------------------------;
* make a timestamp;
data _null_;
length t $6;
t = compress (put (time(), time8.), ': ');
if length(t) = 5 then t = '0' || t;
call symput ('log', '/tmp/log-operate.log.'
|| put (date(),yymmdd6.) || '_' || t);
run;
*---------------------------------------------------------------------------;
* output lock list to log file;
proc printto log="&log." new;
run;
LOCK &LIB..&DS LIST;
proc printto log=log;
run;
*---------------------------------------------------------------------------;
* parse log file for lock info, write stopuser macro invocation
* to temporary file that is %included (call EXECUTE seemed to have
* problems with scope);
filename LOCK pipe "grep &LIB.\.&DS &log";
filename STOPUSER '/tmp/log-stopuser.sas';
data _null_;
infile LOCK length=len;
file STOPUSER;
length line command $200 unixid $40;
input line $varying. len;
p = index (line, 'server connection');
if p then do;
* userid is the nnnnn part of SAS Share connection TINnnnnn.user;
userid = scan (substr(line,p),3,' )');
p = index (line, ' by');
unixid = scan (substr(line,p),2);
command = '%STOPUSER ('
|| trim(userid) || ','
|| trim(unixid) || ','
|| "&LIB..&DS,"
|| "server=&SERVER);";
put command;
end;
run;
%include STOPUSER;
filename LOCK;
filename STOPUSER;
*---------------------------------------------------------------------------;
* stop users that have locks on the dataset;
* (locked by other than LOCK statement);
*---------------------------------------------------------------------------;
* make a timestamp;
data _null_;
length t $6;
t = compress (put (time(), time8.), ': ');
if length(t) = 5 then t = '0' || t;
call symput ('log', '/tmp/log-operate.log.'
|| put (date(),yymmdd6.) || '_' || t);
run;
*---------------------------------------------------------------------------;
* output library list to log file (contains info about locked datasets);
proc printto log="&log." new;
run;
proc operate server=&SERVER;
display lib &LIB;
run;
proc printto log=log;
run;
*---------------------------------------------------------------------------;
* parse log file for lock info;
*---------------------------------------------------------------------------;
* write an awk program to strip out the datasets portion of
* proc operate display output;
data _null_;
file '/tmp/log-_lock_.awk';
length beg_tag end_tag $200;
beg_tag = """These data sets in library &LIB are active""";
end_tag = """==========================""";
put '{';
put 'if (!ok && index($0,' beg_tag ')) ok=1;';
put 'if (ok && index($0,' end_tag ')) ok=0;';
put 'if (ok) print $0';
put '}';
run;
filename LOCK pipe "awk -f /tmp/log-_lock_.awk &log.";
filename STOPUSER '/tmp/log-stopuser.sas';
data _null_;
infile LOCK missover;
file STOPUSER;
length member type status $8 userid unixid $50 openmode $8 libref $20;
length command $200;
input member type status userid openmode libref;
retain doCheck 0;
if member = '--------' then do;
doCheck=1;
return;
end;
if doCheck;
if member = "&DS" and type = "DATA" then do;
* stop user that has lock on dataset;
* userid is formatted like TINnnnnn.user;
* have to extract nnnnn part;
unixid = scan (userid,2,'.');
userid = scan (userid,1,'.');
userid = substr (userid,4);
command = '%STOPUSER ('
|| trim(userid) || ','
|| trim(unixid) || ','
|| "&LIB..&DS,"
|| "server=&SERVER);";
put command;
end;
run;
%include STOPUSER;
filename LOCK;
filename STOPUSER;
filename CLEANUP pipe 'rm -f /tmp/log-_lock_.awk /tmp/log-stopuser.sas';
filename CLEANUP pipe ' ';
data _null_;
infile CLEANUP;
stop;
run;
filename CLEANUP;
options LS=&LINESIZE &NOTES &MPRINT &SOURCE &CENTER;
%mend;