1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 /*
7  * Copyright (C) 2018-2022 Intel Corporation.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <malloc.h>
27 #include "fsutils.h"
28 #include "startupreason.h"
29 #include "log_sys.h"
30 
31 #define CURRENT_KERNEL_CMDLINE "/proc/cmdline"
32 
get_cmdline_bootreason(char * bootreason,const size_t limit)33 static int get_cmdline_bootreason(char *bootreason, const size_t limit)
34 {
35 	int res;
36 	unsigned long size;
37 	char *start, *p1, *p2, *end;
38 	char *cmdline;
39 	const char *key = "ABL.reset=";
40 
41 	res = read_file(CURRENT_KERNEL_CMDLINE, &size, (void *)&cmdline);
42 	if (res < 0) {
43 		LOGE("failed to read file %s - %s\n",
44 		     CURRENT_KERNEL_CMDLINE, strerror(errno));
45 		return -1;
46 	}
47 	if (!size) {
48 		LOGW("empty file (%s)\n", CURRENT_KERNEL_CMDLINE);
49 		return 0;
50 	}
51 
52 	start = strstr(cmdline, key);
53 	if (!start) {
54 		LOGW("can't find reboot reason with key (%s) in cmdline\n",
55 		     key);
56 		free(cmdline);
57 		return 0;
58 	}
59 
60 	/* if the string contains ' ' or '\n', break it by '\0' */
61 	start += strlen(key);
62 	p1 = strchr(start, ' ');
63 	p2 = strchr(start, '\n');
64 	if (p2 && p1)
65 		end = MIN(p1, p2);
66 	else
67 		end = MAX(p1, p2);
68 
69 	if (!end)
70 		end = cmdline + size;
71 
72 	const size_t len = MIN((size_t)(end - start), (size_t)(limit - 1));
73 
74 	if (len > 0) {
75 		memcpy(bootreason, start, len);
76 		*(bootreason + len) = 0;
77 	}
78 
79 	free(cmdline);
80 	return len;
81 }
82 
get_default_bootreason(char * bootreason,const size_t limit)83 static int get_default_bootreason(char *bootreason, const size_t limit)
84 {
85 	int len;
86 	int i;
87 
88 	len = get_cmdline_bootreason(bootreason, limit);
89 	if (len <= 0)
90 		return len;
91 
92 	for (i = 0; i < len; i++)
93 		bootreason[i] = toupper(bootreason[i]);
94 
95 	return len;
96 
97 }
98 
read_startupreason(char * startupreason,const size_t limit)99 void read_startupreason(char *startupreason, const size_t limit)
100 {
101 	int res;
102 	static char reboot_reason_cache[REBOOT_REASON_SIZE];
103 
104 	if (!startupreason || !limit)
105 		return;
106 
107 	if (!reboot_reason_cache[0]) {
108 		/* fill cache */
109 		res = get_default_bootreason(reboot_reason_cache,
110 					     sizeof(reboot_reason_cache));
111 		if (res <= 0)
112 			strncpy(reboot_reason_cache, "UNKNOWN",
113 				sizeof(reboot_reason_cache));
114 	}
115 
116 	const size_t len = MIN(strnlen(reboot_reason_cache, REBOOT_REASON_SIZE),
117 			       limit - 1);
118 
119 	memcpy(startupreason, reboot_reason_cache, len);
120 	*(startupreason + len) = 0;
121 	return;
122 }
123