git-svn: trunk@4927
Török Edvin authored on 2009/03/12 04:11:09... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Wed Mar 11 21:11:03 EET 2009 (edwin) |
|
2 |
+------------------------------------ |
|
3 |
+ * clamav-milter/, clamd/, libclamav/, sigtool/, unit_tests/: |
|
4 |
+ strerror/strerror_r->cli_strerror which is always thread safe. |
|
5 |
+ |
|
1 | 6 |
Wed Mar 11 19:18:15 CET 2009 (acab) |
2 | 7 |
----------------------------------- |
3 | 8 |
* libclamav: changed some warning texts (bb#1456) |
... | ... |
@@ -45,14 +45,7 @@ |
45 | 45 |
#include "libclamav/others.h" |
46 | 46 |
#include "netcode.h" |
47 | 47 |
|
48 |
-#ifdef HAVE_STRERROR_R |
|
49 |
-#define strerror_print(msg) \ |
|
50 |
- strerror_r(errno, er, sizeof(er)); \ |
|
51 |
- logg(msg": %s\n", er); |
|
52 |
-#else |
|
53 |
-#define strerror_print(msg) \ |
|
54 |
- logg(msg"\n"); |
|
55 |
-#endif |
|
48 |
+#define strerror_print(msg) logg(msg": %s\n", cli_strerror(errno, er, sizeof(er))) |
|
56 | 49 |
|
57 | 50 |
enum { |
58 | 51 |
NON_SMTP, |
... | ... |
@@ -610,16 +610,11 @@ int fds_poll_recv(struct fd_data *data, int timeout, int check_signals) |
610 | 610 |
#endif |
611 | 611 |
|
612 | 612 |
if (retval == -1 && errno != EINTR) { |
613 |
- char buff[BUFFSIZE + 1]; |
|
614 |
-#ifdef HAVE_STRERROR_R |
|
615 |
- strerror_r(errno, buff, BUFFSIZE); |
|
616 |
-#else |
|
617 |
- buff[0] = '\0'; |
|
618 |
-#endif |
|
613 |
+ char err[128]; |
|
619 | 614 |
#ifdef HAVE_POLL |
620 |
- logg("!poll_recv_fds: poll failed: %s\n", buff); |
|
615 |
+ logg("!poll_recv_fds: poll failed: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
621 | 616 |
#else |
622 |
- logg("!poll_recv_fds: select failed: %s\n", buff); |
|
617 |
+ logg("!poll_recv_fds: select failed: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
623 | 618 |
#endif |
624 | 619 |
} |
625 | 620 |
|
... | ... |
@@ -26,11 +26,6 @@ |
26 | 26 |
#include "clamav-config.h" |
27 | 27 |
#endif |
28 | 28 |
|
29 |
-#ifdef C_LINUX |
|
30 |
-/* We want XSI compliant strerror_r, not GNU one.*/ |
|
31 |
-#define _XOPEN_SOURCE 600 |
|
32 |
-#endif |
|
33 |
- |
|
34 | 29 |
#include <stdio.h> |
35 | 30 |
#include <stdlib.h> |
36 | 31 |
#include <string.h> |
... | ... |
@@ -172,14 +167,10 @@ int conn_reply_error(const client_conn_t *conn, const char *msg) |
172 | 172 |
int conn_reply_errno(const client_conn_t *conn, const char *path, |
173 | 173 |
const char *msg) |
174 | 174 |
{ |
175 |
- char buf[BUFFSIZE + sizeof(". ERROR")]; |
|
176 |
-#ifdef HAVE_STRERROR_R |
|
177 |
- strerror_r(errno, buf, BUFFSIZE-1); |
|
178 |
- strcat(buf, ". ERROR"); |
|
179 |
-#else |
|
180 |
- snprintf(buf, sizeof(buf), "%u. ERROR", errno); |
|
181 |
-#endif |
|
182 |
- return conn_reply(conn, path, msg, buf); |
|
175 |
+ char err[BUFFSIZE + sizeof(". ERROR")]; |
|
176 |
+ cli_strerror(errno, err, BUFFSIZE-1); |
|
177 |
+ strcat(err, ". ERROR"); |
|
178 |
+ return conn_reply(conn, path, msg, err); |
|
183 | 179 |
} |
184 | 180 |
|
185 | 181 |
/* returns |
... | ... |
@@ -706,6 +706,7 @@ static int in_iconv_u16(const m_area_t* in_m_area, iconv_t* iconv_struct, m_area |
706 | 706 |
char* input = (char*)in_m_area->buffer + in_m_area->offset; |
707 | 707 |
size_t outleft = out_m_area->length > 0 ? out_m_area->length : 0; |
708 | 708 |
char* out = (char*)out_m_area->buffer; |
709 |
+ char err[128]; |
|
709 | 710 |
|
710 | 711 |
out_m_area->offset = 0; |
711 | 712 |
if(!inleft) { |
... | ... |
@@ -734,7 +735,7 @@ static int in_iconv_u16(const m_area_t* in_m_area, iconv_t* iconv_struct, m_area |
734 | 734 |
/* not enough space in output buffer */ |
735 | 735 |
break; |
736 | 736 |
} |
737 |
- cli_dbgmsg(MODULE_NAME "iconv error:%s\n", strerror(errno)); |
|
737 |
+ cli_dbgmsg(MODULE_NAME "iconv error:%s\n", cli_strerror(errno, err, sizeof(err))); |
|
738 | 738 |
} else if(outleft == outleft_last) { |
739 | 739 |
cli_dbgmsg(MODULE_NAME "iconv stall (no output)\n"); |
740 | 740 |
} else { |
... | ... |
@@ -3744,8 +3744,9 @@ rfc1341(message *m, const char *dir) |
3744 | 3744 |
struct stat statb; |
3745 | 3745 |
|
3746 | 3746 |
if(stat(pdir, &statb) < 0) { |
3747 |
+ char err[128]; |
|
3747 | 3748 |
cli_errmsg("Partial directory %s: %s\n", pdir, |
3748 |
- strerror(errno)); |
|
3749 |
+ cli_strerror(errno, err, sizeof(err))); |
|
3749 | 3750 |
free(id); |
3750 | 3751 |
return -1; |
3751 | 3752 |
} |
... | ... |
@@ -4566,6 +4567,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4566 | 4566 |
struct timeval timeout; /* When we should time out */ |
4567 | 4567 |
int numfd; /* Highest fdset fd plus 1 */ |
4568 | 4568 |
long flags; |
4569 |
+ char err[128]; |
|
4569 | 4570 |
|
4570 | 4571 |
gettimeofday(&timeout, 0); /* store when we started to connect */ |
4571 | 4572 |
|
... | ... |
@@ -4576,9 +4578,9 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4576 | 4576 |
flags = fcntl(sock, F_GETFL, 0); |
4577 | 4577 |
|
4578 | 4578 |
if(flags == -1L) |
4579 |
- cli_dbgmsg("getfl: %s\n", strerror(errno)); |
|
4579 |
+ cli_dbgmsg("getfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4580 | 4580 |
else if(fcntl(sock, F_SETFL, (long)(flags | O_NONBLOCK)) < 0) |
4581 |
- cli_dbgmsg("setfl: %s\n", strerror(errno)); |
|
4581 |
+ cli_dbgmsg("setfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4582 | 4582 |
#else |
4583 | 4583 |
flags = -1L; |
4584 | 4584 |
#endif |
... | ... |
@@ -4587,17 +4589,17 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4587 | 4587 |
case EALREADY: |
4588 | 4588 |
case EINPROGRESS: |
4589 | 4589 |
cli_dbgmsg("%s: connect: %s\n", hostname, |
4590 |
- strerror(errno)); |
|
4590 |
+ cli_strerror(errno, err, sizeof(err))); |
|
4591 | 4591 |
break; /* wait for connection */ |
4592 | 4592 |
case EISCONN: |
4593 | 4593 |
return 0; /* connected */ |
4594 | 4594 |
default: |
4595 | 4595 |
cli_dbgmsg("%s: connect: %s\n", |
4596 |
- hostname, strerror(errno)); |
|
4596 |
+ hostname, cli_strerror(errno, err, sizeof(err))); |
|
4597 | 4597 |
#ifdef F_SETFL |
4598 | 4598 |
if(flags != -1L) |
4599 | 4599 |
if(fcntl(sock, F_SETFL, flags)) |
4600 |
- cli_dbgmsg("f_setfl: %s\n", strerror(errno)); |
|
4600 |
+ cli_dbgmsg("f_setfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4601 | 4601 |
#endif |
4602 | 4602 |
return -1; /* failed */ |
4603 | 4603 |
} |
... | ... |
@@ -4605,7 +4607,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4605 | 4605 |
#ifdef F_SETFL |
4606 | 4606 |
if(flags != -1L) |
4607 | 4607 |
if(fcntl(sock, F_SETFL, flags)) |
4608 |
- cli_dbgmsg("f_setfl: %s\n", strerror(errno)); |
|
4608 |
+ cli_dbgmsg("f_setfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4609 | 4609 |
#endif |
4610 | 4610 |
return connect_error(sock, hostname); |
4611 | 4611 |
} |
... | ... |
@@ -4647,7 +4649,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4647 | 4647 |
n = select(numfd, 0, &fds, 0, &waittime); |
4648 | 4648 |
if(n < 0) { |
4649 | 4649 |
cli_dbgmsg("%s: select attempt %d %s\n", |
4650 |
- hostname, select_failures, strerror(errno)); |
|
4650 |
+ hostname, select_failures, cli_strerror(errno, err, sizeof(err))); |
|
4651 | 4651 |
if(--select_failures >= 0) |
4652 | 4652 |
continue; /* not timed-out, try again */ |
4653 | 4653 |
break; /* failed */ |
... | ... |
@@ -4659,7 +4661,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4659 | 4659 |
#ifdef F_SETFL |
4660 | 4660 |
if(flags != -1L) |
4661 | 4661 |
if(fcntl(sock, F_SETFL, flags)) |
4662 |
- cli_dbgmsg("f_setfl: %s\n", strerror(errno)); |
|
4662 |
+ cli_dbgmsg("f_setfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4663 | 4663 |
#endif |
4664 | 4664 |
return connect_error(sock, hostname); |
4665 | 4665 |
} |
... | ... |
@@ -4674,7 +4676,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4674 | 4674 |
#ifdef F_SETFL |
4675 | 4675 |
if(flags != -1L) |
4676 | 4676 |
if(fcntl(sock, F_SETFL, flags)) |
4677 |
- cli_dbgmsg("f_setfl: %s\n", strerror(errno)); |
|
4677 |
+ cli_dbgmsg("f_setfl: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
4678 | 4678 |
#endif |
4679 | 4679 |
return -1; /* failed */ |
4680 | 4680 |
} |
... | ... |
@@ -4682,6 +4684,7 @@ nonblock_connect(SOCKET sock, const struct sockaddr_in *sin, const char *hostnam |
4682 | 4682 |
static int |
4683 | 4683 |
connect_error(SOCKET sock, const char *hostname) |
4684 | 4684 |
{ |
4685 |
+ char err[128]; |
|
4685 | 4686 |
#ifdef SO_ERROR |
4686 | 4687 |
int optval; |
4687 | 4688 |
socklen_t optlen = sizeof(optval); |
... | ... |
@@ -4689,7 +4692,7 @@ connect_error(SOCKET sock, const char *hostname) |
4689 | 4689 |
getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen); |
4690 | 4690 |
|
4691 | 4691 |
if(optval) { |
4692 |
- cli_dbgmsg("%s: %s\n", hostname, strerror(optval)); |
|
4692 |
+ cli_dbgmsg("%s: %s\n", hostname, cli_strerror(optval, err, sizeof(err))); |
|
4693 | 4693 |
return -1; |
4694 | 4694 |
} |
4695 | 4695 |
#endif |
... | ... |
@@ -668,7 +668,8 @@ int cli_gentempfd(const char *dir, char **name, int *fd) |
668 | 668 |
* errors |
669 | 669 |
*/ |
670 | 670 |
if(*fd == -1) { |
671 |
- cli_errmsg("cli_gentempfd: Can't create temporary file %s: %s\n", *name, strerror(errno)); |
|
671 |
+ char err[128]; |
|
672 |
+ cli_errmsg("cli_gentempfd: Can't create temporary file %s: %s\n", *name, cli_strerror(errno, err, sizeof(err))); |
|
672 | 673 |
free(*name); |
673 | 674 |
return CL_ECREAT; |
674 | 675 |
} |
... | ... |
@@ -682,7 +683,8 @@ int cli_gentempfd(const char *dir, char **name, int *fd) |
682 | 682 |
int cli_unlink(const char *pathname) |
683 | 683 |
{ |
684 | 684 |
if (unlink(pathname)==-1) { |
685 |
- cli_warnmsg("cli_unlink: failure - %s\n", strerror(errno)); |
|
685 |
+ char err[128]; |
|
686 |
+ cli_warnmsg("cli_unlink: failure - %s\n", cli_strerror(errno, err, sizeof(err))); |
|
686 | 687 |
return 1; |
687 | 688 |
} |
688 | 689 |
return 0; |
... | ... |
@@ -705,10 +707,11 @@ cli_rmdirs(const char *name) |
705 | 705 |
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; |
706 | 706 |
} result; |
707 | 707 |
#endif |
708 |
+ char err[128]; |
|
708 | 709 |
|
709 | 710 |
|
710 | 711 |
if(stat(name, &statb) < 0) { |
711 |
- cli_warnmsg("cli_rmdirs: Can't locate %s: %s\n", name, strerror(errno)); |
|
712 |
+ cli_warnmsg("cli_rmdirs: Can't locate %s: %s\n", name, cli_strerror(errno, err, sizeof(err))); |
|
712 | 713 |
return -1; |
713 | 714 |
} |
714 | 715 |
|
... | ... |
@@ -753,7 +756,7 @@ cli_rmdirs(const char *name) |
753 | 753 |
closedir(dd); |
754 | 754 |
|
755 | 755 |
if(rmdir(name) < 0) { |
756 |
- cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", name, strerror(errno)); |
|
756 |
+ cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", name, cli_strerror(errno, err, sizeof(err))); |
|
757 | 757 |
return -1; |
758 | 758 |
} |
759 | 759 |
|
... | ... |
@@ -772,6 +775,7 @@ int cli_rmdirs(const char *dirname) |
772 | 772 |
#endif |
773 | 773 |
struct stat maind, statbuf; |
774 | 774 |
char *path; |
775 |
+ char err[128]; |
|
775 | 776 |
|
776 | 777 |
|
777 | 778 |
chmod(dirname, 0700); |
... | ... |
@@ -779,7 +783,7 @@ int cli_rmdirs(const char *dirname) |
779 | 779 |
while(stat(dirname, &maind) != -1) { |
780 | 780 |
if(!rmdir(dirname)) break; |
781 | 781 |
if(errno != ENOTEMPTY && errno != EEXIST && errno != EBADF) { |
782 |
- cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", dirname, strerror(errno)); |
|
782 |
+ cli_errmsg("cli_rmdirs: Can't remove temporary directory %s: %s\n", dirname, cli_strerror(errno, err, sizeof(err))); |
|
783 | 783 |
closedir(dd); |
784 | 784 |
return -1; |
785 | 785 |
} |
... | ... |
@@ -437,4 +437,5 @@ typedef int (*cli_ftw_cb)(struct stat *stat_buf, char *filename, const char *pat |
437 | 437 |
*/ |
438 | 438 |
int cli_ftw(char *base, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data); |
439 | 439 |
|
440 |
+const char *cli_strerror(int errnum, char* buf, size_t len); |
|
440 | 441 |
#endif |
... | ... |
@@ -76,7 +76,9 @@ |
76 | 76 |
# ifndef HAVE_CTIME_R |
77 | 77 |
static pthread_mutex_t cli_ctime_mutex = PTHREAD_MUTEX_INITIALIZER; |
78 | 78 |
# endif |
79 |
- |
|
79 |
+#ifndef HAVE_STRERROR_R |
|
80 |
+static pthread_mutex_t cli_strerror_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
81 |
+#endif |
|
80 | 82 |
#endif |
81 | 83 |
uint8_t cli_debug_flag = 0; |
82 | 84 |
|
... | ... |
@@ -296,10 +298,11 @@ int cli_readn(int fd, void *buff, unsigned int count) |
296 | 296 |
return (count - todo); |
297 | 297 |
} |
298 | 298 |
if (retval < 0) { |
299 |
+ char err[128]; |
|
299 | 300 |
if (errno == EINTR) { |
300 | 301 |
continue; |
301 | 302 |
} |
302 |
- cli_errmsg("cli_readn: read error: %s\n", strerror(errno)); |
|
303 |
+ cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
303 | 304 |
return -1; |
304 | 305 |
} |
305 | 306 |
todo -= retval; |
... | ... |
@@ -326,10 +329,11 @@ int cli_writen(int fd, const void *buff, unsigned int count) |
326 | 326 |
do { |
327 | 327 |
retval = write(fd, current, todo); |
328 | 328 |
if (retval < 0) { |
329 |
+ char err[128]; |
|
329 | 330 |
if (errno == EINTR) { |
330 | 331 |
continue; |
331 | 332 |
} |
332 |
- cli_errmsg("cli_writen: write error: %s\n", strerror(errno)); |
|
333 |
+ cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
333 | 334 |
return -1; |
334 | 335 |
} |
335 | 336 |
todo -= retval; |
... | ... |
@@ -679,3 +683,25 @@ static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb |
679 | 679 |
} |
680 | 680 |
return ret; |
681 | 681 |
} |
682 |
+ |
|
683 |
+/* strerror_r is not available everywhere, (and when it is there are two variants, |
|
684 |
+ * the XSI, and the GNU one, so provide a wrapper to make sure correct one is |
|
685 |
+ * used */ |
|
686 |
+const char* cli_strerror(int errnum, char *buf, size_t len) |
|
687 |
+{ |
|
688 |
+#ifdef HAVE_STRERROR_R |
|
689 |
+ if (strerror_r(errnum, buf, len) == -1) |
|
690 |
+ return "strerror_r failed"; |
|
691 |
+ return buf; |
|
692 |
+#else |
|
693 |
+ { |
|
694 |
+ char *err; |
|
695 |
+ pthread_mutex_lock(&cli_strerror_mutex); |
|
696 |
+ err = strerror(errnum); |
|
697 |
+ strncpy(buf, err, len); |
|
698 |
+ pthread_mutex_unlock(&cli_strerror_mutex); |
|
699 |
+ return buf; |
|
700 |
+ } |
|
701 |
+#endif |
|
702 |
+} |
|
703 |
+ |
... | ... |
@@ -399,7 +399,8 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset) |
399 | 399 |
snprintf(fullname, sizeof(fullname), "%s/pdf%02u", dir, files); |
400 | 400 |
fout = open(fullname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600); |
401 | 401 |
if(fout < 0) { |
402 |
- cli_errmsg("cli_pdf: can't create temporary file %s: %s\n", fullname, strerror(errno)); |
|
402 |
+ char err[128]; |
|
403 |
+ cli_errmsg("cli_pdf: can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err))); |
|
403 | 404 |
rc = CL_ETMPFILE; |
404 | 405 |
break; |
405 | 406 |
} |
... | ... |
@@ -161,7 +161,8 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx, cli_file_t container) |
161 | 161 |
if(container == CL_TYPE_MAIL) { |
162 | 162 |
fd = open(fname, O_RDONLY|O_BINARY); |
163 | 163 |
if(fd == -1) { |
164 |
- cli_warnmsg("Cannot open file %s: %s, mode: %x\n", fname, strerror(errno), statbuf.st_mode); |
|
164 |
+ char err[128]; |
|
165 |
+ cli_warnmsg("Cannot open file %s: %s, mode: %x\n", fname, cli_strerror(errno, err, sizeof(err)), statbuf.st_mode); |
|
165 | 166 |
free(fname); |
166 | 167 |
continue; |
167 | 168 |
} |
... | ... |
@@ -185,10 +185,11 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx) |
185 | 185 |
fout = open(fullname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600); |
186 | 186 |
|
187 | 187 |
if(fout < 0) { |
188 |
- cli_errmsg("cli_untar: Can't create temporary file %s: %s\n", fullname, strerror(errno)); |
|
188 |
+ char err[128]; |
|
189 |
+ cli_errmsg("cli_untar: Can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err))); |
|
189 | 190 |
return CL_ETMPFILE; |
190 | 191 |
} |
191 |
- |
|
192 |
+ |
|
192 | 193 |
cli_dbgmsg("cli_untar: extracting to %s\n", fullname); |
193 | 194 |
|
194 | 195 |
in_block = 1; |
... | ... |
@@ -53,7 +53,7 @@ host_triplet = @host@ |
53 | 53 |
target_triplet = @target@ |
54 | 54 |
bin_PROGRAMS = sigtool$(EXEEXT) |
55 | 55 |
subdir = sigtool |
56 |
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in |
|
56 |
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in COPYING |
|
57 | 57 |
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 |
58 | 58 |
am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \ |
59 | 59 |
$(top_srcdir)/m4/argz.m4 $(top_srcdir)/m4/fdpassing.m4 \ |
... | ... |
@@ -115,11 +115,7 @@ static void conn_teardown(void) |
115 | 115 |
|
116 | 116 |
#define NONEXISTENT "/nonexistent\vfilename" |
117 | 117 |
|
118 |
-#ifdef HAVE_STRERROR_R |
|
119 | 118 |
#define NONEXISTENT_REPLY NONEXISTENT": lstat() failed: No such file or directory. ERROR" |
120 |
-#else |
|
121 |
-#define NONEXISTENT_REPLY NONEXISTENT": lstat() failed: 2. ERROR" |
|
122 |
-#endif |
|
123 | 119 |
|
124 | 120 |
#define ACCDENIED BUILDDIR"/accdenied" |
125 | 121 |
#define ACCDENIED_REPLY ACCDENIED": Access denied. ERROR" |