nmc-utils  0.1.1
nmlogd.c
Go to the documentation of this file.
1 /*
2  * libEasyNMC DSP communication library.
3  * Copyright (C) 2014 RC "Module"
4  * Written by Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * ut WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  */
21 
22 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <stdio.h>
25 #include <getopt.h>
26 #include <sys/ioctl.h>
27 #include <unistd.h>
28 #include <sys/select.h>
29 #include <string.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <termios.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdint.h>
40 #include <getopt.h>
41 #include <errno.h>
42 #include <sys/epoll.h>
43 #include <syslog.h>
44 #include <easynmc.h>
45 
46 #define MODE_SYSLOG 2
47 #define MODE_STDOUT 1
48 #define MODE_FILE 0
49 
50 static int g_mode = MODE_STDOUT;
51 static int g_nodaemon;
52 static int g_debug = 1;
53 
54 
55 #define dbg(fmt, ...) if (g_debug > 1) { \
56  fprintf(stderr, "nmlogd: " fmt, ##__VA_ARGS__); \
57  }
58 
59 #define err(fmt, ...) if (g_debug) { \
60  fprintf(stderr, "nmlogd: " fmt, ##__VA_ARGS__); \
61  }
62 
63 
64 void usage(char *nm)
65 {
66  fprintf(stderr,
67  "nmlogd - The EasyNMC logging daemon\n"
68  "(c) 2014 RC Module | Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>\n"
69  "This is free software; see the source for copying conditions. There is NO\n"
70  "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
71  "License: LGPLv2 \n"
72  "Usage: %s [options] - operate on core 0 (default)\n"
73  "Valid options are: \n"
74  " --help - Show this help\n"
75  " --syslog[=facility]- Log to syslog facility (default - neuromatrix)\n"
76  " --file=/tmp/log - Log to a file. "
77  " --nodaemon - Do not daemonize and log to stdout\n"
78  " --core=n - Log on core n. Can be specified multiple times.\n"
79  " --pidfile - Write a pid file\n"
80  " --log-interrupts - Log incoming interrupts\n"
81  "Debugging options: \n"
82  " --debug - Print lots of debugging info (nmctl)\n"
83  " --debug-lib - Print lots of debugging info (libeasynmc)\n"
84  , nm
85 );
86 }
87 
88 static struct option long_options[] =
89 {
90  /* Generic stuff. */
91  {"help", no_argument, 0, 'h' },
92 
93  /* Options */
94  {"prefix", required_argument, 0, 'P' },
95  {"core", required_argument, 0, 'c' },
96  {"syslog", optional_argument, &g_mode, 's' },
97  {"file", required_argument, 0, 'f' },
98  {"pid", required_argument, 0, 'p' },
99  {"nodaemon", no_argument, &g_nodaemon, 1 },
100 
101  /* Debugging hacks */
102  {"debug-lib", no_argument, &g_libeasynmc_debug, 1 },
103  {"debug", no_argument, &g_debug, 2 },
104  {"dump-ldr-regs", optional_argument, 0, 'D' },
105 
106  {0, 0, 0, 0}
107 };
108 
109 
110 
111 /*
112  openlog("slog", LOG_PID|LOG_CONS, LOG_USER);
113  syslog(LOG_INFO, "A different kind of Hello world ... ");
114  closelog();
115 
116  */
117 
118 
120  struct easynmc_handle *h;
121  FILE *rfd;
122  char *logprefix;
123 };
124 
125 
126 int add_core_to_logger(char* prefix, int numcore, int efd)
127 {
128  if (!prefix)
129  asprintf(&prefix, "core%d: ", numcore);
130  struct nmc_logger_core *c = malloc(sizeof(struct nmc_logger_core));
131  if (!c)
132  return -ENOMEM;
133  c->h = easynmc_open(numcore);
134  c->logprefix = prefix;
135  if (!c->h)
136  return -EIO;
137 
138  struct epoll_event evt;
139  evt.data.ptr = c;
140  evt.events = EPOLLIN | EPOLLHUP;
141  int ret = epoll_ctl(efd, EPOLL_CTL_ADD, c->h->iofd, &evt);
142  if (ret !=0)
143  return -EFAULT;
144  int flags = fcntl(c->h->iofd, F_GETFL, 0);
145  fcntl(c->h->iofd, F_SETFL, flags | O_NONBLOCK);
146  c->rfd = fdopen(c->h->iofd, "r");
147  setvbuf(c->rfd, NULL, _IOLBF, 2048);
148  return 0;
149 }
150 
151 void log_string_stdout(struct nmc_logger_core *core, char* str)
152 {
153  printf("'%s' %s", core->logprefix, str);
154 }
155 
156 void log_string_syslog(struct nmc_logger_core *core, char* str)
157 {
158 
159 }
160 
161 void log_string_file(struct nmc_logger_core *core, char* str)
162 {
163 
164 }
165 
166 int main(int argc, char* argv[])
167 {
168  if (argc < 2)
169  usage(argv[0]), exit(1);
170 
171  int numcore;
172  int curevt;
173  int fd;
174  int efd = epoll_create(argc);
175  char *prefix = NULL;
176  int numaddedcores = 0;
177  void (*do_log)(struct nmc_logger_core *core, char* str);
178  do_log = log_string_stdout;
179 
180  while (1)
181  {
182  int c;
183  int option_index = 0;
184  c = getopt_long (argc, argv, "P:c:s:f:p:Dh",
185  long_options, &option_index);
186 
187  /* Detect the end of the options. */
188  if (c == -1)
189  break;
190 
191  switch (c)
192  {
193  case 'c':
194  if (strcmp(optarg, "all") == 0)
195  numcore = -1;
196  else
197  numcore = atoi(optarg);
198 
199  int ret = add_core_to_logger(prefix, numcore, efd);
200  if (ret != 0) {
201  err("Failed to add core %d to logger\n", numcore);
202  exit(1);
203  }
204  numaddedcores++;
205  prefix = NULL;
206  break;
207  case 'h':
208  usage(argv[0]);
209  exit(1);
210  break;
211  case '?':
212  default:
213  break;
214  }
215  }
216  dbg("added %d core(s) to the logger\n", numaddedcores);
217 
218 #define BUFSIZE 2048
219 
220  while (1) {
221  char tmp[BUFSIZE];
222  char *ptr;
223  int num;
224  struct epoll_event evt;
225  num = epoll_wait(efd, &evt, 1, -1);
226  if (num == -1) {
227  perror("epoll_wait");
228  exit(1);
229  }
230 
231  struct nmc_logger_core *c = evt.data.ptr;
232 
233 
234  /* FixMe:
235  This is a simple hacky thing with known limitations:
236  Long lines that don't entirely fit in ring buffer will be split.
237  single characters sent with putc() from nmc will get a separate line
238  each.
239  The proper way would be
240  */
241  if (evt.events & EPOLLIN) {
242  int ret = fgets(c->rfd, tmp, BUFSIZE);
243  fprintf("gets %x %s\n",ret, tmp);
244  if (ret != NULL)
245  do_log(c, tmp);
246  }
247  if (evt.events & EPOLLHUP) {
248  do_log(c, "NOTICE: Application stopped!");
249  }
250 
251  }
252 
253  return 0;
254 }