ProviewR Programmer's Reference Manual  V7.0.0
rt_errh.c
Go to the documentation of this file.
1 /*
2  * ProviewR Open Source Process Control.
3  * Copyright (C) 2005-2026 SSAB EMEA AB.
4  *
5  * This file is part of ProviewR.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with ProviewR. If not, see <http://www.gnu.org/licenses/>
19  *
20  * Linking ProviewR statically or dynamically with other modules is
21  * making a combined work based on ProviewR. Thus, the terms and
22  * conditions of the GNU General Public License cover the whole
23  * combination.
24  *
25  * In addition, as a special exception, the copyright holders of
26  * ProviewR give you permission to, from the build function in the
27  * ProviewR Configurator, combine ProviewR with modules generated by the
28  * ProviewR PLC Editor to a PLC program, regardless of the license
29  * terms of these modules. You may copy and distribute the resulting
30  * combined work under the terms of your choice, provided that every
31  * copy of the combined work is accompanied by a complete copy of
32  * the source code of ProviewR (the version used to produce the
33  * combined work), being distributed under the terms of the GNU
34  * General Public License plus this exception.
35  */
36 
37 /* rt_errh.c -- Logg errors and more.
38  The routines in this module are the error logging package. */
39 
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <limits.h>
47 #include <pthread.h> /* for tid_t */
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <stdio.h> /* for EOF */
51 #include <string.h>
52 #include <unistd.h>
53 
54 #if defined OS_LINUX || defined OS_CYGWIN
55 #include <mqueue.h>
56 #elif defined OS_MACOS || defined OS_FREEBSD || defined OS_OPENBSD
57 #include <sys/msg.h>
58 #include <sys/ipc.h>
59 #endif
60 
61 #include "pwr_msg.h"
62 #include "co_msg.h"
63 #include "co_time.h"
64 #include "co_string.h"
65 #include "rt_gdh.h"
66 #include "rt_errh_msg.h"
67 #include "rt_pwr_msg.h"
68 
69 #define UNKNOWN_PROGRAM_NAME "Unknown name "
70 
71 //typedef void* aa_list[];
72 
73 typedef enum { eArg_sts, eArg_int, eArg_string } eArg;
74 
75 typedef struct {
76  eArg class;
77  union {
78  pwr_tStatus sts;
79  int intval;
80  char* string;
81  } u;
82 } sArg;
83 
84 #if defined OS_LINUX || defined OS_CYGWIN
85 typedef pid_t sPid;
86 
87 static mqd_t mqid = (mqd_t)-1;
88 static unsigned int prio = 0;
89 static int mq_send_errno = 0;
90 #elif defined OS_MACOS || defined OS_FREEBSD || defined OS_OPENBSD
91 typedef pid_t sPid;
92 
93 static int mqid = -1;
94 // static unsigned int prio = 0;
95 static int mq_send_errno = 0;
96 #endif
97 
98 static char programName[16];
99 static int interactive = 0;
100 static int initDone = 0;
101 static errh_eAnix errh_anix = errh_eNAnix;
102 
103 static char* get_header(char, char*);
104 static char* get_message(const int, unsigned int, char*, int);
105 static char* get_name(char*, int);
106 static char get_severity(pwr_tStatus);
107 static void openLog();
108 static void set_name(const char*);
109 static void errh_send(char*, char, pwr_tStatus, errh_eMsgType);
110 static void log_message(errh_sLog*, char, const char*, va_list);
111 //static int msg_vsprintf(char*, const char*, aa_list, va_list);
112 
113 static char anix_name[40][32] = {
114  "rt_init",
115  "rt_qmon",
116  "rt_neth",
117  "rt_neth_acp",
118  "rt_io",
119  "rt_tmon",
120  "rt_emon",
121  "rt_alimserver",
122  "rt_bck",
123  "rt_linksup",
124  "rt_trend",
125  "rt_fast",
126  "rt_elog",
127  "rt_webmon",
128  "rt_webmonmh",
129  "rt_sysmon",
130  "plc",
131  "rs_remotehandler",
132  "opc_server",
133  "rt_statussrv",
134  "rt_post",
135  "rt_report",
136  "rt_sevhistmon",
137  "rt_sim",
138  "rt_powerlink",
139  "rt_videomgm",
140  "rt_redcom",
141  "rt_websocketserver",
142  "rt_maintsupserver",
143  "rt_mqttserver",
144 };
145 
146 void errh_AnixName(errh_eAnix anix, char *name)
147 {
148  if (anix > 0 && anix <= 40)
149  strcpy(name, anix_name[anix - 1]);
150  else
151  strcpy(name, "");
152 }
153 
154 void errh_Interactive(void)
155 {
156  interactive = 1;
157 }
158 
171 pwr_tStatus errh_Init(const char* name, errh_eAnix anix)
172 {
173  get_name(programName, sizeof(programName) - 1);
174  if (name != NULL && name[0] != '\0')
175  set_name(name);
176  errh_anix = anix;
177 
178  if (!initDone) {
179  initDone = 1;
180  openLog();
181  }
182 
183  return 1;
184 }
185 
196 {
197  /* Send close message */
198  errh_send(0, 0, sts, errh_eMsgType_Status);
199 }
200 
206 {
207  return errh_anix;
208 }
209 
214 {
215  errh_anix = anix;
216 }
217 
221 void errh_SetName(char* name)
222 {
223  set_name(name);
224 }
225 
226 /* Check if a given messagenumber exists,
227  return string representation if valid. */
228 
229 char* errh_GetMsg(const int sts, char* buf, int bufSize)
230 {
231  return get_message(sts, 0xf, buf, bufSize);
232 }
233 
234 /* Checks if a given messagenumber exists,
235  return string representation if valid. */
236 
237 char* errh_GetText(const int sts, char* buf, int bufSize)
238 {
239  return get_message(sts, 1, buf, bufSize);
240 }
241 
242 /* Log a message. */
243 char* errh_Log(char* buff, char severity, const char* msg, ...)
244 {
245  char* s;
246  va_list ap;
247 
248  s = get_header(severity, buff);
249  va_start(ap, msg);
250  msg_vsprintf(s, msg, NULL, ap);
251  va_end(ap);
252 
253  if (interactive)
254  printf("%s\n", buff);
255  else
256  errh_send(buff, severity, 0, errh_eMsgType_Log);
257 
258  return buff;
259 }
260 
273 void errh_Success(const char* msg, ...)
274 {
275  va_list args;
276 
277  va_start(args, msg);
278  log_message(NULL, 'S', msg, args);
279  va_end(args);
280 }
281 
294 void errh_Info(const char* msg, ...)
295 {
296  va_list args;
297 
298  va_start(args, msg);
299  log_message(NULL, 'I', msg, args);
300  va_end(args);
301 }
302 
315 void errh_Warning(const char* msg, ...)
316 {
317  va_list args;
318 
319  va_start(args, msg);
320  log_message(NULL, 'W', msg, args);
321  va_end(args);
322 }
323 
336 void errh_Error(const char* msg, ...)
337 {
338  va_list args;
339 
340  va_start(args, msg);
341  log_message(NULL, 'E', msg, args);
342  va_end(args);
343 }
344 
357 void errh_Fatal(const char* msg, ...)
358 {
359  va_list args;
360 
361  va_start(args, msg);
362  log_message(NULL, 'F', msg, args);
363  va_end(args);
364 }
365 
366 /* Log a fatal message. */
367 void errh_LogFatal(errh_sLog* lp, const char* msg, ...)
368 {
369  va_list args;
370 
371  va_start(args, msg);
372  log_message(lp, 'F', msg, args);
373  va_end(args);
374 }
375 
376 /* Log a warning message. */
377 void errh_LogWarning(errh_sLog* lp, const char* msg, ...)
378 {
379  va_list args;
380 
381  va_start(args, msg);
382  log_message(lp, 'W', msg, args);
383  va_end(args);
384 }
385 
386 /* Log a error message. */
387 void errh_LogError(errh_sLog* lp, const char* msg, ...)
388 {
389  va_list args;
390 
391  va_start(args, msg);
392  log_message(lp, 'E', msg, args);
393  va_end(args);
394 }
395 
396 /* Log a info message. */
397 void errh_LogInfo(errh_sLog* lp, const char* msg, ...)
398 {
399  va_list args;
400 
401  va_start(args, msg);
402  log_message(lp, 'I', msg, args);
403  va_end(args);
404 }
405 
406 /* Log a success message. */
407 void errh_LogSuccess(errh_sLog* lp, const char* msg, ...)
408 {
409  va_list args;
410 
411  va_start(args, msg);
412  log_message(lp, 'S', msg, args);
413  va_end(args);
414 }
415 
416 /* Insert a status message in a message. */
417 
418 void* errh_ErrArgMsg(pwr_tStatus sts)
419 {
420  sArg* eap;
421 
422  eap = (sArg*)malloc(sizeof(*eap));
423  eap->class = eArg_sts;
424  eap->u.sts = sts;
425 
426  return eap;
427 }
428 
429 /* Insert a string argument in a message. */
430 
431 void* errh_ErrArgAF(char* str)
432 {
433  sArg* eap;
434 
435  eap = (sArg*)malloc(sizeof(*eap));
436 
437  eap->class = eArg_string;
438  eap->u.string = str;
439 
440  return eap;
441 }
442 
443 /* Insert a integer value in a message. */
444 
445 void* errh_ErrArgL(int val)
446 {
447  sArg* eap;
448 
449  eap = (sArg*)malloc(sizeof(*eap));
450 
451  eap->class = eArg_int;
452  eap->u.intval = val;
453 
454  return eap;
455 }
456 
457 void errh_CErrLog(pwr_tStatus sts, ...)
458 {
459  va_list ap;
460  void* args[25];
461  char msg[200];
462  sArg* eap;
463  int argno = 0;
464  char* s;
465  char string[1000];
466 
467  get_message(sts, 0xb, msg, sizeof(msg));
468 
469  va_start(ap, sts);
470  while ((eap = va_arg(ap, sArg*)) != NULL) {
471  switch (eap->class) {
472  case eArg_sts:
473  args[argno++] = (char*)((long int)eap->u.sts);
474  strcat(msg, "\n%m");
475  break;
476  case eArg_int:
477  args[argno++] = (char*)((long int)eap->u.intval);
478  break;
479  case eArg_string:
480  args[argno++] = eap->u.string;
481  break;
482  }
483  free(eap);
484  }
485  va_end(ap);
486 
487  args[argno] = NULL;
488 
489  va_list tmp;
490  memset(&tmp, 0, sizeof(tmp));
491  s = get_header(get_severity(sts), string);
492  msg_vsprintf(s, msg, args, tmp);
493  errh_send(string, get_severity(sts), sts, errh_eMsgType_Log);
494 }
495 
496 /* Format a string. */
497 
498 char* errh_Message(char* string, char severity, char* msg, ...)
499 {
500  char* s;
501  va_list ap;
502 
503  s = get_header(severity, string);
504  va_start(ap, msg);
505  msg_vsprintf(s, msg, NULL, ap);
506  va_end(ap);
507 
508  return string;
509 }
510 
511 /* Get a message string, VMS style.
512 
513  %FACILITYNAME-S-MESSAGENAME, message string
514 
515  flags:
516  0x1 message string
517  0x2 MESSAGENAME
518  0x4 S (severity)
519  0x8 FACILITYNAME
520  0xf % + all
521 
522  any other gives a combination of above excluding % */
523 
524 static char* get_message(
525  const pwr_tStatus sts, unsigned int flags, char* buf, int bufSize)
526 {
527  return msg_GetMessage(sts, flags, buf, bufSize);
528 }
529 
530 static void set_name(const char* name)
531 {
532  strncpy(programName, name, sizeof(programName) - 1);
533  programName[sizeof(programName) - 1] = '\0';
534 }
535 
536 static void openLog()
537 {
538 #if defined OS_LINUX || defined OS_CYGWIN
539  if (mqid == (mqd_t)-1) {
540  char name[64];
541  char* busid = getenv(pwr_dEnvBusId);
542 
543  sprintf(name, "%s_%s", LOG_QUEUE_NAME, busid ? busid : "");
544  mqid = mq_open(name, O_WRONLY | O_NONBLOCK, 0, 0);
545  if (mqid == (mqd_t)-1) {
546  char string[256];
547  char* s;
548 
549  s = errh_Message(
550  string, 'E', "Open messageQ, mq_open(%s)\n%s", name, strerror(errno));
551  printf("%s\n", s);
552  return;
553  }
554  }
555 #elif defined OS_MACOS || defined OS_FREEBSD || defined OS_OPENBSD
556  if (mqid == (key_t)-1) {
557  char name[64];
558  char* busid = getenv(pwr_dEnvBusId);
559  key_t key;
560  int fd;
561  int flags = O_RDWR | O_CREAT;
562  mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
563 
564  sprintf(name, "%s_%s", LOG_QUEUE_NAME, busid ? busid : "");
565  fd = open(name, flags, mode);
566  if (fd == -1) {
567  printf("Message Queue, open failed on %s, errno: %d\n", name, errno);
568  }
569  key = ftok(name, 'm');
570  close(fd);
571 
572  mqid = msgget(key, IPC_CREAT | 0660);
573  if (mqid == -1) {
574  char string[256];
575  char* s;
576 
577  s = errh_Message(string, 'E', "Open message queue, msgget(%s)\n%s", name,
578  strerror(errno));
579  printf("%s\n", s);
580  return;
581  }
582  }
583 #endif
584 }
585 
586 static char* get_name(char* name, int size)
587 {
588  int len = strlen(UNKNOWN_PROGRAM_NAME);
589 
590  strncpy(name, UNKNOWN_PROGRAM_NAME, MIN(size, len));
591 
592  name[MIN(size, len)] = '\0';
593 
594  return name;
595 }
596 static sPid* get_pid(sPid* pid)
597 {
598  *pid = getpid();
599 
600  return pid;
601 }
602 
603 static char* get_header(char severity, char* s)
604 {
605  sPid pid;
606  pwr_tTime time;
607  struct tm tp, *t;
608 
609  if (!initDone)
610  errh_Init(NULL, 0);
611 
612  if (interactive) {
613  s += sprintf(s, "%c ", severity);
614  return s;
615  }
616 
617  time_GetTime(&time);
618 
619  get_pid(&pid);
620 
621  s += sprintf(s, "%c %-*.*s", severity, (int)sizeof(programName),
622  (int)sizeof(programName), programName);
623 
624  time_t sec = time.tv_sec;
625  localtime_r(&sec, &tp);
626  t = &tp;
627  s += sprintf(s, " %8d ", pid);
628 
629  s += sprintf(s, "%02d-%02d-%02d %02d:%02d:%02d.%02d ", t->tm_year % 100,
630  t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
631  (int)(time.tv_nsec / 10000000));
632 
633  return s;
634 }
635 
636 /* Format a string and write it to log devices. */
637 
638 static void log_message(
639  errh_sLog* lp, char severity, const char* msg, va_list ap)
640 {
641  char* s;
642  char string[1000];
643 
644  s = get_header(severity, string);
645  msg_vsprintf(s, msg, NULL, ap);
646  if (interactive)
647  printf("%s\n", string);
648  else
649  errh_send(string, severity, 0, errh_eMsgType_Log);
650 
651  if (lp != NULL && lp->send) {
652  lp->put.data = string;
653  lp->put.size = strlen(string) + 1;
654  lp->put.allocate = 1;
655  qcom_Put(NULL, &lp->logQ, &lp->put);
656  }
657 }
658 
659 /* Print a message on error log. */
660 
661 static char get_severity(pwr_tStatus sts)
662 {
663  switch (sts & 7) {
664  case 0:
665  return 'W';
666  case 1:
667  return 'S';
668  case 2:
669  return 'E';
670  case 3:
671  return 'I';
672  case 4:
673  return 'F';
674  default:
675  return '?';
676  }
677 }
678 
679 /****** internals ************************************************************/
680 
681 /* Handle numerics. */
682 
683 static void errh_send(
684  char* s, char severity, pwr_tStatus sts, errh_eMsgType message_type)
685 {
686 #if defined OS_LINUX || defined OS_CYGWIN
687 
688  int len;
689  if (mqid != (mqd_t)-1) {
690  errh_sMsg msg;
691 
692  switch (message_type) {
693  case errh_eMsgType_Log:
694  strncpy(msg.str, s, LOG_MAX_MSG_SIZE);
695  str_Cut(msg.str, LOG_MAX_MSG_SIZE);
696  msg.message_type = message_type;
697  msg.severity = severity;
698  msg.sts = sts;
699  msg.anix = errh_anix;
700  len = sizeof(msg) - sizeof(msg.message_type) - sizeof(msg.str)
701  + strlen(msg.str) + 1;
702  break;
704  msg.message_type = message_type;
705  msg.sts = sts;
706  msg.anix = errh_anix;
707  len = sizeof(msg) - sizeof(msg.message_type) - sizeof(msg.str);
708  break;
709  }
710  if (prio == 0)
711  prio = sysconf(_SC_MQ_PRIO_MAX) - 1;
712  if (mq_send(mqid, (char*)&msg, MIN(len, LOG_MAX_MSG_SIZE - 1), prio)
713  == -1) {
714  if (mq_send_errno != errno) {
715  mq_send_errno = errno;
716  perror("mq_send");
717  }
718  }
719  } else if (s) {
720  puts(s);
721  return;
722  }
723 
724 #elif defined OS_MACOS || defined OS_FREEBSD || defined OS_OPENBSD
725 
726  int len;
727  if (mqid != -1) {
728  errh_sMsg msg;
729 
730  switch (message_type) {
731  case errh_eMsgType_Log:
732  strncpy(msg.str, s, LOG_MAX_MSG_SIZE);
733  str_Cut(msg.str, LOG_MAX_MSG_SIZE);
734  msg.message_type = message_type;
735  msg.severity = severity;
736  msg.sts = sts;
737  msg.anix = errh_anix;
738  len = sizeof(msg) - sizeof(msg.message_type) - sizeof(msg.str)
739  + strlen(msg.str) + 1;
740  break;
742  msg.message_type = message_type;
743  msg.sts = sts;
744  msg.anix = errh_anix;
745  len = sizeof(msg) - sizeof(msg.message_type) - sizeof(msg.str);
746  break;
747  }
748  // if ( prio == 0)
749  // prio = sysconf(_SC_MQ_PRIO_MAX) - 1;
750  if (msgsnd(mqid, (char*)&msg, MIN(len, LOG_MAX_MSG_SIZE - 1), 0) == -1) {
751  if (mq_send_errno != errno) {
752  mq_send_errno = errno;
753  perror("msgsnd");
754  }
755  }
756  } else if (s) {
757  puts(s);
758  return;
759  }
760 
761 #else
762 
763  if (message_type != errh_eMsgType_Log)
764  return;
765 
766  printf("%s\n", s);
767 
768 #endif
769 }
770 
771 errh_eSeverity errh_Severity(pwr_tStatus sts)
772 {
773  if (sts == 0)
774  return errh_eSeverity_Null;
775 
776  switch (sts & 7) {
777  case 1:
778  return errh_eSeverity_Success;
779  case 3:
780  return errh_eSeverity_Info;
781  case 0:
782  return errh_eSeverity_Warning;
783  case 2:
784  return errh_eSeverity_Error;
785  case 4:
786  return errh_eSeverity_Fatal;
787  default:
788  return errh_eSeverity_Null;
789  }
790 }
Include file for Time management.
errh_eAnix
Definition: rt_errh.h:99
errh_eMsgType
Definition: rt_errh.h:207
errh_eSeverity
Definition: rt_errh.h:83
@ errh_eMsgType_Log
Definition: rt_errh.h:208
@ errh_eMsgType_Status
Definition: rt_errh.h:209
void errh_Error(const char *msg,...)
Log an error message. The function has a variable argument list similar to sprintf.
Definition: rt_errh.c:336
pwr_tStatus errh_Init(const char *name, errh_eAnix anix)
Initialize errh. Set up a queue to write to, set application name.
Definition: rt_errh.c:171
void errh_SetStatus(pwr_tStatus sts)
Set application status. The application status is showed in the Node graph. The application can set t...
Definition: rt_errh.c:195
errh_eAnix errh_Anix(void)
Get application index for the process.
Definition: rt_errh.c:205
void errh_Success(const char *msg,...)
Log a success message. The function has a variable argument list similar to sprintf.
Definition: rt_errh.c:273
void errh_SetName(char *name)
Set application name for the process.
Definition: rt_errh.c:221
void errh_Fatal(const char *msg,...)
Log a fatal message. The function has a variable argument list similar to sprintf.
Definition: rt_errh.c:357
void errh_SetAnix(errh_eAnix anix)
Set application index for the process.
Definition: rt_errh.c:213
void errh_Info(const char *msg,...)
Log an info message. The function has a variable argument list similar to sprintf.
Definition: rt_errh.c:294
void errh_Warning(const char *msg,...)
Log a warning message. The function has a variable argument list similar to sprintf.
Definition: rt_errh.c:315
pwr_tBoolean qcom_Put(pwr_tStatus *sts, const qcom_sQid *receiver, qcom_sPut *put)
Put a new message.
Definition: rt_qcom.c:747
int time_GetTime(pwr_tTime *ts)
Get current time.
Definition: co_time.c:1427
int pwr_tStatus
Status type.
Definition: pwr.h:284
Include file for Gdh Global Data Handler.