1
0
Files
irix-657m-src/eoe/cmd/sun/rpc.lockd/tests/tools/release.c
2022-09-29 17:59:04 +03:00

401 lines
8.1 KiB
C

#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#if defined(_SUNOS) && defined(SVR4)
#include <sys/t_lock.h>
#endif/* _SUNOS */
#include <sys/flock.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <assert.h>
#include <rpc/rpc.h>
#include <rpcsvc/sm_inter.h>
#include <sys/param.h>
#include <string.h>
struct stat_chge {
char *name;
int state;
};
typedef struct stat_chge stat_chge;
#define SM_NOTIFY 6
char *typetostr[] = {
"null",
"F_RDLCK",
"F_WRLCK",
"F_UNLCK",
};
enum option_type {REMOTE, LOCAL, NONE};
enum sysid_format {SYSID_HOSTNAME, SYSID_IPADDRESS, SYSID_NUMERIC, SYSID_NONE};
struct flock Test_fl = {
(short)F_WRLCK, /* l_type */
(short)0, /* l_whence */
(off_t)0, /* l_start */
(off_t)0, /* l_len */
(long)0, /* l_sysid */
(pid_t)0, /* l_pid */
{(long)0, (long)0, (long)0, (long)0} /* l_pad[4] */
};
void
usage(char *progname)
{
fprintf(stderr, "usage: %s [-l sysid,pid] [-r client] file|server\n",
progname);
}
int
is_numeric_string(char *token)
{
int state = 0;
for ( ; *token; token++) {
switch (state) {
case 0:
if (*token == '0') {
state = 2;
} else if (isdigit(*token) || (*token == '+') ||
(*token == '-')) {
state = 1;
} else {
return(0);
}
break;
case 1:
if (!isdigit(*token)) {
return(0);
}
break;
case 2:
if (isdigit(*token) || (*token == 'x') || (*token == 'X')) {
state = 1;
} else {
return(0);
}
break;
case 3:
return(0);
default:
fprintf(stderr, "invalid state %d in is_numeric_string\n",
state);
assert((state > 0) && (state < 4));
}
}
assert((state == 1) || (state == 2));
return(1);
}
int
is_ip_address(char *token)
{
int state = 0;
int dots = 0;
for ( ; *token; token++) {
switch (state) {
case 0:
if (isdigit(*token)) {
state = 1;
} else {
return(0);
}
break;
case 1:
if (isdigit(*token)) {
state = 2;
} else if (*token == '.') {
state = 4;
dots++;
} else {
return(0);
}
break;
case 2:
if (isdigit(*token)) {
state = 3;
} else if (*token == '.') {
state = 4;
dots++;
} else {
return(0);
}
break;
case 3:
if (*token == '.') {
state = 4;
dots++;
} else {
return(0);
}
break;
case 4:
if (isdigit(*token)) {
state = 2;
} else {
return(0);
}
break;
case 5:
return(0);
default:
fprintf(stderr, "invalid state %d in is_ip_address\n", state);
assert((state > 0) && (state < 4));
}
if (dots > 3) {
return(0);
}
}
return(1);
}
enum sysid_format
get_sysid_format(char *token)
{
enum sysid_format format = SYSID_HOSTNAME;
if (is_numeric_string(token)) {
format = SYSID_NUMERIC;
} else if (is_ip_address(token)) {
format = SYSID_IPADDRESS;
}
return(format);
}
xdr_notify(xdrs, ntfp)
XDR *xdrs;
stat_chge *ntfp;
{
if (!xdr_string(xdrs, &ntfp->name, MAXHOSTNAMELEN+1)) {
return(FALSE);
}
if (!xdr_int(xdrs, &ntfp->state)) {
return(FALSE);
}
return(TRUE);
}
int
main(int argc, char **argv)
{
struct in_addr ipaddr;
char *token;
char errbuf[256];
stat_chge ntf;
enum clnt_stat clnt_stat;
int pid;
long sysid;
int error;
char *progname = *argv;
char *file = NULL;
char *host = NULL;
int fd;
struct flock fl;
struct flock temp_fl;
struct hostent *hp;
enum option_type option = NONE;
char *client_name;
int opt;
while ((opt = getopt(argc, argv, "l:r:")) != EOF) {
switch (opt) {
case 'l':
if (option != NONE) {
fprintf(stderr, "%s: only one of -l or -r may be used\n",
progname);
exit(-1);
}
option = LOCAL;
token = strtok(optarg, ", ");
if (!token) {
usage(progname);
exit(-1);
}
switch (get_sysid_format(token)) {
case SYSID_HOSTNAME:
/*
* get the IP address of the host and use that as
* the sysid
*/
hp = gethostbyname(token);
if (!hp) {
#if defined(_SUNOS)
fprintf(stderr, "Host %s unknown\n", token);
#else /* _SUNOS */
herror(token);
#endif /* _SUNOS */
exit(-1);
}
switch (hp->h_addrtype) {
case AF_INET:
sysid = ((struct in_addr *)hp->h_addr)->s_addr;
break;
default:
fprintf(stderr,
"%s: invalid address type %d for host %s\n",
progname, hp->h_addrtype, token);
exit(-1);
}
break;
case SYSID_IPADDRESS:
sysid = inet_addr(token);
break;
case SYSID_NUMERIC:
sysid = strtol(token, NULL, 0);
break;
default:
fprintf(stderr, "%s: sysid must be a host name, "
"IP address, or number\n", progname);
exit(-1);
}
token = strtok(NULL, " ");
if (token) {
pid = IGN_PID;
} else {
pid = atoi(token);
}
break;
case 'r':
if (option != NONE) {
fprintf(stderr, "%s: only one of -l or -r may be used\n",
progname);
exit(-1);
}
client_name = optarg;
option = REMOTE;
break;
default:
usage(progname);
exit(-1);
}
}
if (optind >= argc) {
usage(progname);
exit(-1);
}
switch (option) {
case LOCAL:
/*
* release locks locally for the specified file, sysid, and
* process id
*/
file = argv[optind];
fd = open(file, O_RDWR);
if (fd == -1) {
error = errno;
perror(file);
} else {
bzero(&fl, sizeof(fl));
fl.l_sysid = sysid;
fl.l_type = F_UNLCK;
fl.l_pid = pid;
if (fcntl(fd, F_RSETLK, &fl) == -1) {
error = errno;
perror("Unlock");
} else {
fl.l_type = F_WRLCK;
fl.l_pid = 0;
if (fcntl(fd, F_RGETLK, &fl) == -1) {
error = errno;
perror("Verification");
} else {
if (fl.l_type != F_UNLCK) {
error = EBUSY;
fprintf(stderr, "%s locked: %s %ld %ld %ld %ld\n",
file, typetostr[fl.l_type], fl.l_start,
fl.l_len, fl.l_sysid, (long)fl.l_pid);
}
}
}
close(fd);
}
break;
case REMOTE:
/*
* call the remote statd to release locks for the specified
* client name
*/
ntf.name = client_name;
ntf.state = 0;
clnt_stat = callrpc(argv[optind], SM_PROG, SM_VERS, SM_NOTIFY,
xdr_notify, (void *)&ntf, xdr_void, NULL);
if (clnt_stat != RPC_SUCCESS) {
fprintf(stderr, "SM_NOTIFY %s for %s: %s\n", argv[optind],
client_name, clnt_sperrno(clnt_stat));
}
break;
default:
/*
* release everything
*/
file = argv[optind];
fd = open(file, O_RDWR);
if (fd == -1) {
error = errno;
perror(file);
} else {
/*
* loop until we get an error, a lock fails to be released,
* or no more locks are held for the file
*/
for ( fl = Test_fl;
!fcntl(fd, F_RGETLK, &fl) && (fl.l_type != F_UNLCK);
fl = Test_fl ) {
/*
* fl contains the description of the lock to be
* released, change its type to F_UNLCK and do
* F_RSETLK
*/
fl.l_type = F_UNLCK;
if (fcntl(fd, F_RSETLK, &fl)) {
error = errno;
ipaddr.s_addr = fl.l_sysid;
sprintf(errbuf, "%s F_RSETLK %lld %lld %s %d",
file, fl.l_start, fl.l_len,
fl.l_sysid ? inet_ntoa(ipaddr) : "0",
fl.l_pid);
perror(errbuf);
break;
} else {
/*
* verify that the lock has been released
* there should be no identical lock held
*/
temp_fl = fl;
if (fcntl(fd, F_RGETLK, &temp_fl)) {
error = errno;
ipaddr.s_addr = fl.l_sysid;
sprintf(errbuf, "%s F_RGETLK %lld %lld %s %d",
file, fl.l_start, fl.l_len,
fl.l_sysid ? inet_ntoa(ipaddr) : "0",
fl.l_pid);
perror(errbuf);
break;
} else if (bcmp(&fl, &temp_fl) == 0) {
ipaddr.s_addr = fl.l_sysid;
fprintf(stderr,
"%s: lock %s %lld %lld %s %d still held\n",
file, typetostr[fl.l_type], fl.l_start,
fl.l_len,
fl.l_sysid ? inet_ntoa(ipaddr) : "0",
fl.l_pid);
error = -1;
break;
}
}
}
close(fd);
}
}
return(error);
}