More memory leak fixes, added command thread to mbtask

This commit is contained in:
Michiel Broek 2003-12-06 16:35:33 +00:00
parent 07012fa3e1
commit d55d4e0df1
13 changed files with 500 additions and 399 deletions

View File

@ -59,6 +59,11 @@ v0.39.3 26-Nov-2003
mbtask: mbtask:
The ping function now runs in a separate thread. The ping function now runs in a separate thread.
Changed some ping timer logic. Changed some ping timer logic.
Added a "secret" commandline parameter to allow mbtask to run
under control of debuggers.
The client command server runs in a separate thread.
Fixed some small memory leaks which had no effect on long term
running of mbtask, only leaks during program stop.
mbpasswd: mbpasswd:
Fixed a small memory leak. Fixed a small memory leak.

View File

@ -14,12 +14,12 @@
</HEAD> </HEAD>
<BODY> <BODY>
<BLOCKQUOTE> <BLOCKQUOTE>
<div align="right"><h5>Last update 23-Mar-2002</h5></div> <div align="right"><h5>Last update 06-Dec-2003</h5></div>
<div align="center"><H1>mbtask - MBSE BBS Taskmanager</H1></div> <div align="center"><H1>mbtask - MBSE BBS Taskmanager</H1></div>
<H3>Sysopsis.</H3> <H3>Sysopsis.</H3>
<P> <P>
<code><strong>mbtask</strong></code> <code><strong>mbtask</strong> [-nd]</code>
<P>&nbsp;<P> <P>&nbsp;<P>
<H3>Description.</H3> <H3>Description.</H3>
@ -119,6 +119,10 @@ the chance that numbers are repeated on your system are almost zero. The first
time the counter is initialized it is set to the current unix time in seconds time the counter is initialized it is set to the current unix time in seconds
since 1 januari 1970. This counter is used by several programs to create unique since 1 januari 1970. This counter is used by several programs to create unique
.pkt filenames, msgid numbers etc. .pkt filenames, msgid numbers etc.
<P>
The commandline option <b>-nd</b> is only for debugging, it allows to start
without becoming a daemon, <b>mbtask</b> will run in the foreground. This
option is only usefull for developers.
<P>&nbsp;<P> <P>&nbsp;<P>
<H3>Environment.</H3> <H3>Environment.</H3>

View File

