tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / kern / amiga_log.c
bloba7a38dd619101c06d3e74a460ee761aecd21a63c
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
23 #include <conf.h>
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/time.h>
29 #include <exec/exec.h>
30 #include <dos/dos.h>
31 #include <dos/dostags.h>
32 #include <dos/dosextens.h>
34 #include <kern/amiga_includes.h>
35 #include <syslog.h>
36 #include <kern/amiga_cx.h>
37 #include <kern/amiga_dhcp.h>
38 #include <kern/amiga_gui.h>
39 #include <kern/amiga_log.h>
40 #include <kern/amiga_rexx.h>
41 #include <libraries/miamipanel.h>
42 #include <utility/date.h>
44 #include <proto/miami.h>
46 #include <proto/dos.h>
47 #include <proto/miamipanel.h>
48 #include <proto/utility.h>
49 #define DOSBase logDOSBase
50 #define UtilityBase logUtilityBase
51 #undef DOSBase
53 struct MsgPort *logPort;
54 struct MsgPort *ExtLogPort;
56 struct Library *logDOSBase = NULL;
57 struct Library *logUtilityBase = NULL;
59 extern struct Task *AROSTCP_Task;
60 extern struct DosLibrary *DOSBase;
62 extern void REGARGFUN stuffchar();
63 extern int logname_changed(void *p, IPTR new);
65 static struct SysLogPacket *log_poll(void);
66 static void log_task(void);
67 static void log_close(struct SysLogPacket *msg);
68 static BPTR logOpen(STRPTR name);
70 static struct SysLogPacket *log_messages = NULL;
71 static char *log_buffers = NULL;
72 static LONG log_messages_mem_size, log_buffers_mem_size;
73 static int GetLogMsgFail;
76 UBYTE consoledefname[] = "con:0/0/640/200/AROSTCP syslog/AUTO/INACTIVE";
77 extern UBYTE logfiledefname[];
78 STRPTR logfilename = logfiledefname;
79 STRPTR consolename = consoledefname;
81 struct log_cnf log_cnf = { LOG_BUFS, LOG_BUF_LEN, LOG_INFO};
83 LONG OpenGUIOnStartup = 1;
85 #define SOCKET_VERSION 3
87 struct SignalSemaphore LogLock;
88 struct MsgPort logReplyPort;
91 * Initialization function for the logging subsystem
94 BOOL
95 log_init(void)
97 struct Message *msg;
98 int i;
99 ULONG sig;
100 #if defined(__AROS__)
101 D(bug("[AROSTCP](amiga_log.c) log_init()\n"));
102 #endif
103 /* if (logReplyPort)
104 return(TRUE);*/ /* We're allready initialized */
105 InitSemaphore(&LogLock);
108 * Allocate buffers for log messages.
110 * Save lengths to static variables, since the configuration variables might
111 * change.
113 log_messages_mem_size = sizeof(struct SysLogPacket) * log_cnf.log_bufs;
114 log_buffers_mem_size = log_cnf.log_bufs * log_cnf.log_buf_len * sizeof(char);
115 if (log_messages = AllocMem(log_messages_mem_size, MEMF_CLEAR|MEMF_PUBLIC))
116 if (log_buffers = AllocMem(log_buffers_mem_size, MEMF_CLEAR|MEMF_PUBLIC)) {
117 logPort = NULL; /* NETTRACE will set this on success */
118 GetLogMsgFail = 0;
120 #if defined(__AROS__)
121 DSYSCALLS(__log(LOG_DEBUG,"Set initial SysLogPort");)
122 ExtLogPort = FindPort("SysLog");
123 #else
124 SetSysLogPort();
125 #endif
126 logReplyPort.mp_Flags = PA_SIGNAL;
127 logReplyPort.mp_SigBit = SIGBREAKB_CTRL_E;
128 logReplyPort.mp_SigTask = FindTask(NULL);
129 NewList(&logReplyPort.mp_MsgList);
131 * Start the NETTRACE process
133 D(Printf("Creating NETTRACE process...");)
135 #ifdef __MORPHOS__
136 if (CreateNewProcTags(NP_Entry, (IPTR)&log_task,
137 NP_Name, (IPTR)LOG_TASK_NAME,
138 NP_Priority, LOG_TASK_PRI,
139 NP_CodeType,CODETYPE_PPC,
140 TAG_DONE, NULL))
141 #else
142 if (CreateNewProcTags(NP_Entry, (IPTR)&log_task,
143 NP_Name, (IPTR)LOG_TASK_NAME,
144 NP_Priority, LOG_TASK_PRI,
145 TAG_DONE, NULL))
146 #endif
148 for (;;) {
150 * Wait for a signal for success or failure
152 sig = Wait(SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
153 D(Printf(" got some reply...");)
155 if (sig & SIGBREAKF_CTRL_F && logPort == (struct MsgPort *)-1) {
156 /* Initializion failed */
157 D(Printf(" initialization failed!\n");)
158 logPort = NULL;
159 break;
161 else if (msg = GetMsg(&logReplyPort)) { /* Got message back? */
162 D(Printf(" done!\n");)
163 ReplyMsg(msg);
164 logReplyPort.mp_Flags = PA_IGNORE;
166 * Initialize messages
168 for (i = 0; i < log_cnf.log_bufs; i++) {
169 D(Printf("Initialising log message %ld\n",i);)
170 log_messages[i].Msg.mn_ReplyPort = &logReplyPort;
171 log_messages[i].Msg.mn_Length = sizeof(struct SysLogPacket);
172 log_messages[i].Level = 0;
173 log_messages[i].String = log_buffers+i*log_cnf.log_buf_len;
174 PutMsg(&logReplyPort, (struct Message *)&log_messages[i]);
176 D(Printf("Finished!\n");)
177 return(TRUE); /* We're done */
183 * Something went wrong
185 log_deinit();
186 return(FALSE);
189 /* A little stub for calling GetMsg w/ error reporting and cheking */
190 struct SysLogPacket *GetLogMsg(struct MsgPort *port)
192 struct Message *msg;
193 #if defined(__AROS__)
194 D(bug("[AROSTCP](amiga_log.c) GetLogMsg()\n"));
195 #endif
197 /* We should have a port, if not-> fail */
198 if (port) {
199 ObtainSemaphore(&LogLock);
200 for (;;) {
201 if (msg = GetMsg(port)) { /* Get a message */
202 SetSignal(0, SIGBREAKF_CTRL_E);
203 ReleaseSemaphore(&LogLock);
204 return (struct SysLogPacket *)msg;
206 port->mp_SigTask = FindTask(NULL);
207 port->mp_Flags = PA_SIGNAL;
208 WaitPort(port);
209 port->mp_Flags = PA_IGNORE;
212 DNETTRACE(else KPrintF("WARNING!!! port = NULL!\n");)
214 ++GetLogMsgFail; /* Increment number of failed messages */
215 return NULL;
219 * This function may be called only if no other tasks (applications) are
220 * accessing the logging system (the messages, to be exact).
222 void
223 log_deinit(void)
225 struct SysLogPacket *msg, *dump;
226 #if defined(__AROS__)
227 D(bug("[AROSTCP](amiga_log.c) log_deinit()\n"));
228 #endif
230 D(Printf("log_deinit() called\n");)
231 if (logPort) { /* Logport exists? (=> NETTRACE is running) */
234 * Get a free message, Wait() for it if necessary
236 msg = GetLogMsg(&logReplyPort);
237 D(Printf("Got next log message\n");)
240 * Initalize END_MESSAGE
242 msg->Msg.mn_ReplyPort = &logReplyPort;
243 msg->Msg.mn_Length = sizeof(struct SysLogPacket);
244 msg->Level = LOG_CLOSE;
246 PutMsg(logPort, (struct Message *)msg);
247 D(Printf("Sent LOG_CLOSE\n");)
249 for (;;) {
250 dump = GetLogMsg(&logReplyPort);
251 D(Printf("Got next log message\n");)
252 if (dump->Level == LOG_CLOSE) { /* got the Close message back */
253 D(Printf("LOG_CLOSE returned\n");)
254 break; /* It was the last one */
258 if (log_buffers) {
259 D(Printf("Freeing log_buffers\n");)
260 FreeMem(log_buffers, log_buffers_mem_size);
261 log_buffers = NULL;
263 if (log_messages) {
264 D(Printf("Freeing log_messages\n");)
265 FreeMem(log_messages, log_messages_mem_size);
266 log_messages = NULL;
271 * Functions following these defines may be called from the NETTRACE
272 * task ONLY! These defines cause the SAS/C to generate calls to
273 * dos.library and utility.library using these bases, respectively.
275 #define DOSBase logDOSBase
276 #define UtilityBase logUtilityBase
278 struct Library *SocketBase = NULL;
279 struct Task *Nettrace_Task = NULL;
281 /* Main loop for NETTRACE */
282 static void SAVEDS
283 log_task(void)
285 struct SysLogPacket *initmsg = NULL;
286 ULONG rexxmask = 0, logmask = 0, sigmask = 0, cxmask = 0;
287 #if defined(__AROS__)
288 D(bug("[AROSTCP](amiga_log.c) log_task()\n"));
289 #endif
291 DNETTRACE(KPrintF("NETTRACE started\n");)
292 Nettrace_Task = FindTask(NULL); /* Store task pointer for AmiTCP */
294 /* We need our own DosBase */
295 if ((logDOSBase = OpenLibrary(DOSNAME, 0L)) == NULL)
296 goto fail;
298 if ((logUtilityBase = OpenLibrary("utility.library", 37L)) == NULL)
299 goto fail;
301 /* Allocate message to reply startup */
302 if ((initmsg = AllocMem(sizeof(struct SysLogPacket), MEMF_CLEAR|MEMF_PUBLIC))
303 == NULL)
304 goto fail;
306 /* Create our port for log messages */
307 if ((logPort = CreateMsgPort()) == NULL)
308 goto fail;
310 logmask = 1<<logPort->mp_SigBit;
313 * Initialize rexx subsystem
315 if (!(rexxmask = rexx_init()))
316 goto fail;
319 * Initialize Commodities Exchange subsystem
321 if (!(cxmask = cx_init()))
322 goto fail;
325 * Syncronize with AmiTCP/IP
327 DNETTRACE(KPrintF("NETTRACE initialization complete, sending message...");)
328 initmsg->Msg.mn_ReplyPort = logPort;
329 initmsg->Msg.mn_Length = sizeof(struct SysLogPacket);
330 PutMsg(&logReplyPort, (struct Message *)initmsg);
331 do {
332 Wait(logmask);
333 } while(initmsg != (struct SysLogPacket *)GetMsg(logPort));
334 #if !defined(__AROS__)
335 D(KPrintF(" done!\n");)
336 #endif
338 FreeMem(initmsg, sizeof(struct SysLogPacket));
339 initmsg = NULL;
341 sigmask = logmask | rexxmask | cxmask | SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C;
344 * Main loop of the NETTRACE
346 for (;;) {
347 ULONG sig;
348 struct SysLogPacket *msg;
350 sig = Wait(sigmask | guimask); /* Wait for signals */
351 DNETTRACE(KPrintF("NETTRACE: got some signal...");)
352 do {
353 /* Signal from the AmiTCP/IP: API ready */
354 if ((sig & SIGBREAKF_CTRL_F) && (SocketBase == NULL)) {
355 sig &= ~SIGBREAKF_CTRL_F;
356 #if !defined(__AROS__)
357 D(KPrintF(" bsdsocket API ready\n");)
358 #endif
360 * Open a base to our own library so that ARexx message handling
361 * can use socket functions.
362 * This name does not work with the "nthLibrary" system
364 if (SocketBase = OpenLibrary("bsdsocket.library", SOCKET_VERSION)) {
366 * Make our ARexx port public
368 rexx_show();
370 * Make our Commodities Exchange object public
372 cx_show();
374 * Execute delayed DHCP startup
376 run_dhcp();
378 * Open control panel
380 if (OpenGUIOnStartup)
381 gui_open();
382 sigmask &= ~SIGBREAKF_CTRL_F;
385 if (sig & SIGBREAKF_CTRL_C) {
387 * Forward CTRL-C to our main task
389 Signal(AROSTCP_Task, SIGBREAKF_CTRL_C);
390 sig &= ~SIGBREAKF_CTRL_C;
393 if (sig & logmask) { /* Process log messages,
394 * handles all ones pending.
396 DNETTRACE(KPrintF(" log message\n");)
397 if (msg = log_poll()) { /* Got a LOG_CLOSE-message? */
398 DNETTRACE(KPrintF("Got LOG_CLOSE, exiting.\n");)
399 log_close(msg);
400 return;
402 sig &= ~logmask;
405 if (sig & rexxmask) { /* One rexx message at a time */
406 DNETTRACE(KPrintF(" REXX message\n");)
407 if (SocketBase) {
408 if (!rexx_poll())
409 sig &= ~rexxmask;
410 } else
411 sig &= ~rexxmask;
414 if (sig & cxmask) { /* One Exchange message at time */
415 DNETTRACE(KPrintF(" CX message\n");)
416 if (!cx_poll())
417 sig &= ~cxmask;
420 if (sig & guimask) {
421 DNETTRACE(KPrintF(" GUI signal\n");)
422 if (GUI_Running)
423 MiamiPanelEvent(sig & guimask);
424 sig &= ~guimask;
427 sig |= SetSignal(0L, sigmask) & sigmask; /* Signals left? */
428 } while (sig);
431 fail:
432 /* Initializion Failed */
433 if (initmsg)
434 FreeMem(initmsg, sizeof(struct SysLogPacket));
436 log_close(NULL);
438 logPort = (struct MsgPort *)-1;
439 /* Inform AmiTCP that we failed */
440 Signal(AROSTCP_Task, SIGBREAKF_CTRL_F);
443 #ifdef CONSOLE_SYSLOG
444 static BPTR confile = BNULL;
445 static BOOL conopenfail = FALSE;
446 static BOOL conwritefail = FALSE;
447 #endif
449 static BPTR logfile = BNULL;
450 static BOOL fileopenfail = FALSE;
451 static BOOL filewritefail = FALSE;
453 static char *months =
454 "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
456 static char *wdays =
457 "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
459 static char *levels =
460 "emerg\0"
461 "alert\0"
462 "crit \0"
463 "err \0"
464 "warn \0"
465 "note \0"
466 "info \0"
467 "debug";
469 void log_msg(struct SysLogPacket *msg)
471 LONG i;
472 int chars;
473 struct ClockData clockdata;
474 struct CSource cs;
476 /* 28 for date, 14 for level */
477 # define LEVELBUF 28+14
479 UBYTE buffer[LEVELBUF];
481 cs.CS_Buffer = buffer;
482 cs.CS_Length = LEVELBUF;
483 cs.CS_CurChr = 0;
485 Amiga2Date(msg->Time, &clockdata);
487 csprintf(&cs,
488 #ifdef HAVE_TIMEZONES
489 "%s %s %02d %02d:%02d:%02d %s %4d [%s]: ",
490 #else
491 "%s %s %02d %02d:%02d:%02d %4d [%s]: ",
492 #endif
493 wdays + 4 * clockdata.wday,
494 months + 4 * (clockdata.month - 1),
495 clockdata.mday,
496 clockdata.hour,
497 clockdata.min,
498 clockdata.sec,
499 #ifdef HAVE_TIMEZONES
500 "UCT", /* Universal Coordinated Time */
501 #endif
502 clockdata.year,
503 levels + 6 * ((msg->Level <= LOG_DEBUG) ? msg->Level : LOG_DEBUG)
505 chars = strlen(msg->String) - 1;
506 /* Remove last newline */
507 if (msg->String[chars] == '\n') {
508 msg->String[chars] = '\0';
511 /* Replace all control chars with space */
512 for (i = 0; msg->String[i]; ++i) {
513 if ((msg->String)[i] < ' ')
514 (msg->String)[i] = ' ';
516 #ifdef CONSOLE_SYSLOG
517 /* If console is not open, open it */
518 while (confile == NULL) {
519 if ((confile = logOpen(consolename)) == NULL) {
520 if (!conopenfail) /* log only once */
521 __log(LOG_ERR,"Opening console log '%s' failed", consolename);
522 if (consolename == consoledefname) {
523 conopenfail = TRUE;
524 break;
526 /* try again with the default name */
527 consolename = consoledefname;
528 conopenfail = conwritefail = FALSE;
531 if (confile != NULL) {
532 int error = FPuts(confile, buffer) == -1;
533 if ((!error) && msg->Tag)
534 error = FPrintf(confile, "%s: ", msg->Tag) == -1;
535 error = error ||
536 FPuts(confile, msg->String) == -1 ||
537 FPutC(confile, '\n') == -1;
538 Flush(confile);
539 if (error && !conwritefail) { /* To avoid loops */
540 conwritefail = TRUE;
541 __log(LOG_ERR, "log: Write failed to console '%s'", consolename);
544 #endif
545 if (LOG_PRI(msg->Level) <= log_cnf.log_filter) {
546 /* If log file is not open, open it */
547 while (logfile == BNULL) {
548 if ((logfile = logOpen(logfilename)) == BNULL) {
549 if (!fileopenfail) /* log only once */
550 __log(LOG_ERR,"Opening log file '%s' failed", logfilename);
551 if (logfilename == logfiledefname) {
552 fileopenfail = TRUE;
553 break;
555 /* try again with the default name */
556 logfilename = logfiledefname;
557 fileopenfail = filewritefail = FALSE;
560 if (logfile != BNULL) {
561 int error = FPuts(logfile, buffer) == -1;
562 if ((!error) && msg->Tag)
563 error = FPrintf(logfile, "%s: ", msg->Tag) == -1;
564 error = error ||
565 FPuts(logfile, msg->String) == -1 ||
566 FPutC(logfile, '\n') == -1;
567 Flush(logfile);
568 if (error && !filewritefail) { /* To avoid loops */
569 filewritefail = TRUE;
570 __log(LOG_ERR, "log: Write failed to file '%s'", logfilename);
576 * Process all pending log messages
578 static
579 struct SysLogPacket *log_poll()
581 struct SysLogPacket *msg;
582 static ULONG TotalFail;
584 /* Process all messages */
585 while (msg = (struct SysLogPacket *)GetMsg(logPort)) {
587 if (msg == (struct SysLogPacket *)gui_timerio)
588 gui_process_refresh();
589 else {
590 DNETTRACE(KPrintF("Message level = 0x%08lx\n", msg->Level);)
591 if (msg->Level == LOG_CLOSE) {
592 return (msg);
594 if ((msg->Level & LOG_CMDMASK) == LOG_GUIMSG) {
595 gui_process_msg(msg);
596 ReplyMsg((struct Message *)msg);
597 } else {
598 log_msg(msg);
599 if (ExtLogPort)
600 PutMsg(ExtLogPort, (struct Message *)msg);
601 else
602 ReplyMsg((struct Message *)msg);
603 if (GetLogMsgFail != TotalFail) {
604 int t = GetLogMsgFail; /* Check if we have lost messages */
606 __log(LOG_WARNING,"%ld log messages lost (total %ld lost)\n",
607 t - TotalFail, TotalFail);
608 TotalFail = t;
613 return(NULL);
616 /* Close logging subsystem */
617 static
618 void log_close(struct SysLogPacket *msg)
620 #if defined(__AROS__)
621 D(bug("[AROSTCP](amiga_log.c) log_close()\n"));
622 #endif
623 gui_close();
624 cx_deinit();
625 rexx_deinit();
626 DNETTRACE(KPrintF("rexx_deinit() completed\n");)
627 #ifdef CONSOLE_SYSLOG
628 if (confile) {
629 Close(confile);
630 DNETTRACE(KPrintF("confile closed\n");)
632 #endif
633 if (logfile) {
634 Close(logfile);
635 DNETTRACE(KPrintF("logfile closed\n");)
637 if (logUtilityBase) {
638 CloseLibrary(logUtilityBase);
639 logUtilityBase = NULL;
640 DNETTRACE(KPrintF("logUtilityBase closed\n");)
642 if (logDOSBase) { /* DOS not needed below */
643 CloseLibrary(logDOSBase);
644 logDOSBase = NULL;
645 DNETTRACE(KPrintF("logDOSBase closed\n");)
647 if (SocketBase) {
648 CloseLibrary((struct Library *)SocketBase);
649 SocketBase = NULL;
650 DNETTRACE(KPrintF("SocketBase closed\n");)
653 * Make sure that we get to end before task switch
654 * and do not get messages from interrupts
656 Disable();
658 if (logPort) {
659 struct Message *m;
661 while (m = GetMsg(logPort)) {/* Check for messages and reply */
662 ReplyMsg(m);
663 DNETTRACE(KPrintF("Message replied\n");)
666 DeleteMsgPort(logPort); /* Delete port */
667 logPort = NULL;
668 DNETTRACE(KPrintF("logPort deleted\n");)
671 if (msg) {
672 if (ExtLogPort)
673 PutMsg(ExtLogPort, (struct Message *)msg);
674 else
675 ReplyMsg((struct Message *)msg);
676 DNETTRACE(KPrintF("LOG_CLOSE replied\n");)
679 Nettrace_Task = NULL;
682 * Interrupts are left disabled,
683 * they will be enabled again when this process dies
685 DNETTRACE(KPrintF("log_close() finished\n");)
689 * Try first open w/ shared lock, then as an old file and finally as a new file
691 static
692 BPTR logOpen(STRPTR name)
694 BPTR file;
695 #if defined(__AROS__)
696 D(bug("[AROSTCP](amiga_log.c) logOpen()\n"));
697 #endif
699 if ((file = Open(name, MODE_READWRITE)) ||
700 (file = Open(name, MODE_OLDFILE)))
701 Seek(file, 0, OFFSET_END);
702 else
703 file = Open(name, MODE_NEWFILE);
705 return file;
709 * This function might be called by either AmiTCP or NETTRACE. If the
710 * call is done by the AmiTCP, no DOS calls may be done, since the
711 * DosBase used by these functions is the one of the NETTRACE, and is
712 * not initialized at that time!
714 int logname_changed(void *p, IPTR new)
716 #if defined(__AROS__)
717 D(bug("[AROSTCP](amiga_log.c) logname_changed()\n"));
718 #endif
719 if (p == &logfilename) { /* Is logname requested? */
721 * logfile may be non-NULL only if the NETTRACE is already initialized
723 if (logfile != BNULL) {
724 Close(logfile);
725 logfile = BNULL;
727 fileopenfail = filewritefail = FALSE;
729 * setvalue() (who called this) will set the new value when we return
730 * TRUE.
732 return TRUE;
734 #ifdef CONSOLE_SYSLOG
735 if ( p == &consolename ) { /* Name of the console log */
737 if (confile) { /* only if NETTRACE is already initialized */
738 Close(confile);
739 confile = BNULL;
741 conopenfail = conwritefail = FALSE;
743 * setvalue() (who called this) will set the new value when we return
744 * TRUE.
746 return TRUE;
748 #endif
750 * Some invalid pointer
752 return FALSE;