automotive-dlt
dlt_cdh.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include <fcntl.h>
34 #include <syslog.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <sys/stat.h>
40 #include <sys/statvfs.h>
41 #include "dlt_cdh.h"
42 #include <dirent.h>
43 
44 // Unusual characters in a windows filename are replaced
45 #define UNUSUAL_CHARS ":/\\!*"
46 #define REPLACEMENT_CHAR '_'
47 
48 #define COREDUMP_FILESYSTEM "/var"
49 #define COREDUMP_FILESYSTEM_MIN_SIZE_MB 40
50 #define COREDUMP_HANDLER_PRIORITY -19
51 
52 void core_locks(const proc_info_t* p_proc, int action);
53 
54 /* ===================================================================
55  ** Method : init_proc_info(...)
56  **
57  ** Description : initialises all members of process info structure to defined values
58  **
59  ** Parameters : INPUT p_proc
60  ** OUTPUT pointer to initialised crashed process info structure
61  **
62  ** Returns : nothing
63  ** ===================================================================*/
65 {
66  memset(p_proc->name, 0, sizeof(p_proc->name));
67  memset(p_proc->threadname, 0, sizeof(p_proc->threadname));
68 
69  p_proc->pid = 0;
70  p_proc->timestamp = 0;
71  p_proc->signal = 0;
72 
73  p_proc->can_create_coredump = 1;
74  memset(&p_proc->streamer, 0, sizeof(p_proc->streamer));
75 
76  memset(&p_proc->m_Ehdr, 0, sizeof(p_proc->m_Ehdr));
77  p_proc->m_pPhdr = NULL;
78  p_proc->m_Nhdr = NULL;
79 
80  p_proc->m_note_page_size = 0;
81 
82  memset(&p_proc->m_registers, 0, sizeof(p_proc->m_registers));
83 
84  p_proc->m_crashed_pid = 0;
85  p_proc->m_crashid_phase1 = 0;
86  memset(p_proc->m_crashid, 0, sizeof(p_proc->m_crashid));
87 }
88 
89 /* ===================================================================
90  ** Method : read_args(...)
91  **
92  ** Description : reads command line arguments
93  **
94  ** Parameters : INPUT argc
95  ** INPUT argv
96  ** OUTPUT pointer to crashed process info structure
97  **
98  ** Returns : 0 if success, else -1
99  ** ===================================================================*/
100 cdh_status_t read_args(int argc, char** argv, proc_info_t* proc)
101 {
102  if (argc < 5)
103  {
104  syslog(LOG_ERR, "Usage: cdh timestamp pid signal procname");
105  return CDH_NOK;
106  }
107 
108  init_proc_info(proc);
109 
110  if (sscanf(argv[1], "%u", &proc->timestamp) != 1)
111  {
112  syslog(LOG_ERR, "Unable to read timestamp argument <%s>. Closing", argv[1]);
113  return CDH_NOK;
114  }
115 
116  if (sscanf(argv[2], "%d", &proc->pid) != 1)
117  {
118  syslog(LOG_ERR, "Unable to read pid argument <%s>. Closing", argv[2]);
119  return CDH_NOK;
120  }
121 
122  if (sscanf(argv[3], "%d", &proc->signal) != 1)
123  {
124  syslog(LOG_ERR, "Unable to read signal argument <%s>. Closing", argv[3]);
125  return CDH_NOK;
126  }
127 
128  // save the thread name given by the kernel
129  strncpy(proc->threadname, argv[4], sizeof(proc->threadname) - 1);
130 
131  // initialize the binary name with threadname... in case we cannot read it from /proc
132  strncpy(proc->name, argv[4], sizeof(proc->name) - 1);
133 
134  return CDH_OK;
135 }
136 
137 /* ===================================================================
138  ** Method : remove_unusual_chars(...)
139  **
140  ** Description : modify the input string to change UNUSUALS_CHARS to
141  ** REPLACEMENT_CHAR
142  ** Parameters : INPUT/OUTPUT string to be modified
143  **
144  ** Returns : nothing
145  ** ===================================================================*/
146 void remove_unusual_chars(char* p_string)
147 {
148  unsigned int l_char_index = 0;
149 
150  for (l_char_index = 0; l_char_index < sizeof(UNUSUAL_CHARS) - 1; l_char_index++)
151  {
152  char* l_str_pointer = p_string;
153 
154  do
155  {
156  l_str_pointer = strchr(l_str_pointer, UNUSUAL_CHARS[l_char_index]);
157 
158  if (l_str_pointer != NULL)
159  {
160  *l_str_pointer = REPLACEMENT_CHAR;
161  l_str_pointer++;
162  }
163  }
164  while (l_str_pointer != NULL);
165  }
166 }
167 
168 /* ===================================================================
169  ** Method : check_disk_space(...)
170  **
171  ** Description : check if there is sufficient disk space to write a coredump
172  ** Parameters : INPUT/OUTPUT string to be modified
173  **
174  ** Returns : 0 if success, else -1
175  ** ===================================================================*/
177 {
178  struct statvfs stat;
179  unsigned long free_size = 0;
180 
181  if (statvfs(COREDUMP_FILESYSTEM, &stat) < 0)
182  {
183  syslog(LOG_ERR, "ERR cannot stat disk space on %s: %s", COREDUMP_FILESYSTEM, strerror(errno));
184  return CDH_NOK;
185  }
186 
187  // free space: size of block * number of free blocks (>>20 => MB)
188  free_size = (stat.f_bsize * stat.f_bavail) >> 20;
189  if (free_size < COREDUMP_FILESYSTEM_MIN_SIZE_MB)
190  {
191  syslog(LOG_WARNING, "ERR insufficient disk space for coredump: %ld MB.", free_size);
192  return CDH_NOK;
193  }
194 
195  syslog(LOG_INFO, "INFO disk space for coredump: %ld MB.", free_size);
196  return CDH_OK;
197 }
198 
200 {
201  DIR *d = NULL;
202  struct dirent *dir = NULL;
203 
204  if ((d = opendir(CORE_TMP_DIRECTORY)) != NULL)
205  {
206  char lockfilepath[CORE_MAX_FILENAME_LENGTH];
207 
208  while ((dir = readdir(d)) != NULL)
209  {
210  struct stat unused_stat;
211 
212  // check if lock file exists
213  snprintf(lockfilepath, sizeof(lockfilepath), "%s/%s", CORE_LOCK_DIRECTORY, dir->d_name);
214 
215  if (stat(lockfilepath, &unused_stat) != 0)
216  {
217  // No lock file found for this coredump => from previous LC => delete
218  char filepath[CORE_MAX_FILENAME_LENGTH] = { 0 };
219 
220  snprintf(filepath, sizeof(filepath), "%s/%s", CORE_TMP_DIRECTORY, dir->d_name);
221 
222  syslog(LOG_INFO, "Cleaning %s: delete file %s", CORE_TMP_DIRECTORY, filepath);
223 
224  unlink(filepath);
225  }
226  }
227 
228  closedir(d);
229  }
230 }
231 
232 /* ===================================================================
233  ** Method : check_core_directory(...)
234  **
235  ** Description : checks the availability of core dumps directory.
236  ** if not available, there is an installation issue.
237  **
238  ** Parameters :
239  **
240  ** Returns : 0 if success, else -1
241  ** ===================================================================*/
242 cdh_status_t check_and_create_directory(const char* p_dirname, int create_silently)
243 {
244  int l_need_create = 0;
245  int l_need_delete = 0;
246 
247  struct stat l_stat;
248 
249  if (lstat(p_dirname, &l_stat) < 0)
250  {
251  l_need_create = 1;
252  }
253  else if (!S_ISDIR(l_stat.st_mode))
254  {
255  l_need_delete = 1;
256  l_need_create = 1;
257  }
258 
259  if (l_need_delete > 0)
260  {
261  syslog(LOG_WARNING, "WARN core directory '%s' is not a directory => removing it", p_dirname);
262 
263  if (unlink(p_dirname) == -1)
264  {
265  syslog(LOG_ERR, "ERR core directory '%s' cannot be unlinked: %s", p_dirname, strerror(errno));
266  return CDH_NOK;
267  }
268  }
269  if (l_need_create > 0)
270  {
271  if (create_silently == 0)
272  syslog(LOG_WARNING, "WARN core directory '%s' does not exist => creation", p_dirname);
273 
274  if (mkdir(p_dirname, 0666) == -1)
275  {
276  syslog(LOG_ERR, "ERR core directory '%s' cannot be created: %s", p_dirname, strerror(errno));
277  return CDH_NOK;
278  }
279  }
280 
281  return CDH_OK;
282 }
283 
284 /* ===================================================================
285  ** Method : check_core_directory(...)
286  **
287  ** Description : checks the availability of core dumps directory.
288  ** if not available, there is an installation issue.
289  **
290  ** Parameters :
291  **
292  ** Returns : 0 if success, else -1
293  ** ===================================================================*/
295 {
297  return CDH_NOK;
298 
300  return CDH_NOK;
301 
303  return CDH_NOK;
304 
306 
307  return CDH_OK;
308 }
309 
310 /* ===================================================================
311  ** Method : move_to_core_directory(...)
312  **
313  ** Description : move the coredump and context files
314  ** from temporary dir to final core directory
315  **
316  ** Parameters :
317  **
318  ** Returns : 0 if success, else -1
319  ** ===================================================================*/
321 {
322  char l_src_filename[CORE_MAX_FILENAME_LENGTH] = { 0 };
323  char l_dst_filename[CORE_MAX_FILENAME_LENGTH] = { 0 };
324  char* patterns[] = { CORE_FILE_PATTERN, CONTEXT_FILE_PATTERN };
325  unsigned int pattern_num = 0;
326 
327  if (p_proc == NULL)
328  return CDH_NOK;
329 
330  for (pattern_num = 0; pattern_num < sizeof(patterns) / sizeof(char*); pattern_num++)
331  {
332  // Don't move coredump if it cannot be created
333  if (p_proc->can_create_coredump == 0 && pattern_num == 0)
334  continue;
335 
336  snprintf(l_src_filename, sizeof(l_src_filename), patterns[pattern_num],
337  CORE_TMP_DIRECTORY, p_proc->timestamp, p_proc->name, p_proc->pid);
338 
339  snprintf(l_dst_filename, sizeof(l_dst_filename), patterns[pattern_num],
340  CORE_DIRECTORY, p_proc->timestamp, p_proc->name, p_proc->pid);
341 
342  syslog(LOG_INFO, "Moving coredump from %s to %s", l_src_filename, l_dst_filename);
343 
344  if (rename(l_src_filename, l_dst_filename) < 0)
345  syslog(LOG_ERR, "Moving failed: %s", strerror(errno));
346  }
347 
348  return CDH_OK;
349 }
350 
351 /* ===================================================================
352  ** Method : main(...)
353  **
354  ** Description :
355  **
356  ** Parameters : argc, argv
357  **
358  ** Returns :
359  ** ===================================================================*/
360 int main(int argc, char* argv[])
361 {
362  proc_info_t l_proc_info;
363 // char l_exec_name[CORE_MAX_FILENAME_LENGTH] = {0};
364 
365  openlog("CoredumpHandler", 0, LOG_DAEMON);
366 
367  if (read_args(argc, argv, &l_proc_info) < 0)
368  exit(-1);
369 
370  if (get_exec_name(l_proc_info.pid, l_proc_info.name, sizeof(l_proc_info.name)) != 0)
371  syslog(LOG_ERR, "Failed to get executable name");
372 
373  syslog(LOG_NOTICE, "Handling coredump procname:%s pid:%d timest:%d signal:%d",
374  l_proc_info.name,
375  l_proc_info.pid,
376  l_proc_info.timestamp,
377  l_proc_info.signal);
378 
379  // Increase priority of the coredump handler
381  syslog(LOG_WARNING, "Failed to change CDH priority");
382 
383  if (check_disk_space() < 0)
384  {
385  //return CDH_NOK;
386  l_proc_info.can_create_coredump = 0;
387  }
388 
389  if (check_core_directory() < 0)
390  {
391  //return CDH_NOK;
392  l_proc_info.can_create_coredump = 0;
393  }
394 
395  remove_unusual_chars(l_proc_info.name);
396 
397  core_locks(&l_proc_info, 1);
398 
399  write_proc_context(&l_proc_info);
400 
401  treat_coredump(&l_proc_info);
402 
403  move_to_core_directory(&l_proc_info);
404 
405  core_locks(&l_proc_info, 0);
406 
407  treat_crash_data(&l_proc_info);
408 
409  closelog();
410 
411  return CDH_OK;
412 }
413 
414 void core_locks(const proc_info_t* p_proc, int action)
415 {
416  char l_lockfilepath[CORE_MAX_FILENAME_LENGTH] = { 0 };
417  char* patterns[] = { CORE_FILE_PATTERN, CONTEXT_FILE_PATTERN };
418  unsigned int pattern_num = 0;
419  int fd_lockfile = -1;
420 
421  if (p_proc == NULL)
422  return;
423 
424  for (pattern_num = 0; pattern_num < sizeof(patterns) / sizeof(char*); pattern_num++)
425  {
426  snprintf(l_lockfilepath, sizeof(l_lockfilepath), patterns[pattern_num],
427  CORE_LOCK_DIRECTORY, p_proc->timestamp, p_proc->name, p_proc->pid);
428 
429  switch (action)
430  {
431  case 0:
432  {
433  unlink(l_lockfilepath);
434  break;
435  }
436 
437  case 1:
438  {
439  if ((fd_lockfile = open(l_lockfilepath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) >= 0)
440  {
441  if (write(fd_lockfile, "1", 1) < 0)
442  syslog(LOG_WARNING, "Failed to write lockfile %d: %s", fd_lockfile, strerror(errno));
443 
444  close(fd_lockfile);
445  }
446  else
447  {
448  syslog(LOG_WARNING, "Failed to open lockfile %s: %s", l_lockfilepath, strerror(errno));
449  }
450 
451  break;
452  }
453 
454  default:
455  break;
456  }
457  }
458 }
unsigned int m_note_page_size
Definition: dlt_cdh.h:79
ELF_Ehdr m_Ehdr
Definition: dlt_cdh.h:75
pid_t m_crashed_pid
Definition: dlt_cdh.h:83
cdh_status_t get_exec_name(unsigned int p_pid_str, char *p_exec_name, int p_exec_name_maxsize)
#define CORE_DIRECTORY
Definition: dlt_cdh.h:39
#define REPLACEMENT_CHAR
Definition: dlt_cdh.c:46
cdh_status_t check_disk_space()
Definition: dlt_cdh.c:176
#define CORE_LOCK_DIRECTORY
Definition: dlt_cdh.h:41
cdh_status_t treat_coredump(proc_info_t *p_proc)
char name[MAX_PROC_NAME_LENGTH]
Definition: dlt_cdh.h:65
void remove_unusual_chars(char *p_string)
Definition: dlt_cdh.c:146
unsigned char m_crashid[CRASH_ID_LEN]
Definition: dlt_cdh.h:85
int signal
Definition: dlt_cdh.h:69
#define COREDUMP_FILESYSTEM_MIN_SIZE_MB
Definition: dlt_cdh.c:49
int main(int argc, char *argv[])
Definition: dlt_cdh.c:360
uint64_t m_crashid_phase1
Definition: dlt_cdh.h:84
cdh_status_t read_args(int argc, char **argv, proc_info_t *proc)
Definition: dlt_cdh.c:100
#define CONTEXT_FILE_PATTERN
Definition: dlt_cdh.h:48
#define COREDUMP_HANDLER_PRIORITY
Definition: dlt_cdh.c:50
cdh_status_t
#define COREDUMP_FILESYSTEM
Definition: dlt_cdh.c:48
#define CORE_TMP_DIRECTORY
Definition: dlt_cdh.h:40
void init_proc_info(proc_info_t *p_proc)
Definition: dlt_cdh.c:64
int can_create_coredump
Definition: dlt_cdh.h:71
file_streamer_t streamer
Definition: dlt_cdh.h:72
pid_t pid
Definition: dlt_cdh.h:67
cdh_status_t check_core_directory()
Definition: dlt_cdh.c:294
cdh_status_t move_to_core_directory(proc_info_t *p_proc)
Definition: dlt_cdh.c:320
cdh_status_t treat_crash_data(proc_info_t *p_proc)
cdh_registers_t m_registers
Definition: dlt_cdh.h:81
cdh_status_t write_proc_context(const proc_info_t *)
cdh_status_t check_and_create_directory(const char *p_dirname, int create_silently)
Definition: dlt_cdh.c:242
#define UNUSUAL_CHARS
Definition: dlt_cdh.c:45
#define CORE_FILE_PATTERN
Definition: dlt_cdh.h:47
void clean_core_tmp_dir()
Definition: dlt_cdh.c:199
char threadname[MAX_PROC_NAME_LENGTH]
Definition: dlt_cdh.h:66
void core_locks(const proc_info_t *p_proc, int action)
Definition: dlt_cdh.c:414
uint32_t timestamp
Definition: dlt_cdh.h:68
char * m_Nhdr
Definition: dlt_cdh.h:77
#define CORE_MAX_FILENAME_LENGTH
Definition: dlt_cdh.h:42
#define NULL
Definition: dlt_common.h:232
ELF_Phdr * m_pPhdr
Definition: dlt_cdh.h:76