@ -489,7 +489,7 @@ char *printable(char *s, int l)
len=-l; len=-l;
} }
pbuff=(char*)xmalloc(len*4+1); pbuff=(char*)xmalloc(len*3+1);
p=pbuff; p=pbuff;
while (len--) { while (len--) {
if (isprint(*(unsigned char*)s)) if (isprint(*(unsigned char*)s))

View File

@ -4,7 +4,7 @@
* Purpose ...............: Fidonet mailer * Purpose ...............: Fidonet mailer
* *
***************************************************************************** *****************************************************************************
* Copyright (C) 1997-2002 * Copyright (C) 1997-2003
* *
* Michiel Broek FIDO: 2:280/2802 * Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10 * Beekmansbos 10
@ -49,6 +49,10 @@ extern int Loaded;
extern int mypid; extern int mypid;
/*
* Encode EMSI string. If called with a NULL pointer memory is freed.
*/
char *emsiencode(char *s) char *emsiencode(char *s)
{ {
char Base16Code[]="0123456789ABCDEF"; char Base16Code[]="0123456789ABCDEF";
@ -57,6 +61,10 @@ char *emsiencode(char *s)
if (buf) if (buf)
free(buf); free(buf);
buf = NULL;
if (s == NULL)
return NULL;
if ((buf = malloc(2 * strlen(s) + 1 * sizeof(char))) == NULL) { if ((buf = malloc(2 * strlen(s) + 1 * sizeof(char))) == NULL) {
Syslog('+', "emsiencode:out of memory:string too long:\"%s\"", s); Syslog('+', "emsiencode:out of memory:string too long:\"%s\"", s);
return s; return s;
@ -84,8 +92,7 @@ char *emsiencode(char *s)
char *mkemsidat(int caller) char *mkemsidat(int caller)
{ {
time_t tt; time_t tt;
char cbuf[16]; char cbuf[16], *p;
char *p;
faddr *primary; faddr *primary;
int i; int i;
@ -96,10 +103,8 @@ char *mkemsidat(int caller)
for (i = 0; i < 40; i++) for (i = 0; i < 40; i++)
if ((CFG.aka[i].node) && (CFG.akavalid[i]) && if ((CFG.aka[i].node) && (CFG.akavalid[i]) &&
((CFG.aka[i].zone != primary->zone) || ((CFG.aka[i].zone != primary->zone) || (CFG.aka[i].net != primary->net) ||
(CFG.aka[i].net != primary->net) || (CFG.aka[i].node != primary->node) || (CFG.aka[i].point!= primary->point))) {
(CFG.aka[i].node != primary->node) ||
(CFG.aka[i].point!= primary->point))) {
p = xstrcat(p, (char *)" "); p = xstrcat(p, (char *)" ");
p = xstrcat(p, aka2str(CFG.aka[i])); p = xstrcat(p, aka2str(CFG.aka[i]));
} }
@ -109,8 +114,7 @@ char *mkemsidat(int caller)
if (emsi_local_password) if (emsi_local_password)
p=xstrcat(p,emsi_local_password); p=xstrcat(p,emsi_local_password);
else else if (strlen(nodes.Spasswd)) {
if (strlen(nodes.Spasswd)) {
p = xstrcat(p, nodes.Spasswd); p = xstrcat(p, nodes.Spasswd);
} }
@ -236,6 +240,7 @@ char *mkemsidat(int caller)
sprintf(cbuf,"%04X",(unsigned int)strlen(p+12)); sprintf(cbuf,"%04X",(unsigned int)strlen(p+12));
memcpy(p+8,cbuf,4); memcpy(p+8,cbuf,4);
Syslog('I',"Prepared: \"%s\"",p); Syslog('I',"Prepared: \"%s\"",p);
emsiencode(NULL); /* Free memory */
return p; return p;
} }

View File

@ -129,7 +129,7 @@ int tcprcvfiles(void)
{ {
int rc, bufl; int rc, bufl;
long filesize, filetime; long filesize, filetime;
char *filename, *p; char *filename = NULL, *p;
Syslog('+', "TCP: start receive files"); Syslog('+', "TCP: start receive files");
if (getsync()) { if (getsync()) {
@ -155,8 +155,12 @@ next:
} else } else
return rc==0?1:rc; return rc==0?1:rc;
if (strlen(filename) && filesize && filetime) if (strlen(filename) && filesize && filetime) {
rc = receivefile(filename,filetime,filesize); rc = receivefile(filename,filetime,filesize);
if (filename)
free(filename);
filename = NULL;
}
if (fout) { if (fout) {
if (closeit(0)) if (closeit(0))

View File

@ -33,7 +33,7 @@ install: all
@if [ "`id -un`" != "root" ] ; then \ @if [ "`id -un`" != "root" ] ; then \
echo; echo " Must be root to install!"; echo; exit 3; \ echo; echo " Must be root to install!"; echo; exit 3; \
fi fi
${INSTALL} -c -s -o `id -un` -g `id -gn` -m 6711 mbtask ${BINDIR} ${INSTALL} -c -o `id -un` -g `id -gn` -m 6755 mbtask ${BINDIR}
@if [ ! -f ${ETCDIR}/issue ]; then \ @if [ ! -f ${ETCDIR}/issue ]; then \
${INSTALL} -c -o ${OWNER} -g ${GROUP} -m 0644 issue ${ETCDIR} ; \ ${INSTALL} -c -o ${OWNER} -g ${GROUP} -m 0644 issue ${ETCDIR} ; \
echo "${INSTALL} -c -o ${OWNER} -g ${GROUP} -m 0644 issue ${ETCDIR}"; \ echo "${INSTALL} -c -o ${OWNER} -g ${GROUP} -m 0644 issue ${ETCDIR}"; \

View File

@ -48,7 +48,7 @@
#include "mbtask.h" #include "mbtask.h"
#define NUM_THREADS 1 /* Max. nr of threads */ #define NUM_THREADS 2 /* Max. nr of threads */
/* /*
@ -110,7 +110,9 @@ extern int ipmailers; /* TCP/IP mail sessions */
extern int tosswait; /* Toss wait timer */ extern int tosswait; /* Toss wait timer */
extern pid_t mypid; /* Pid of daemon */ extern pid_t mypid; /* Pid of daemon */
int T_Shutdown = FALSE; /* Shutdown threads */ int T_Shutdown = FALSE; /* Shutdown threads */
int nodaemon = FALSE; /* Run in foreground */
extern int cmd_run; /* Cmd running */
extern int ping_run; /* Ping running */
/* /*
@ -118,7 +120,7 @@ int T_Shutdown = FALSE; /* Shutdown threads */
*/ */
int thr_id[NUM_THREADS]; /* thread ID's */ int thr_id[NUM_THREADS]; /* thread ID's */
pthread_t p_thread[NUM_THREADS]; /* thread's structure */ pthread_t p_thread[NUM_THREADS]; /* thread's structure */
pthread_mutex_t p_mutex = PTHREAD_MUTEX_INITIALIZER; /* Ping mutex */ // pthread_mutex_t p_mutex = PTHREAD_MUTEX_INITIALIZER; /* Ping mutex */
@ -443,8 +445,7 @@ void load_taskcfg(void)
*/ */
pid_t launch(char *cmd, char *opts, char *name, int tasktype) pid_t launch(char *cmd, char *opts, char *name, int tasktype)
{ {
char buf[PATH_MAX]; char buf[PATH_MAX], *vector[16];
char *vector[16];
int i, rc = 0; int i, rc = 0;
pid_t pid = 0; pid_t pid = 0;
@ -452,6 +453,7 @@ pid_t launch(char *cmd, char *opts, char *name, int tasktype)
Syslog('?', "Launch: can't execute %s, maximum tasks reached", cmd); Syslog('?', "Launch: can't execute %s, maximum tasks reached", cmd);
return 0; return 0;
} }
memset(vector, 0, sizeof(vector));
if (opts == NULL) if (opts == NULL)
sprintf(buf, "%s", cmd); sprintf(buf, "%s", cmd);
@ -651,10 +653,11 @@ void die(int onsig)
{ {
int i, count; int i, count;
signal(onsig, SIG_IGN);
if (onsig == SIGTERM) {
Syslog('+', "Starting normal shutdown");
T_Shutdown = TRUE; T_Shutdown = TRUE;
signal(onsig, SIG_IGN);
if ((onsig == SIGTERM) || (nodaemon && (onsig == SIGINT))) {
Syslog('+', "Starting normal shutdown (%s)", SigName[onsig]);
} else { } else {
Syslog('+', "Abnormal shutdown on signal %s", SigName[onsig]); Syslog('+', "Abnormal shutdown on signal %s", SigName[onsig]);
} }
@ -686,13 +689,28 @@ void die(int onsig)
} }
} }
if (cmd_run || ping_run)
Syslog('+', "Waiting for threads to stop");
while (cmd_run || ping_run) {
sleep(1);
}
if ((count = checktasks(0))) if ((count = checktasks(0)))
Syslog('?', "Shutdown with %d tasks still running", count); Syslog('?', "Shutdown with %d tasks still running", count);
else else
Syslog('+', "Good, no more tasks running"); Syslog('+', "Good, no more tasks running");
/*
* Free memory
*/
deinitnl(); deinitnl();
ulocktask(); ulocktask();
printable(NULL, 0);
/*
* Close socket
*/
if (sock != -1) if (sock != -1)
close(sock); close(sock);
if (ping_isocket != -1) if (ping_isocket != -1)
@ -700,6 +718,7 @@ void die(int onsig)
if (!file_exist(spath, R_OK)) { if (!file_exist(spath, R_OK)) {
unlink(spath); unlink(spath);
} }
Syslog(' ', "MBTASK finished"); Syslog(' ', "MBTASK finished");
exit(onsig); exit(onsig);
} }
@ -797,6 +816,7 @@ void ulocktask(void)
free(lockfile); free(lockfile);
return; return;
} }
if (fscanf(fp, "%u", &oldpid) != 1) { if (fscanf(fp, "%u", &oldpid) != 1) {
WriteError("$Can't read old pid from \"%s\"", lockfile); WriteError("$Can't read old pid from \"%s\"", lockfile);
fclose(fp); fclose(fp);
@ -805,6 +825,8 @@ void ulocktask(void)
return; return;
} }
fclose(fp);
if (oldpid == getpid()) { if (oldpid == getpid()) {
(void)unlink(lockfile); (void)unlink(lockfile);
} }
@ -877,16 +899,15 @@ void check_sema(void)
void scheduler(void) void scheduler(void)
{ {
struct passwd *pw; struct passwd *pw;
int running = 0, rc, i, rlen, found; int running = 0, i, found;
static int LOADhi = FALSE, oldmin = 70, olddo = 70, oldsec = 70; static int LOADhi = FALSE, oldmin = 70, olddo = 70, oldsec = 70;
char *cmd = NULL, opts[41], port[21]; char *cmd = NULL, opts[41], port[21];
static char doing[32], buf[2048]; static char doing[32];
time_t now; time_t now;
struct tm *tm, *utm; struct tm *tm, *utm;
#if defined(__linux__) #if defined(__linux__)
FILE *fp; FILE *fp;
#endif #endif
struct pollfd pfd;
int call_work = 0; int call_work = 0;
static int call_entry = MAXTASKS; static int call_entry = MAXTASKS;
double loadavg[3]; double loadavg[3];
@ -949,43 +970,16 @@ void scheduler(void)
} }
/* /*
* Install ping thread * Install threads
*/ */
thr_id[0] = pthread_create(&p_thread[0], NULL, (void (*))ping_thread, NULL); thr_id[0] = pthread_create(&p_thread[0], NULL, (void (*))ping_thread, NULL);
thr_id[1] = pthread_create(&p_thread[1], NULL, (void (*))cmd_thread, NULL);
/* /*
* Enter the mainloop (forever) * Enter the mainloop (forever)
*/ */
do { do {
/* sleep(1);
* Poll UNIX Datagram socket until the defined timeout of one second.
* This means we listen of a MBSE BBS client program has something
* to tell.
*/
pfd.fd = sock;
pfd.events = POLLIN | POLLPRI;
pfd.revents = 0;
rc = poll(&pfd, 1, 1000);
if (rc == -1) {
/*
* Poll can be interrupted by a finished child so that's not a real error.
*/
if (errno != EINTR) {
Syslog('?', "$poll() rc=%d sock=%d, events=%04x", rc, sock, pfd.revents);
}
} else if (rc) {
if (pfd.revents & POLLIN) {
/*
* Process the clients request
*/
memset(&buf, 0, sizeof(buf));
fromlen = sizeof(from);
rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, (struct sockaddr *)&from, &fromlen);
do_cmd(buf);
} else {
Syslog('-', "Return poll rc=%d, events=%04x", rc, pfd.revents);
}
}
/* /*
* Check all registered connections and semafore's * Check all registered connections and semafore's
@ -1323,12 +1317,19 @@ int main(int argc, char **argv)
for (i = 0; i < NSIG; i++) { for (i = 0; i < NSIG; i++) {
if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM))
signal(i, (void (*))die); signal(i, (void (*))die);
else else if ((i != SIGKILL) && (i != SIGSTOP))
signal(i, SIG_IGN); signal(i, SIG_IGN);
} }
init_pingsocket(); init_pingsocket();
/*
* Secret undocumented startup switch, ie: no help available.
*/
if ((argc == 2) && (strcmp(argv[1], "-nd") == 0)) {
nodaemon = TRUE;
}
/* /*
* mbtask is setuid root, drop privileges to user mbse. * mbtask is setuid root, drop privileges to user mbse.
* This will stay forever like this, no need to become * This will stay forever like this, no need to become
@ -1341,12 +1342,19 @@ int main(int argc, char **argv)
close(ping_isocket); close(ping_isocket);
exit(MBERR_INIT_ERROR); exit(MBERR_INIT_ERROR);
} }
/*
* If running in the foreground under valgrind the next call fails.
* Developers should know what they are doing so we are not bailing out.
*/
if (setgid(pw->pw_gid)) { if (setgid(pw->pw_gid)) {
perror(""); perror("");
fprintf(stderr, "can't setgid to bbs\n"); fprintf(stderr, "can't setgid to bbs\n");
if (! nodaemon) {
close(ping_isocket); close(ping_isocket);
exit(MBERR_INIT_ERROR); exit(MBERR_INIT_ERROR);
} }
}
umask(007); umask(007);
if (locktask(pw->pw_dir)) { if (locktask(pw->pw_dir)) {
@ -1360,6 +1368,9 @@ int main(int argc, char **argv)
mypid = getpid(); mypid = getpid();
Syslog(' ', " "); Syslog(' ', " ");
Syslog(' ', "MBTASK v%s", VERSION); Syslog(' ', "MBTASK v%s", VERSION);
if (nodaemon)
Syslog('+', "Starting in no-daemon mode");
sprintf(tcfgfn, "%s/etc/task.data", getenv("MBSE_ROOT")); sprintf(tcfgfn, "%s/etc/task.data", getenv("MBSE_ROOT"));
load_taskcfg(); load_taskcfg();
status_init(); status_init();
@ -1381,6 +1392,13 @@ int main(int argc, char **argv)
if (!file_exist(spath, R_OK)) if (!file_exist(spath, R_OK))
unlink(spath); unlink(spath);
if (nodaemon) {
/*
* For debugging, run in foreground mode
*/
mypid = getpid();
scheduler();
} else {
/* /*
* Server initialization is complete. Now we can fork the * Server initialization is complete. Now we can fork the
* daemon and return to the user. We need to do a setpgrp * daemon and return to the user. We need to do a setpgrp
@ -1439,6 +1457,7 @@ int main(int argc, char **argv)
pthread_exit(NULL); pthread_exit(NULL);
exit(MBERR_OK); exit(MBERR_OK);
} }
}
/* /*
* Not reached * Not reached

View File

@ -620,6 +620,9 @@ int each(faddr *addr, char flavor, int isflo, char *fname)
sprintf((*tmp)->addr.domain, "%s", addr->domain); sprintf((*tmp)->addr.domain, "%s", addr->domain);
if (nlent->addr.domain) if (nlent->addr.domain)
free(nlent->addr.domain); free(nlent->addr.domain);
if (nlent->url)
free(nlent->url);
nlent->url = NULL;
(*tmp)->flavors = 0; (*tmp)->flavors = 0;
if (nlent->pflag != NL_DUMMY) { if (nlent->pflag != NL_DUMMY) {
(*tmp)->olflags = nlent->oflags; (*tmp)->olflags = nlent->oflags;

View File

@ -48,6 +48,7 @@ extern int internet; /* Internet is down */
extern int rescan; /* Master rescan flag */ extern int rescan; /* Master rescan flag */
struct in_addr paddr; /* Current ping address */ struct in_addr paddr; /* Current ping address */
extern int T_Shutdown; /* Program shutdown */ extern int T_Shutdown; /* Program shutdown */
int ping_run = FALSE; /* Thread runnning */
@ -244,7 +245,7 @@ int ping_send(struct in_addr addr)
int ping_receive(struct in_addr addr) int ping_receive(struct in_addr addr)
{ {
char buf[1024]; char buf[1024];
int len; int rc, len;
struct sockaddr_in ffrom; struct sockaddr_in ffrom;
struct icmphdr icmpp; struct icmphdr icmpp;
struct iphdr iph; struct iphdr iph;
@ -253,15 +254,17 @@ int ping_receive(struct in_addr addr)
pfd.fd = ping_isocket; pfd.fd = ping_isocket;
pfd.events = POLLIN; pfd.events = POLLIN;
pfd.revents = 0;
/* /*
* 100 mSec is enough, this function is called at regular intervals. * 100 mSec is enough, this function is called at regular intervals.
*/ */
if (poll(&pfd, 1, 100) < 0) { if ((rc = poll(&pfd, 1, 100) < 0)) {
if (icmp_errs < ICMP_MAX_ERRS) if (icmp_errs < ICMP_MAX_ERRS)
Syslog('?', "$poll/select failed"); Syslog('?', "$poll/select failed");
return -3; return -3;
} }
// Syslog('p', "poll_thread: poll interrupted rc=%d events=%04x", rc, pfd.revents);
if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) { if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) {
sl = sizeof(ffrom); sl = sizeof(ffrom);
@ -339,6 +342,7 @@ void *ping_thread(void)
pingresult[1] = pingresult[2] = FALSE; pingresult[1] = pingresult[2] = FALSE;
pingnr = 2; pingnr = 2;
internet = FALSE; internet = FALSE;
ping_run = TRUE;
while (! T_Shutdown) { while (! T_Shutdown) {
@ -438,6 +442,7 @@ void *ping_thread(void)
} }
} }
ping_run = FALSE;
Syslog('+', "Ping thread stopped"); Syslog('+', "Ping thread stopped");
pthread_exit(NULL); pthread_exit(NULL);
} }

View File

@ -86,6 +86,7 @@ void fill_portlist(pp_list **fdp, pp_list *new)
pp_list *tmp, *ta; pp_list *tmp, *ta;
tmp = (pp_list *)malloc(sizeof(pp_list)); tmp = (pp_list *)malloc(sizeof(pp_list));
memset(tmp, 0, sizeof(tmp));
tmp->next = NULL; tmp->next = NULL;
strncpy(tmp->tty, new->tty, 6); strncpy(tmp->tty, new->tty, 6);
tmp->mflags = new->mflags; tmp->mflags = new->mflags;

View File

@ -45,6 +45,9 @@ extern int sock; /* Server socket */
extern struct sockaddr_un from; /* From socket address */ extern struct sockaddr_un from; /* From socket address */
extern int fromlen; /* From address length */ extern int fromlen; /* From address length */
extern int logtrans; /* Log transactions */ extern int logtrans; /* Log transactions */
extern int T_Shutdown; /* Program shutdown */
int cmd_run = FALSE;/* cmd running */
/************************************************************************ /************************************************************************
@ -543,6 +546,7 @@ char *exe_cmd(char *in)
void do_cmd(char *);
void do_cmd(char *cmd) void do_cmd(char *cmd)
{ {
char buf[SS_BUFSIZE]; char buf[SS_BUFSIZE];
@ -570,3 +574,55 @@ void do_cmd(char *cmd)
} }
/*
* Thread that reads the command socket for new commands.
*/
void *cmd_thread(void)
{
int rlen, rc;
struct pollfd pfd;
static char buf[2048];
Syslog('+', "Starting cmd thread with pid %d", (int)getpid());
cmd_run = TRUE;
while (! T_Shutdown) {
/*
* Poll UNIX Datagram socket until the defined timeout of one second.
* This means we listen of a MBSE BBS client program has something
* to tell.
*/
pfd.fd = sock;
pfd.events = POLLIN;
pfd.revents = 0;
rc = poll(&pfd, 1, 1000);
// Syslog('c', "cmd_thread: poll interrupted rc=%d events=%04x", rc, pfd.revents);
if (rc == -1) {
/*
* Poll can be interrupted by a finished child so that's not a real error.
*/
// if (errno != EINTR) {
Syslog('?', "$poll() rc=%d sock=%d, events=%04x", rc, sock, pfd.revents);
// }
} else if (rc) {
if (pfd.revents & POLLIN) {
/*
* Process the clients request
*/
memset(&buf, 0, sizeof(buf));
fromlen = sizeof(from);
rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, (struct sockaddr *)&from, &fromlen);
do_cmd(buf);
} else {
Syslog('-', "Return poll rc=%d, events=%04x", rc, pfd.revents);
}
}
}
cmd_run = FALSE;
Syslog('+', "Cmd thread stopped");
pthread_exit(NULL);
}

View File

@ -3,8 +3,7 @@
/* $Id$ */ /* $Id$ */
void *cmd_thread(void);
void do_cmd(char *);
#endif #endif

View File

@ -559,10 +559,10 @@ char *printable(char *s, int l)
if (len > -l) if (len > -l)
len=-l; len=-l;
} }
pbuff=(char*)xmalloc(len*4+1); pbuff=(char*)xmalloc(len*3+1);
p=pbuff; p=pbuff;
while (len--) { while (len--) {
if (*(unsigned char*)s >= ' ') if (isprint(*(unsigned char*)s))
*p++=*s; *p++=*s;
else switch (*s) { else switch (*s) {
case '\\': *p++='\\'; *p++='\\'; break; case '\\': *p++='\\'; *p++='\\'; break;
@ -570,7 +570,7 @@ char *printable(char *s, int l)
case '\n': *p++='\\'; *p++='n'; break; case '\n': *p++='\\'; *p++='n'; break;
case '\t': *p++='\\'; *p++='t'; break; case '\t': *p++='\\'; *p++='t'; break;
case '\b': *p++='\\'; *p++='b'; break; case '\b': *p++='\\'; *p++='b'; break;
default: sprintf(p,"\\%03o",*s); p+=4; break; default: sprintf(p,"\\%02x", (*s & 0xff)); p+=3; break;
} }
s++; s++;
} }