2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
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,
25 #include <sys/param.h>
26 #include <sys/systm.h>
29 #include <exec/exec.h>
31 #include <dos/dostags.h>
32 #include <dos/dosextens.h>
34 #include <kern/amiga_includes.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
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
100 #if defined(__AROS__)
101 D(bug("[AROSTCP](amiga_log.c) log_init()\n"));
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
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 */
120 #if defined(__AROS__)
121 DSYSCALLS(__log(LOG_DEBUG
,"Set initial SysLogPort");)
122 ExtLogPort
= FindPort("SysLog");
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...");)
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
,
142 if (CreateNewProcTags(NP_Entry
, (IPTR
)&log_task
,
143 NP_Name
, (IPTR
)LOG_TASK_NAME
,
144 NP_Priority
, LOG_TASK_PRI
,
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");)
161 else if (msg
= GetMsg(&logReplyPort
)) { /* Got message back? */
162 D(Printf(" done!\n");)
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
189 /* A little stub for calling GetMsg w/ error reporting and cheking */
190 struct SysLogPacket
*GetLogMsg(struct MsgPort
*port
)
193 #if defined(__AROS__)
194 D(bug("[AROSTCP](amiga_log.c) GetLogMsg()\n"));
197 /* We should have a port, if not-> fail */
199 ObtainSemaphore(&LogLock
);
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
;
209 port
->mp_Flags
= PA_IGNORE
;
212 DNETTRACE(else KPrintF("WARNING!!! port = NULL!\n");)
214 ++GetLogMsgFail
; /* Increment number of failed messages */
219 * This function may be called only if no other tasks (applications) are
220 * accessing the logging system (the messages, to be exact).
225 struct SysLogPacket
*msg
, *dump
;
226 #if defined(__AROS__)
227 D(bug("[AROSTCP](amiga_log.c) log_deinit()\n"));
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");)
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 */
259 D(Printf("Freeing log_buffers\n");)
260 FreeMem(log_buffers
, log_buffers_mem_size
);
264 D(Printf("Freeing log_messages\n");)
265 FreeMem(log_messages
, log_messages_mem_size
);
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 */
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"));
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
)
298 if ((logUtilityBase
= OpenLibrary("utility.library", 37L)) == NULL
)
301 /* Allocate message to reply startup */
302 if ((initmsg
= AllocMem(sizeof(struct SysLogPacket
), MEMF_CLEAR
|MEMF_PUBLIC
))
306 /* Create our port for log messages */
307 if ((logPort
= CreateMsgPort()) == NULL
)
310 logmask
= 1<<logPort
->mp_SigBit
;
313 * Initialize rexx subsystem
315 if (!(rexxmask
= rexx_init()))
319 * Initialize Commodities Exchange subsystem
321 if (!(cxmask
= cx_init()))
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
);
333 } while(initmsg
!= (struct SysLogPacket
*)GetMsg(logPort
));
334 #if !defined(__AROS__)
335 D(KPrintF(" done!\n");)
338 FreeMem(initmsg
, sizeof(struct SysLogPacket
));
341 sigmask
= logmask
| rexxmask
| cxmask
| SIGBREAKF_CTRL_F
| SIGBREAKF_CTRL_C
;
344 * Main loop of the NETTRACE
348 struct SysLogPacket
*msg
;
350 sig
= Wait(sigmask
| guimask
); /* Wait for signals */
351 DNETTRACE(KPrintF("NETTRACE: got some signal...");)
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");)
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
370 * Make our Commodities Exchange object public
374 * Execute delayed DHCP startup
380 if (OpenGUIOnStartup
)
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");)
405 if (sig
& rexxmask
) { /* One rexx message at a time */
406 DNETTRACE(KPrintF(" REXX message\n");)
414 if (sig
& cxmask
) { /* One Exchange message at time */
415 DNETTRACE(KPrintF(" CX message\n");)
421 DNETTRACE(KPrintF(" GUI signal\n");)
423 MiamiPanelEvent(sig
& guimask
);
427 sig
|= SetSignal(0L, sigmask
) & sigmask
; /* Signals left? */
432 /* Initializion Failed */
434 FreeMem(initmsg
, sizeof(struct SysLogPacket
));
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
;
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";
457 "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
459 static char *levels
=
469 void log_msg(struct SysLogPacket
*msg
)
473 struct ClockData clockdata
;
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
;
485 Amiga2Date(msg
->Time
, &clockdata
);
488 #ifdef HAVE_TIMEZONES
489 "%s %s %02d %02d:%02d:%02d %s %4d [%s]: ",
491 "%s %s %02d %02d:%02d:%02d %4d [%s]: ",
493 wdays
+ 4 * clockdata
.wday
,
494 months
+ 4 * (clockdata
.month
- 1),
499 #ifdef HAVE_TIMEZONES
500 "UCT", /* Universal Coordinated Time */
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
) {
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;
536 FPuts(confile
, msg
->String
) == -1 ||
537 FPutC(confile
, '\n') == -1;
539 if (error
&& !conwritefail
) { /* To avoid loops */
541 __log(LOG_ERR
, "log: Write failed to console '%s'", consolename
);
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
) {
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;
565 FPuts(logfile
, msg
->String
) == -1 ||
566 FPutC(logfile
, '\n') == -1;
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
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();
590 DNETTRACE(KPrintF("Message level = 0x%08lx\n", msg
->Level
);)
591 if (msg
->Level
== LOG_CLOSE
) {
594 if ((msg
->Level
& LOG_CMDMASK
) == LOG_GUIMSG
) {
595 gui_process_msg(msg
);
596 ReplyMsg((struct Message
*)msg
);
600 PutMsg(ExtLogPort
, (struct Message
*)msg
);
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
);
616 /* Close logging subsystem */
618 void log_close(struct SysLogPacket
*msg
)
620 #if defined(__AROS__)
621 D(bug("[AROSTCP](amiga_log.c) log_close()\n"));
626 DNETTRACE(KPrintF("rexx_deinit() completed\n");)
627 #ifdef CONSOLE_SYSLOG
630 DNETTRACE(KPrintF("confile closed\n");)
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
);
645 DNETTRACE(KPrintF("logDOSBase closed\n");)
648 CloseLibrary((struct Library
*)SocketBase
);
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
661 while (m
= GetMsg(logPort
)) {/* Check for messages and reply */
663 DNETTRACE(KPrintF("Message replied\n");)
666 DeleteMsgPort(logPort
); /* Delete port */
668 DNETTRACE(KPrintF("logPort deleted\n");)
673 PutMsg(ExtLogPort
, (struct Message
*)msg
);
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
692 BPTR
logOpen(STRPTR name
)
695 #if defined(__AROS__)
696 D(bug("[AROSTCP](amiga_log.c) logOpen()\n"));
699 if ((file
= Open(name
, MODE_READWRITE
)) ||
700 (file
= Open(name
, MODE_OLDFILE
)))
701 Seek(file
, 0, OFFSET_END
);
703 file
= Open(name
, MODE_NEWFILE
);
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"));
719 if (p
== &logfilename
) { /* Is logname requested? */
721 * logfile may be non-NULL only if the NETTRACE is already initialized
723 if (logfile
!= BNULL
) {
727 fileopenfail
= filewritefail
= FALSE
;
729 * setvalue() (who called this) will set the new value when we return
734 #ifdef CONSOLE_SYSLOG
735 if ( p
== &consolename
) { /* Name of the console log */
737 if (confile
) { /* only if NETTRACE is already initialized */
741 conopenfail
= conwritefail
= FALSE
;
743 * setvalue() (who called this) will set the new value when we return
750 * Some invalid pointer