📄 queue.c
字号:
(void) strlcpy(qd, ".", sizeof qd);
(void) strlcpy(qddf, ".", sizeof qddf);
}
else
{
(void) snprintf(qd, sizeof qd, "%s%s",
QPaths[queuedir].qp_name,
(bitset(QP_SUBQF, QPaths[queuedir].qp_subdirs) ? "/qf" : ""));
(void) snprintf(qddf, sizeof qddf, "%s%s",
QPaths[queuedir].qp_name,
(bitset(QP_SUBDF, QPaths[queuedir].qp_subdirs) ? "/df" : ""));
}
/*
** Check for permission to print the queue
*/
if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0)
{
struct stat st;
# ifdef NGROUPS_MAX
int n;
extern GIDSET_T InitialGidSet[NGROUPS_MAX];
# endif /* NGROUPS_MAX */
if (stat(qd, &st) < 0)
{
syserr("Cannot stat %s", qid_printqueue(queuedir));
return 0;
}
# ifdef NGROUPS_MAX
n = NGROUPS_MAX;
while (--n >= 0)
{
if (InitialGidSet[n] == st.st_gid)
break;
}
if (n < 0 && RealGid != st.st_gid)
# else /* NGROUPS_MAX */
if (RealGid != st.st_gid)
# endif /* NGROUPS_MAX */
{
usrerr("510 You are not permitted to see the queue");
setstat(EX_NOPERM);
return 0;
}
}
/*
** Read and order the queue.
*/
nrequests = orderq(queuedir, TRUE);
/*
** Print the work list that we have read.
*/
/* first see if there is anything */
if (nrequests <= 0)
{
printf("%s is empty\n", qid_printqueue(queuedir));
return 0;
}
CurrentLA = sm_getla(NULL); /* get load average */
printf("\t\t%s (%d request%s", qid_printqueue(queuedir), nrequests,
nrequests == 1 ? "" : "s");
if (MaxQueueRun > 0 && nrequests > MaxQueueRun)
printf(", only %d printed", MaxQueueRun);
if (Verbose)
printf(")\n----Q-ID---- --Size-- -Priority- ---Q-Time--- ---------Sender/Recipient--------\n");
else
printf(")\n----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
for (w = WorkQ; w != NULL; w = w->w_next)
{
struct stat st;
auto time_t submittime = 0;
long dfsize;
int flags = 0;
int qfver;
char statmsg[MAXLINE];
char bodytype[MAXNAME + 1];
char qf[MAXPATHLEN];
printf("%12s", w->w_name + 2);
(void) snprintf(qf, sizeof qf, "%s/%s", qd, w->w_name);
f = fopen(qf, "r");
if (f == NULL)
{
printf(" (job completed)\n");
errno = 0;
continue;
}
w->w_name[0] = 'd';
(void) snprintf(qf, sizeof qf, "%s/%s", qddf, w->w_name);
if (stat(qf, &st) >= 0)
dfsize = st.st_size;
else
dfsize = -1;
if (w->w_lock)
printf("*");
else if (w->w_tooyoung)
printf("-");
else if (shouldqueue(w->w_pri, w->w_ctime))
printf("X");
else
printf(" ");
errno = 0;
statmsg[0] = bodytype[0] = '\0';
qfver = 0;
while (fgets(buf, sizeof buf, f) != NULL)
{
register int i;
register char *p;
fixcrlf(buf, TRUE);
switch (buf[0])
{
case 'V': /* queue file version */
qfver = atoi(&buf[1]);
break;
case 'M': /* error message */
if ((i = strlen(&buf[1])) >= sizeof statmsg)
i = sizeof statmsg - 1;
memmove(statmsg, &buf[1], i);
statmsg[i] = '\0';
break;
case 'B': /* body type */
if ((i = strlen(&buf[1])) >= sizeof bodytype)
i = sizeof bodytype - 1;
memmove(bodytype, &buf[1], i);
bodytype[i] = '\0';
break;
case 'S': /* sender name */
if (Verbose)
{
printf("%8ld %10ld%c%.12s ",
dfsize,
w->w_pri,
bitset(EF_WARNING, flags) ? '+' : ' ',
ctime(&submittime) + 4);
prtstr(&buf[1], 78);
}
else
{
printf("%8ld %.16s ", dfsize,
ctime(&submittime));
prtstr(&buf[1], 40);
}
if (statmsg[0] != '\0' || bodytype[0] != '\0')
{
printf("\n %10.10s", bodytype);
if (statmsg[0] != '\0')
printf(" (%.*s)",
Verbose ? 100 : 60,
statmsg);
}
break;
case 'C': /* controlling user */
if (Verbose)
printf("\n\t\t\t\t (---%.74s---)",
&buf[1]);
break;
case 'R': /* recipient name */
p = &buf[1];
if (qfver >= 1)
{
p = strchr(p, ':');
if (p == NULL)
break;
p++;
}
if (Verbose)
{
printf("\n\t\t\t\t\t ");
prtstr(p, 73);
}
else
{
printf("\n\t\t\t\t ");
prtstr(p, 40);
}
break;
case 'T': /* creation time */
submittime = atol(&buf[1]);
break;
case 'F': /* flag bits */
for (p = &buf[1]; *p != '\0'; p++)
{
switch (*p)
{
case 'w':
flags |= EF_WARNING;
break;
}
}
}
}
if (submittime == (time_t) 0)
printf(" (no control file)");
printf("\n");
(void) fclose(f);
}
return nrequests;
}
/*
** QUEUENAME -- build a file name in the queue directory for this envelope.
**
** Parameters:
** e -- envelope to build it in/from.
** type -- the file type, used as the first character
** of the file name.
**
** Returns:
** a pointer to the queue name (in a static buffer).
**
** Side Effects:
** If no id code is already assigned, queuename() will
** assign an id code with assign_queueid(). If no queue
** directory is assigned, one will be set with setnewqueue().
*/
char *
queuename(e, type)
register ENVELOPE *e;
int type;
{
char *sub = "";
static char buf[MAXPATHLEN];
/* Assign an ID if needed */
if (e->e_id == NULL)
assign_queueid(e);
/* Assign a queue directory if needed */
if (e->e_queuedir == NOQDIR)
setnewqueue(e);
if (e->e_queuedir == NOQDIR)
(void) snprintf(buf, sizeof buf, "%cf%s",
type, e->e_id);
else
{
switch (type)
{
case 'd':
if (bitset(QP_SUBDF, QPaths[e->e_queuedir].qp_subdirs))
sub = "/df";
break;
case 'T':
case 't':
case 'Q':
case 'q':
if (bitset(QP_SUBQF, QPaths[e->e_queuedir].qp_subdirs))
sub = "/qf";
break;
case 'x':
if (bitset(QP_SUBXF, QPaths[e->e_queuedir].qp_subdirs))
sub = "/xf";
break;
}
(void) snprintf(buf, sizeof buf, "%s%s/%cf%s",
QPaths[e->e_queuedir].qp_name,
sub, type, e->e_id);
}
if (tTd(7, 2))
dprintf("queuename: %s\n", buf);
return buf;
}
/*
** ASSIGN_QUEUEID -- assign a queue ID for this envelope.
**
** Assigns an id code if one does not already exist.
** This code assumes that nothing will remain in the queue for
** longer than 60 years. It is critical that files with the given
** name not already exist in the queue.
** Also initializes e_queuedir to NOQDIR.
**
** Parameters:
** e -- envelope to set it in.
**
** Returns:
** none.
*/
static char Base60Code[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx";
void
assign_queueid(e)
register ENVELOPE *e;
{
pid_t pid = getpid();
static char cX = 0;
static long random_offset;
struct tm *tm;
char idbuf[MAXQFNAME - 2];
if (e->e_id != NULL)
return;
/* see if we need to get a new base time/pid */
if (cX >= 60 || LastQueueTime == 0 || LastQueuePid != pid)
{
time_t then = LastQueueTime;
/* if the first time through, pick a random offset */
if (LastQueueTime == 0)
random_offset = get_random();
while ((LastQueueTime = curtime()) == then &&
LastQueuePid == pid)
{
(void) sleep(1);
}
LastQueuePid = getpid();
cX = 0;
}
if (tTd(7, 50))
dprintf("assign_queueid: random_offset = %ld (%d)\n",
random_offset, (int)(cX + random_offset) % 60);
tm = gmtime(&LastQueueTime);
idbuf[0] = Base60Code[tm->tm_year % 60];
idbuf[1] = Base60Code[tm->tm_mon];
idbuf[2] = Base60Code[tm->tm_mday];
idbuf[3] = Base60Code[tm->tm_hour];
idbuf[4] = Base60Code[tm->tm_min];
idbuf[5] = Base60Code[tm->tm_sec];
idbuf[6] = Base60Code[((int)cX++ + random_offset) % 60];
(void) snprintf(&idbuf[7], sizeof idbuf - 7, "%05d",
(int) LastQueuePid);
e->e_id = newstr(idbuf);
define('i', e->e_id, e);
e->e_queuedir = NOQDIR;
if (tTd(7, 1))
dprintf("assign_queueid: assigned id %s, e=%lx\n",
e->e_id, (u_long) e);
if (LogLevel > 93)
sm_syslog(LOG_DEBUG, e->e_id, "assigned id");
}
/*
** SYNC_QUEUE_TIME -- Assure exclusive PID in any given second
**
** Make sure one PID can't be used by two processes in any one second.
**
** If the system rotates PIDs fast enough, may get the
** same pid in the same second for two distinct processes.
** This will interfere with the queue file naming system.
**
** Parameters:
** none
**
** Returns:
** none
*/
void
sync_queue_time()
{
# if FAST_PID_RECYCLE
if (OpMode != MD_TEST &&
OpMode != MD_VERIFY &&
LastQueueTime > 0 &&
LastQueuePid == getpid() &&
curtime() == LastQueueTime)
(void) sleep(1);
# endif /* FAST_PID_RECYCLE */
}
/*
** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
**
** Parameters:
** e -- the envelope to unlock.
**
** Returns:
** none
**
** Side Effects:
** unlocks the queue for `e'.
*/
void
unlockqueue(e)
ENVELOPE *e;
{
if (tTd(51, 4))
dprintf("unlockqueue(%s)\n",
e->e_id == NULL ? "NOQUEUE" : e->e_id);
/* if there is a lock file in the envelope, close it */
if (e->e_lockfp != NULL)
(void) fclose(e->e_lockfp);
e->e_lockfp = NULL;
/* don't create a queue id if we don't already have one */
if (e->e_id == NULL)
return;
/* remove the transcript */
if (LogLevel > 87)
sm_syslog(LOG_DEBUG, e->e_id, "unlock");
if (!tTd(51, 104))
xunlink(queuename(e, 'x'));
}
/*
** SETCTLUSER -- create a controlling address
**
** Create a fake "address" given only a local login name; this is
** used as a "controlling user" for future recipient addresses.
**
** Parameters:
** user -- the user name of the controlling user.
** qfver -- the version stamp of this qf file.
**
** Returns:
** An address descriptor for the controlling user.
**
** Side Effects:
** none.
*/
static ADDRESS *
setctluser(user, qfver)
char *user;
int qfver;
{
register ADDRESS *a;
struct passwd *pw;
char *p;
/*
** See if this clears our concept of controlling user.
*/
if (user == NULL || *user == '\0')
return NULL;
/*
** Set up addr fields for controlling user.
*/
a = (ADDRESS *) xalloc(sizeof *a);
memset((char *) a, '\0', sizeof *a);
if (*user == '\0')
{
p = NULL;
a->q_user = newstr(DefUser);
}
else if (*user == ':')
{
p = &user[1];
a->q_user = newstr(p);
}
else
{
p = strtok(user, ":");
a->q_user = newstr(user);
if (qfver >= 2)
{
if ((p = strtok(NULL, ":")) != NULL)
a->q_uid = atoi(p);
if ((p = strtok(NULL, ":")) != NULL)
a->q_gid = atoi(p);
if ((p = strtok(NULL, ":")) != NULL)
a->q_flags |= QGOODUID;
}
else if ((pw = sm_getpwnam(user)) != NULL)
{
if (*pw->pw_dir == '\0')
a->q_home = NULL;
else if (strcmp(pw->pw_dir, "/") == 0)
a->q_home = "";
else
a->q_home = newstr(pw->pw_dir);
a->q_uid = pw->pw_uid;
a->q_gid = pw->pw_gid;
a->q_flags |= QGOODUID;
}
}
a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */
a->q_mailer = LocalMailer;
if (p == NULL)
a->q_paddr = newstr(a->q_user);
else
a->q_paddr = newstr(p);
return a;
}
/*
** LOSEQFILE -- save the qf as Qf and try to let someone know
**
** Parameters:
** e -- the envelope (e->e_id will be used).
** why -- reported to whomever can hear.
**
** Returns:
** none.
*/
# define LOSEQF_LETTER 'Q'
void
loseqfile(e, why)
register ENVELOPE *e;
char *why;
{
char *p;
char buf[MAXPATHLEN];
if (e == NULL || e->e_id == NULL)
return;
p = queuename(e, 'q');
if (strlen(p) >= (SIZE_T) sizeof buf)
return;
(void) strlcpy(buf, p, sizeof buf);
p = queuename(e, LOSEQF_LETTER);
if (rename(buf, p) < 0)
syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid());
else if (LogLevel > 0)
sm_syslog(LOG_ALERT, e->e_id,
"Losing %s: %s", buf, why);
}
/*
** QID_PRINTNAME -- create externally printable version of queue id
**
** Parameters:
** e -- the envelope.
**
** Returns:
** a printable version
*/
char *
qid_printname(e)
ENVELOPE *e;
{
char *id;
static char idbuf[MAXQFNAME + 34];
if (e == NULL)
return "";
if (e->e_id == NULL)
id = "";
else
id = e->e_id;
if (e->e_queuedir == NOQDIR)
return id;
(void) snprintf(idbuf, sizeof idbuf, "%.32s/%s",
QPaths[e->e_queuedir].qp_name, id);
return idbuf;
}
/*
** QID_PRINTQUEUE -- create full version of queue directory for df files
**
** Parameters:
** queuedir -- the short version of the queue directory
**
** Returns:
** the full pathname to the queue (static)
*/
char *
qid_printqueue(queuedir)
int queuedir;
{
char *subdir;
static char dir[MAXPATHLEN];
if (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -