📄 mci.c
字号:
errno = save_errno;
return;
}
/*
** MCI_TRAVERSE_PERSISTENT -- walk persistent status tree
**
** Recursively find all the mci host files in `pathname'. Default to
** main host status directory if no path is provided.
** Call (*action)(pathname, host) for each file found.
**
** Note: all information is collected in a list before it is processed.
** This may not be the best way to do it, but it seems safest, since
** the file system would be touched while we are attempting to traverse
** the directory tree otherwise (during purges).
**
** Parameters:
** action -- function to call on each node. If returns < 0,
** return immediately.
** pathname -- root of tree. If null, use main host status
** directory.
**
** Returns:
** < 0 -- if any action routine returns a negative value, that
** value is returned.
** 0 -- if we successfully went to completion.
** > 0 -- return status from action()
*/
int
mci_traverse_persistent(action, pathname)
int (*action)();
char *pathname;
{
struct stat statbuf;
DIR *d;
int ret;
if (pathname == NULL)
pathname = HostStatDir;
if (pathname == NULL)
return -1;
if (tTd(56, 1))
dprintf("mci_traverse: pathname is %s\n", pathname);
ret = stat(pathname, &statbuf);
if (ret < 0)
{
if (tTd(56, 2))
dprintf("mci_traverse: Failed to stat %s: %s\n",
pathname, errstring(errno));
return ret;
}
if (S_ISDIR(statbuf.st_mode))
{
struct dirent *e;
char *newptr;
char newpath[MAXPATHLEN + 1];
bool leftone, removedone;
if ((d = opendir(pathname)) == NULL)
{
if (tTd(56, 2))
dprintf("mci_traverse: opendir %s: %s\n",
pathname, errstring(errno));
return -1;
}
if (strlen(pathname) >= sizeof newpath - MAXNAMLEN - 3)
{
if (tTd(56, 2))
dprintf("mci_traverse: path \"%s\" too long",
pathname);
return -1;
}
(void) strlcpy(newpath, pathname, sizeof newpath);
newptr = newpath + strlen(newpath);
*newptr++ = '/';
/*
** repeat until no file has been removed
** this may become ugly when several files "expire"
** during these loops, but it's better than doing
** a rewinddir() inside the inner loop
*/
do
{
leftone = removedone = FALSE;
while ((e = readdir(d)) != NULL)
{
if (e->d_name[0] == '.')
continue;
(void) strlcpy(newptr, e->d_name,
sizeof newpath -
(newptr - newpath));
ret = mci_traverse_persistent(action, newpath);
if (ret < 0)
break;
if (ret == 1)
leftone = TRUE;
if (!removedone && ret == 0 &&
action == mci_purge_persistent)
removedone = TRUE;
}
if (ret < 0)
break;
/*
** The following appears to be
** necessary during purges, since
** we modify the directory structure
*/
if (removedone)
rewinddir(d);
if (tTd(56, 40))
dprintf("mci_traverse: path %s: ret %d removed %d left %d\n",
pathname, ret, removedone, leftone);
} while (removedone);
/* purge (or whatever) the directory proper */
if (!leftone)
{
*--newptr = '\0';
ret = (*action)(newpath, NULL);
}
(void) closedir(d);
}
else if (S_ISREG(statbuf.st_mode))
{
char *end = pathname + strlen(pathname) - 1;
char *start;
char *scan;
char host[MAXHOSTNAMELEN];
char *hostptr = host;
/*
** Reconstruct the host name from the path to the
** persistent information.
*/
do
{
if (hostptr != host)
*(hostptr++) = '.';
start = end;
while (*(start - 1) != '/')
start--;
if (*end == '.')
end--;
for (scan = start; scan <= end; scan++)
*(hostptr++) = *scan;
end = start - 2;
} while (*end == '.');
*hostptr = '\0';
/*
** Do something with the file containing the persistent
** information.
*/
ret = (*action)(pathname, host);
}
return ret;
}
/*
** MCI_PRINT_PERSISTENT -- print persistent info
**
** Dump the persistent information in the file 'pathname'
**
** Parameters:
** pathname -- the pathname to the status file.
** hostname -- the corresponding host name.
**
** Returns:
** 0
*/
int
mci_print_persistent(pathname, hostname)
char *pathname;
char *hostname;
{
static int initflag = FALSE;
FILE *fp;
int width = Verbose ? 78 : 25;
bool locked;
MCI mcib;
/* skip directories */
if (hostname == NULL)
return 0;
if (!initflag)
{
initflag = TRUE;
printf(" -------------- Hostname --------------- How long ago ---------Results---------\n");
}
fp = safefopen(pathname, O_RDWR, FileMode,
SFF_NOLOCK|SFF_NOLINK|SFF_OPENASROOT|SFF_REGONLY|SFF_SAFEDIRPATH);
if (fp == NULL)
{
if (tTd(56, 1))
dprintf("mci_print_persistent: cannot open %s: %s\n",
pathname, errstring(errno));
return 0;
}
FileName = pathname;
memset(&mcib, '\0', sizeof mcib);
if (mci_read_persistent(fp, &mcib) < 0)
{
syserr("%s: could not read status file", pathname);
(void) fclose(fp);
FileName = NULL;
return 0;
}
locked = !lockfile(fileno(fp), pathname, "", LOCK_EX|LOCK_NB);
(void) fclose(fp);
FileName = NULL;
printf("%c%-39s %12s ",
locked ? '*' : ' ', hostname,
pintvl(curtime() - mcib.mci_lastuse, TRUE));
if (mcib.mci_rstatus != NULL)
printf("%.*s\n", width, mcib.mci_rstatus);
else if (mcib.mci_exitstat == EX_TEMPFAIL && mcib.mci_errno != 0)
printf("Deferred: %.*s\n", width - 10, errstring(mcib.mci_errno));
else if (mcib.mci_exitstat != 0)
{
int i = mcib.mci_exitstat - EX__BASE;
extern int N_SysEx;
extern char *SysExMsg[];
if (i < 0 || i >= N_SysEx)
{
char buf[80];
snprintf(buf, sizeof buf, "Unknown mailer error %d",
mcib.mci_exitstat);
printf("%.*s\n", width, buf);
}
else
printf("%.*s\n", width, &(SysExMsg[i])[5]);
}
else if (mcib.mci_errno == 0)
printf("OK\n");
else
printf("OK: %.*s\n", width - 4, errstring(mcib.mci_errno));
return 0;
}
/*
** MCI_PURGE_PERSISTENT -- Remove a persistence status file.
**
** Parameters:
** pathname -- path to the status file.
** hostname -- name of host corresponding to that file.
** NULL if this is a directory (domain).
**
** Returns:
** 0 -- ok
** 1 -- file not deleted (too young, incorrect format)
** < 0 -- some error occurred
*/
int
mci_purge_persistent(pathname, hostname)
char *pathname;
char *hostname;
{
struct stat statbuf;
char *end = pathname + strlen(pathname) - 1;
int ret;
if (tTd(56, 1))
dprintf("mci_purge_persistent: purging %s\n", pathname);
ret = stat(pathname, &statbuf);
if (ret < 0)
{
if (tTd(56, 2))
dprintf("mci_purge_persistent: Failed to stat %s: %s\n",
pathname, errstring(errno));
return ret;
}
if (curtime() - statbuf.st_mtime < MciInfoTimeout)
return 1;
if (hostname != NULL)
{
/* remove the file */
if (unlink(pathname) < 0)
{
if (tTd(56, 2))
dprintf("mci_purge_persistent: failed to unlink %s: %s\n",
pathname, errstring(errno));
}
}
else
{
/* remove the directory */
if (*end != '.')
return 1;
if (tTd(56, 1))
dprintf("mci_purge_persistent: dpurge %s\n", pathname);
if (rmdir(pathname) < 0)
{
if (tTd(56, 2))
dprintf("mci_purge_persistent: rmdir %s: %s\n",
pathname, errstring(errno));
}
}
return 0;
}
/*
** MCI_GENERATE_PERSISTENT_PATH -- generate path from hostname
**
** Given `host', convert from a.b.c to $QueueDir/.hoststat/c./b./a,
** putting the result into `path'. if `createflag' is set, intervening
** directories will be created as needed.
**
** Parameters:
** host -- host name to convert from.
** path -- place to store result.
** pathlen -- length of path buffer.
** createflag -- if set, create intervening directories as
** needed.
**
** Returns:
** 0 -- success
** -1 -- failure
*/
static int
mci_generate_persistent_path(host, path, pathlen, createflag)
const char *host;
char *path;
int pathlen;
bool createflag;
{
char *elem, *p, *x, ch;
int ret = 0;
int len;
char t_host[MAXHOSTNAMELEN];
#if NETINET6
struct in6_addr in6_addr;
#endif /* NETINET6 */
/*
** Rationality check the arguments.
*/
if (host == NULL)
{
syserr("mci_generate_persistent_path: null host");
return -1;
}
if (path == NULL)
{
syserr("mci_generate_persistent_path: null path");
return -1;
}
if (tTd(56, 80))
dprintf("mci_generate_persistent_path(%s): ", host);
if (*host == '\0' || *host == '.')
return -1;
/* make certain this is not a bracketed host number */
if (strlen(host) > sizeof t_host - 1)
return -1;
if (host[0] == '[')
(void) strlcpy(t_host, host + 1, sizeof t_host);
else
(void) strlcpy(t_host, host, sizeof t_host);
/*
** Delete any trailing dots from the hostname.
** Leave 'elem' pointing at the \0.
*/
elem = t_host + strlen(t_host);
while (elem > t_host &&
(elem[-1] == '.' || (host[0] == '[' && elem[-1] == ']')))
*--elem = '\0';
#if NETINET || NETINET6
/* check for bogus bracketed address */
if (host[0] == '[' &&
# if NETINET6
inet_pton(AF_INET6, t_host, &in6_addr) != 1 &&
# endif /* NETINET6 */
# if NETINET
inet_addr(t_host) == INADDR_NONE
# endif /* NETINET */
)
return -1;
#endif /* NETINET || NETINET6 */
/* check for what will be the final length of the path */
len = strlen(HostStatDir) + 2;
for (p = (char *) t_host; *p != '\0'; p++)
{
if (*p == '.')
len++;
len++;
if (p[0] == '.' && p[1] == '.')
return -1;
}
if (len > pathlen || len < 1)
return -1;
(void) strlcpy(path, HostStatDir, pathlen);
p = path + strlen(path);
while (elem > t_host)
{
if (!path_is_dir(path, createflag))
{
ret = -1;
break;
}
elem--;
while (elem >= t_host && *elem != '.')
elem--;
*p++ = '/';
x = elem + 1;
while ((ch = *x++) != '\0' && ch != '.')
{
if (isascii(ch) && isupper(ch))
ch = tolower(ch);
if (ch == '/')
ch = ':'; /* / -> : */
*p++ = ch;
}
if (elem >= t_host)
*p++ = '.';
*p = '\0';
}
if (tTd(56, 80))
{
if (ret < 0)
dprintf("FAILURE %d\n", ret);
else
dprintf("SUCCESS %s\n", path);
}
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -