--- /dev/null
+diff -Nur autofs-4.1.3.orig/daemon/automount.c autofs-4.1.3/daemon/automount.c
+--- autofs-4.1.3.orig/daemon/automount.c 2004-04-05 21:14:10.000000000 +0800
++++ autofs-4.1.3/daemon/automount.c 2004-06-05 21:13:28.000000000 +0800
+@@ -99,8 +99,11 @@
+
+ if (stat(buf, &st) == 0 && !S_ISDIR(st.st_mode))
+ errno = ENOTDIR;
+- else
+- continue;
++ else {
++ /* last component, return -1 */
++ if (*cp != '\0')
++ continue;
++ }
+ }
+ return -1;
+ }
+@@ -1088,9 +1091,11 @@
+ close(ap.state_pipe[0]);
+ close(ap.state_pipe[1]);
+
++ chdir(ap.path);
+ err = ap.lookup->lookup_mount(ap.path,
+ pkt->name, pkt->len,
+ ap.lookup->context);
++ chdir("/");
+
+ /*
+ * If at first you don't succeed, hide all
+@@ -1163,8 +1168,11 @@
+ it.
+ */
+
++ chdir(ap.path);
+ ret = ap.lookup->lookup_mount(ap.path,
+ name, namelen, ap.lookup->context);
++ chdir("/");
++
+ if (ret)
+ error("failed to recover from partial expiry of %s\n",
+ buf);
+diff -Nur autofs-4.1.3.orig/modules/mount_bind.c autofs-4.1.3/modules/mount_bind.c
+--- autofs-4.1.3.orig/modules/mount_bind.c 2004-05-10 20:44:30.000000000 +0800
++++ autofs-4.1.3/modules/mount_bind.c 2004-06-05 18:12:38.000000000 +0800
+@@ -107,15 +107,19 @@
+ fullpath[i] = '\0';
+
+ if (bind_works) {
+- int status;
++ int status, existed = 1;
+
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
+
+- if ((status = mkdir_path(fullpath, 0555)) && errno != EEXIST) {
++ status = mkdir_path(fullpath, 0555);
++ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
+
++ if (!status)
++ existed = 0;
++
+ if (is_mounted(fullpath)) {
+ warn("BUG: %s already mounted", fullpath);
+ return 0;
+@@ -130,7 +134,7 @@
+ unlink(AUTOFS_LOCK);
+
+ if (err) {
+- if (!ap.ghost && name_len)
++ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
+ return 1;
+ } else {
+diff -Nur autofs-4.1.3.orig/modules/mount_changer.c autofs-4.1.3/modules/mount_changer.c
+--- autofs-4.1.3.orig/modules/mount_changer.c 2004-05-10 20:44:30.000000000 +0800
++++ autofs-4.1.3/modules/mount_changer.c 2004-06-05 18:18:04.000000000 +0800
+@@ -52,7 +52,7 @@
+ {
+ char *fullpath;
+ int err;
+- int status;
++ int status, existed = 1;
+
+ fstype = "iso9660";
+
+@@ -80,11 +80,15 @@
+
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
+
+- if ((status = mkdir_path(fullpath, 0555)) && errno != EEXIST) {
++ status = mkdir_path(fullpath, 0555);
++ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
+
++ if (!status)
++ existed = 0;
++
+ debug(MODPREFIX "Swapping CD to slot %s", name);
+
+ err = swapCD(what, name);
+@@ -111,7 +115,7 @@
+ unlink(AUTOFS_LOCK);
+
+ if (err) {
+- if (!ap.ghost && name_len)
++ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
+
+ error(MODPREFIX "failed to mount %s (type %s) on %s",
+diff -Nur autofs-4.1.3.orig/modules/mount_ext2.c autofs-4.1.3/modules/mount_ext2.c
+--- autofs-4.1.3.orig/modules/mount_ext2.c 2004-05-10 20:44:30.000000000 +0800
++++ autofs-4.1.3/modules/mount_ext2.c 2004-06-05 18:23:09.000000000 +0800
+@@ -40,7 +40,6 @@
+ return 0;
+ }
+
+-
+ int mount_mount(const char *root, const char *name, int name_len,
+ const char *what, const char *fstype, const char *options, void *context)
+ {
+@@ -48,7 +47,7 @@
+ const char *p, *p1;
+ int err, ro = 0;
+ const char *fsck_prog;
+- int status;
++ int status, existed = 1;
+
+ fullpath = alloca(strlen(root) + name_len + 2);
+ if (!fullpath) {
+@@ -63,11 +62,15 @@
+
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
+
+- if ((status = mkdir_path(fullpath, 0555)) && errno != EEXIST) {
++ status = mkdir_path(fullpath, 0555);
++ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
+
++ if (!status)
++ existed = 0;
++
+ if (is_mounted(fullpath)) {
+ error("BUG: %s already mounted", fullpath);
+ return 0;
+@@ -120,7 +123,7 @@
+ unlink(AUTOFS_LOCK);
+
+ if (err) {
+- if (!ap.ghost && name_len)
++ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
+ error(MODPREFIX "failed to mount %s (type %s) on %s",
+ what, fstype, fullpath);
+diff -Nur autofs-4.1.3.orig/modules/mount_generic.c autofs-4.1.3/modules/mount_generic.c
+--- autofs-4.1.3.orig/modules/mount_generic.c 2004-05-10 20:44:30.000000000 +0800
++++ autofs-4.1.3/modules/mount_generic.c 2004-06-05 18:22:10.000000000 +0800
+@@ -46,7 +46,7 @@
+ {
+ char *fullpath;
+ int err;
+- int status;
++ int status, existed = 1;
+
+ fullpath = alloca(strlen(root) + name_len + 2);
+ if (!fullpath) {
+@@ -61,11 +61,15 @@
+
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
+
+- if ((status = mkdir_path(fullpath, 0555)) && errno != EEXIST) {
++ status = mkdir_path(fullpath, 0555);
++ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
+
++ if (!status)
++ existed = 0;
++
+ if (is_mounted(fullpath)) {
+ error("BUG: %s already mounted", fullpath);
+ return 0;
+@@ -89,7 +93,7 @@
+ unlink(AUTOFS_LOCK);
+
+ if (err) {
+- if (!ap.ghost && name_len)
++ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
+
+ error(MODPREFIX "failed to mount %s (type %s) on %s",
+diff -Nur autofs-4.1.3.orig/modules/mount_nfs.c autofs-4.1.3/modules/mount_nfs.c
+--- autofs-4.1.3.orig/modules/mount_nfs.c 2004-06-05 14:24:58.000000000 +0800
++++ autofs-4.1.3/modules/mount_nfs.c 2004-06-05 21:10:17.000000000 +0800
+@@ -445,14 +445,19 @@
+ whatstr, "bind", NULL, mount_bind->context);
+ } else {
+ /* Not a local host - do an NFS mount */
+- int status;
++ int status, existed = 1;
+
+ debug(MODPREFIX "calling mkdir_path %s", fullpath);
+- if ((status = mkdir_path(fullpath, 0555)) && errno != EEXIST) {
++
++ status = mkdir_path(fullpath, 0555);
++ if (status && errno != EEXIST) {
+ error(MODPREFIX "mkdir_path %s failed: %m", fullpath);
+ return 1;
+ }
+
++ if (!status)
++ existed = 0;
++
+ if (is_mounted(fullpath)) {
+ error("BUG: %s already mounted", fullpath);
+ return 0;
+@@ -477,8 +482,9 @@
+ unlink(AUTOFS_LOCK);
+
+ if (err) {
+- if (!ap.ghost && name_len)
++ if ((!ap.ghost && name_len) || !existed)
+ rmdir_path(name);
++
+ error(MODPREFIX "nfs: mount failure %s on %s",
+ whatstr, fullpath);
+ return 1;
--- /dev/null
+--- autofs-4.1.3.orig/include/automount.h 2004-05-18 20:20:08.000000000 +0800
++++ autofs-4.1.3/include/automount.h 2004-06-05 16:26:39.000000000 +0800
+@@ -36,7 +36,7 @@
+
+ #define DEFAULT_TIMEOUT (5*60) /* 5 minutes */
+ #define AUTOFS_LOCK "/var/lock/autofs" /* To serialize access to mount */
+-#define MOUNTED_LOCK "_PATH_MOUNTED~" /* mounts' lock file */
++#define MOUNTED_LOCK _PATH_MOUNTED "~" /* mounts' lock file */
+ #define MTAB_NOTUPDATED 0x1000 /* mtab succeded but not updated */
+ #define NOT_MOUNTED 0x0100 /* path notmounted */
+
--- /dev/null
+diff -Nur autofs-4.1.3.orig/lib/rpc_subs.c autofs-4.1.3/lib/rpc_subs.c
+--- autofs-4.1.3.orig/lib/rpc_subs.c 2004-06-14 21:55:29.000000000 +0800
++++ autofs-4.1.3/lib/rpc_subs.c 2004-06-14 21:54:35.000000000 +0800
+@@ -1,38 +1,284 @@
++/* ----------------------------------------------------------------------- *
++ *
++ * rpc_subs.c - routines for rpc discovery
++ *
++ * Copyright 2004 Ian Kent <raven@themaw.net> - All Rights Reserved
++ * Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
++ * USA; either version 2 of the License, or (at your option) any later
++ * version; incorporated herein by reference.
++ *
++ * ----------------------------------------------------------------------- */
++
+ #include <rpc/rpc.h>
++#include <rpc/pmap_prot.h>
+ #include <nfs/nfs.h>
+ #include <linux/nfs2.h>
+ #include <linux/nfs3.h>
+ #include <rpc/xdr.h>
+-
++
++#include <unistd.h>
++#include <sys/socket.h>
++#include <netdb.h>
++#include <netinet/in.h>
++#include <sys/fcntl.h>
++#include <errno.h>
++
+ #include "automount.h"
+
++#define PMAP_TOUT_UDP 2
++#define PMAP_TOUT_TCP 3
++
++struct conn_info {
++ const char *host;
++ unsigned short port;
++ unsigned long program;
++ unsigned long version;
++ struct protoent *proto;
++ unsigned int send_sz;
++ unsigned int recv_sz;
++ struct timeval timeout;
++};
++
++/*
++ * Create a UDP RPC client
++ */
++static CLIENT* create_udp_client(struct conn_info *info)
++{
++ int fd = -1;
++ CLIENT *client;
++ struct sockaddr_in addr;
++ struct hostent *hp;
++
++ if (info->proto->p_proto != IPPROTO_UDP)
++ return NULL;
++
++ memset(&addr, 0, sizeof(addr));
++
++ hp = gethostbyname(info->host);
++ if (!hp)
++ return NULL;
++
++ addr.sin_family = AF_INET;
++ addr.sin_port = htons(info->port);
++ memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
++
++ client = clntudp_bufcreate(&addr,
++ info->program, info->version,
++ info->timeout, &fd,
++ info->send_sz, info->recv_sz);
++
++ return client;
++}
++
++/*
++ * Perform a non-blocking connect on the socket fd.
++ *
++ * tout contains the timeout. It will be modified to contain the time
++ * remaining (i.e. time provided - time elasped).
++ */
++static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
++{
++ int flags, ret, len;
++ fd_set wset, rset;
++
++ flags = fcntl(fd, F_GETFL, 0);
++ if (flags < 0)
++ return -1;
++
++ ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
++ if (ret < 0)
++ return -1;
++
++ /*
++ * From here on subsequent sys calls could change errno so
++ * we set ret = -errno to capture it in case we decide to
++ * use it later.
++ */
++ ret = connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr));
++ if (ret < 0 && errno != EINPROGRESS) {
++ ret = -errno;
++ goto done;
++ }
++
++ if (ret == 0)
++ goto done;
++
++ /* now wait */
++ FD_ZERO(&rset);
++ FD_SET(fd, &rset);
++ wset = rset;
++
++ ret = select(fd + 1, &rset, &wset, NULL, tout);
++ if (ret <= 0) {
++ if (ret == 0)
++ ret = -ETIMEDOUT;
++ else
++ ret = -errno;
++ goto done;
++ }
++
++ if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
++ int stat;
++
++ len = sizeof(ret);
++ stat = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
++ if (stat < 0) {
++ ret = -errno;
++ goto done;
++ }
++
++ /* Oops - something wrong with connect */
++ if (ret)
++ ret = -ret;
++ }
++
++done:
++ fcntl(fd, F_SETFL, flags);
++ return ret;
++}
++
++/*
++ * Create a TCP RPC client using non-blocking connect
++ */
++static CLIENT* create_tcp_client(struct conn_info *info)
++{
++ int fd;
++ CLIENT *client;
++ struct sockaddr_in addr;
++ struct hostent *hp;
++ int ret;
++
++ if (info->proto->p_proto != IPPROTO_TCP)
++ return NULL;
++
++ memset(&addr, 0, sizeof(addr));
++
++ hp = gethostbyname(info->host);
++ if (!hp)
++ return NULL;
++
++ addr.sin_family = AF_INET;
++ addr.sin_port = htons(info->port);
++ memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
++
++ fd = socket(PF_INET, SOCK_STREAM, info->proto->p_proto);
++ if (fd < 0)
++ return NULL;
++
++ ret = connect_nb(fd, &addr, &info->timeout);
++ if (ret < 0)
++ goto out_close;
++
++ client = clnttcp_create(&addr,
++ info->program, info->version, &fd,
++ info->send_sz, info->recv_sz);
++ if (!client)
++ goto out_close;
++
++ return client;
++
++out_close:
++ close(fd);
++ return NULL;
++}
++
++static unsigned short portmap_getport(struct conn_info *info)
++{
++ struct conn_info pmap_info;
++ unsigned short port = 0;
++ CLIENT *client;
++ enum clnt_stat stat;
++ struct pmap parms;
++
++ pmap_info.host = info->host;
++ pmap_info.port = PMAPPORT;
++ pmap_info.program = PMAPPROG;
++ pmap_info.version = PMAPVERS;
++ pmap_info.proto = info->proto;
++ pmap_info.send_sz = RPCSMALLMSGSIZE;
++ pmap_info.recv_sz = RPCSMALLMSGSIZE;
++ pmap_info.timeout.tv_sec = PMAP_TOUT_UDP;
++ pmap_info.timeout.tv_usec = 0;
++
++ if (info->proto->p_proto == IPPROTO_TCP) {
++ pmap_info.timeout.tv_sec = PMAP_TOUT_TCP;
++ client = create_tcp_client(&pmap_info);
++ } else
++ client = create_udp_client(&pmap_info);
++
++ if (!client)
++ return 0;
++
++ parms.pm_prog = info->program;
++ parms.pm_vers = info->version;
++ parms.pm_prot = info->proto->p_proto;
++ parms.pm_port = 0;
++
++ stat = clnt_call(client, PMAPPROC_GETPORT,
++ (xdrproc_t) xdr_pmap, (caddr_t) &parms,
++ (xdrproc_t) xdr_u_short, (caddr_t) &port,
++ pmap_info.timeout);
++
++ clnt_destroy(client);
++
++ if (stat != RPC_SUCCESS)
++ return 0;
++
++ return port;
++}
++
+ static int rpc_ping_proto(const char *host,
+- unsigned long nfs_version, const char *proto,
++ unsigned long nfs_version,
++ const char *proto,
+ long seconds, long micros)
+ {
++ struct conn_info info;
+ CLIENT *client;
+- struct timeval tout;
+ enum clnt_stat stat;
++ struct protoent *prot;
++
++ prot = getprotobyname(proto);
++ if (!prot)
++ return 1;
++
++ info.host = host;
++ info.program = NFS_PROGRAM;
++ info.version = nfs_version;
++ info.proto = prot;
++ info.send_sz = 0;
++ info.recv_sz = 0;
++ info.timeout.tv_sec = seconds;
++ info.timeout.tv_usec = micros;
+
+- client = clnt_create(host, NFS_PROGRAM, nfs_version, proto);
+- if (client == NULL) {
++ info.port = portmap_getport(&info);
++ if (!info.port)
+ return 0;
+- }
+
+- tout.tv_sec = seconds;
+- tout.tv_usec = micros;
++ if (prot->p_proto == IPPROTO_UDP) {
++ info.send_sz = UDPMSGSIZE;
++ info.recv_sz = UDPMSGSIZE;
++ client = create_udp_client(&info);
++ } else
++ client = create_tcp_client(&info);
++
++ if (!client)
++ return 0;
+
+- clnt_control(client, CLSET_TIMEOUT, (char *)&tout);
+- clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&tout);
++ clnt_control(client, CLSET_TIMEOUT, (char *) &info.timeout);
++ clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info.timeout);
+
+ stat = clnt_call(client, NFSPROC_NULL,
+- (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, tout);
++ (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
++ info.timeout);
+
+ clnt_destroy(client);
+
+- if (stat != RPC_SUCCESS) {
++ if (stat != RPC_SUCCESS)
+ return 0;
+- }
+
+ return 1;
+ }
+@@ -108,10 +354,39 @@
+
+ taken = elapsed(start, end);
+
+- if (result != NULL) {
++ if (result != NULL)
+ *result = taken;
+- }
+
+ return status;
+ }
+
++#if 0
++#include <stdio.h>
++
++int main(int argc, char **argv)
++{
++ int ret;
++ double res = 0.0;
++
++ ret = rpc_ping("budgie", 10, 0);
++ printf("ret = %d\n", ret);
++
++ res = 0.0;
++ ret = rpc_time("raven", NFS2_VERSION, RPC_PING_TCP, 10, 0, &res);
++ printf("v2 tcp ret = %d, res = %f\n", ret, res);
++
++ res = 0.0;
++ ret = rpc_time("raven", NFS3_VERSION, RPC_PING_TCP, 10, 0, &res);
++ printf("v3 tcp ret = %d, res = %f\n", ret, res);
++
++ res = 0.0;
++ ret = rpc_time("raven", NFS2_VERSION, RPC_PING_UDP, 10, 0, &res);
++ printf("v2 udp ret = %d, res = %f\n", ret, res);
++
++ res = 0.0;
++ ret = rpc_time("raven", NFS3_VERSION, RPC_PING_UDP, 10, 0, &res);
++ printf("v3 udp ret = %d, res = %f\n", ret, res);
++
++ exit(0);
++}
++#endif
--- /dev/null
+--- autofs-4.1.3/daemon/automount.c.orig 2004-08-18 11:23:49.430470256 -0400
++++ autofs-4.1.3/daemon/automount.c 2004-08-18 11:24:45.047015256 -0400
+@@ -848,10 +848,10 @@ static int st_prepare_shutdown(void)
+ alarm(0);
+
+ /* Prevent any new mounts */
+- ap.state = ST_SHUTDOWN_PENDING;
+-
+ sigprocmask(SIG_SETMASK, &lock_sigs, NULL);
+
++ ap.state = ST_SHUTDOWN_PENDING;
++
+ /* Unmount everything */
+ exp = expire_proc(1);
+
+@@ -919,8 +919,8 @@ static int st_expire(void)
+ return 1;
+
+ case EXP_STARTED:
+- ap.state = ST_EXPIRE;
+ sigprocmask(SIG_SETMASK, &ready_sigs, NULL);
++ ap.state = ST_EXPIRE;
+ return 0;
+ }
+ return 1;
--- /dev/null
+--- autofs-4.1.3-devel/lib/rpc_subs.c~ 2004-08-04 13:20:30.000000000 -0400
++++ autofs-4.1.3-devel/lib/rpc_subs.c 2004-08-18 13:37:14.123571936 -0400
+@@ -34,6 +34,7 @@
+
+ struct conn_info {
+ const char *host;
++ int fd;
+ unsigned short port;
+ unsigned long program;
+ unsigned long version;
+@@ -48,7 +49,6 @@ struct conn_info {
+ */
+ static CLIENT* create_udp_client(struct conn_info *info)
+ {
+- int fd = -1;
+ CLIENT *client;
+ struct sockaddr_in addr;
+ struct hostent *hp;
+@@ -62,13 +62,14 @@ static CLIENT* create_udp_client(struct
+ if (!hp)
+ return NULL;
+
++ info->fd = RPC_ANYSOCK;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(info->port);
+ memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
+
+ client = clntudp_bufcreate(&addr,
+ info->program, info->version,
+- info->timeout, &fd,
++ info->timeout, &info->fd,
+ info->send_sz, info->recv_sz);
+
+ return client;
+@@ -169,6 +170,7 @@ static CLIENT* create_tcp_client(struct
+ if (!client)
+ goto out_close;
+
++ info->fd = fd;
+ return client;
+
+ out_close:
+@@ -214,6 +216,7 @@ static unsigned short portmap_getport(st
+ pmap_info.timeout);
+
+ clnt_destroy(client);
++ close(pmap_info.fd);
+
+ if (stat != RPC_SUCCESS)
+ return 0;
--- /dev/null
+
+Problem: infinite error loop occurs when trying to access non-exitent
+ directory.
+
+This patch, for 4.1.3, fixes the problem caused when the default for
+multi-mounts was changed from strict to non-strict. This change tickled
+a bug in the old autofs4 kernel module found in 2.4 kernels and 2.6
+kernels to date (ie. < 2.6.7).
+
+This change in default caused a small change in mount logic which went
+unnoticed and lead to this problem. So the kernel interaction problem
+remains but is much less likely to occur. If this problem persists
+after applying this patch then update your kernel autofs4.
+
+The patch restores the previous logic but leaves the new default.
+
+diff -Nur autofs-4.1.3.orig/modules/parse_sun.c autofs-4.1.3/modules/parse_sun.c
+--- autofs-4.1.3.orig/modules/parse_sun.c 2004-05-18 20:22:40.000000000 +0800
++++ autofs-4.1.3/modules/parse_sun.c 2004-05-29 15:38:42.000000000 +0800
+@@ -602,10 +602,8 @@
+ options);
+ }
+
+- if (nonstrict && rv) {
+- debug("ignoring failure of non-strict mount");
+- return 0;
+- }
++ if (nonstrict && rv)
++ return -rv;
+
+ return rv;
+ }
+@@ -746,7 +744,11 @@
+ free(loc);
+ free(myoptions);
+
+- if (rv)
++ /* Convert non-strict failure into success */
++ if (rv < 0) {
++ rv = 0;
++ debug("parse_mount: ignoring failure of non-strict mount");
++ } else if (rv > 0)
+ break;
+
+ } while (*p == '/');
+@@ -789,6 +791,10 @@
+ options, loclen, loc);
+
+ rv = sun_mount(root, name, name_len, loc, loclen, options);
++ /* non-strict failure to normal failure for ordinary mount */
++ if (rv < 0)
++ rv = -rv;
++
+ free(loc);
+ free(options);
+ }