Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /*******************************************************************************
3 : : *
4 : : * Module Name: nsnames - Name manipulation and search
5 : : *
6 : : ******************************************************************************/
7 : :
8 : : #include <acpi/acpi.h>
9 : : #include "accommon.h"
10 : : #include "amlcode.h"
11 : : #include "acnamesp.h"
12 : :
13 : : #define _COMPONENT ACPI_NAMESPACE
14 : : ACPI_MODULE_NAME("nsnames")
15 : :
16 : : /* Local Prototypes */
17 : : static void acpi_ns_normalize_pathname(char *original_path);
18 : :
19 : : /*******************************************************************************
20 : : *
21 : : * FUNCTION: acpi_ns_get_external_pathname
22 : : *
23 : : * PARAMETERS: node - Namespace node whose pathname is needed
24 : : *
25 : : * RETURN: Pointer to storage containing the fully qualified name of
26 : : * the node, In external format (name segments separated by path
27 : : * separators.)
28 : : *
29 : : * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
30 : : * for error and debug statements.
31 : : *
32 : : ******************************************************************************/
33 : :
34 : 0 : char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
35 : : {
36 : 0 : char *name_buffer;
37 : :
38 : 0 : ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node);
39 : :
40 : 0 : name_buffer = acpi_ns_get_normalized_pathname(node, FALSE);
41 : 0 : return_PTR(name_buffer);
42 : : }
43 : :
44 : : /*******************************************************************************
45 : : *
46 : : * FUNCTION: acpi_ns_get_pathname_length
47 : : *
48 : : * PARAMETERS: node - Namespace node
49 : : *
50 : : * RETURN: Length of path, including prefix
51 : : *
52 : : * DESCRIPTION: Get the length of the pathname string for this node
53 : : *
54 : : ******************************************************************************/
55 : :
56 : 6912 : acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
57 : : {
58 : 6912 : acpi_size size;
59 : :
60 : : /* Validate the Node */
61 : :
62 [ - + ]: 6912 : if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
63 : 0 : ACPI_ERROR((AE_INFO,
64 : : "Invalid/cached reference target node: %p, descriptor type %d",
65 : : node, ACPI_GET_DESCRIPTOR_TYPE(node)));
66 : 0 : return (0);
67 : : }
68 : :
69 : 6912 : size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE);
70 : 6912 : return (size);
71 : : }
72 : :
73 : : /*******************************************************************************
74 : : *
75 : : * FUNCTION: acpi_ns_handle_to_name
76 : : *
77 : : * PARAMETERS: target_handle - Handle of named object whose name is
78 : : * to be found
79 : : * buffer - Where the name is returned
80 : : *
81 : : * RETURN: Status, Buffer is filled with name if status is AE_OK
82 : : *
83 : : * DESCRIPTION: Build and return a full namespace name
84 : : *
85 : : ******************************************************************************/
86 : :
87 : : acpi_status
88 : 1680 : acpi_ns_handle_to_name(acpi_handle target_handle, struct acpi_buffer *buffer)
89 : : {
90 : 1680 : acpi_status status;
91 : 1680 : struct acpi_namespace_node *node;
92 : 1680 : const char *node_name;
93 : :
94 : 1680 : ACPI_FUNCTION_TRACE_PTR(ns_handle_to_name, target_handle);
95 : :
96 : 1680 : node = acpi_ns_validate_handle(target_handle);
97 [ + - ]: 1680 : if (!node) {
98 : : return_ACPI_STATUS(AE_BAD_PARAMETER);
99 : : }
100 : :
101 : : /* Validate/Allocate/Clear caller buffer */
102 : :
103 : 1680 : status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH);
104 [ + - ]: 1680 : if (ACPI_FAILURE(status)) {
105 : : return_ACPI_STATUS(status);
106 : : }
107 : :
108 : : /* Just copy the ACPI name from the Node and zero terminate it */
109 : :
110 : 1680 : node_name = acpi_ut_get_node_name(node);
111 : 1680 : ACPI_COPY_NAMESEG(buffer->pointer, node_name);
112 : 1680 : ((char *)buffer->pointer)[ACPI_NAMESEG_SIZE] = 0;
113 : :
114 : 1680 : ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%4.4s\n", (char *)buffer->pointer));
115 : 1680 : return_ACPI_STATUS(AE_OK);
116 : : }
117 : :
118 : : /*******************************************************************************
119 : : *
120 : : * FUNCTION: acpi_ns_handle_to_pathname
121 : : *
122 : : * PARAMETERS: target_handle - Handle of named object whose name is
123 : : * to be found
124 : : * buffer - Where the pathname is returned
125 : : * no_trailing - Remove trailing '_' for each name
126 : : * segment
127 : : *
128 : : * RETURN: Status, Buffer is filled with pathname if status is AE_OK
129 : : *
130 : : * DESCRIPTION: Build and return a full namespace pathname
131 : : *
132 : : ******************************************************************************/
133 : :
134 : : acpi_status
135 : 8652 : acpi_ns_handle_to_pathname(acpi_handle target_handle,
136 : : struct acpi_buffer *buffer, u8 no_trailing)
137 : : {
138 : 8652 : acpi_status status;
139 : 8652 : struct acpi_namespace_node *node;
140 : 8652 : acpi_size required_size;
141 : :
142 : 8652 : ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle);
143 : :
144 : 8652 : node = acpi_ns_validate_handle(target_handle);
145 [ + - ]: 8652 : if (!node) {
146 : : return_ACPI_STATUS(AE_BAD_PARAMETER);
147 : : }
148 : :
149 : : /* Determine size required for the caller buffer */
150 : :
151 : 17304 : required_size =
152 : 8652 : acpi_ns_build_normalized_path(node, NULL, 0, no_trailing);
153 [ + - ]: 8652 : if (!required_size) {
154 : : return_ACPI_STATUS(AE_BAD_PARAMETER);
155 : : }
156 : :
157 : : /* Validate/Allocate/Clear caller buffer */
158 : :
159 : 8652 : status = acpi_ut_initialize_buffer(buffer, required_size);
160 [ + - ]: 8652 : if (ACPI_FAILURE(status)) {
161 : : return_ACPI_STATUS(status);
162 : : }
163 : :
164 : : /* Build the path in the caller buffer */
165 : :
166 : 8652 : (void)acpi_ns_build_normalized_path(node, buffer->pointer,
167 : : required_size, no_trailing);
168 : :
169 : : ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n",
170 : 8652 : (char *)buffer->pointer, (u32) required_size));
171 : 8652 : return_ACPI_STATUS(AE_OK);
172 : : }
173 : :
174 : : /*******************************************************************************
175 : : *
176 : : * FUNCTION: acpi_ns_build_normalized_path
177 : : *
178 : : * PARAMETERS: node - Namespace node
179 : : * full_path - Where the path name is returned
180 : : * path_size - Size of returned path name buffer
181 : : * no_trailing - Remove trailing '_' from each name segment
182 : : *
183 : : * RETURN: Return 1 if the AML path is empty, otherwise returning (length
184 : : * of pathname + 1) which means the 'FullPath' contains a trailing
185 : : * null.
186 : : *
187 : : * DESCRIPTION: Build and return a full namespace pathname.
188 : : * Note that if the size of 'FullPath' isn't large enough to
189 : : * contain the namespace node's path name, the actual required
190 : : * buffer length is returned, and it should be greater than
191 : : * 'PathSize'. So callers are able to check the returning value
192 : : * to determine the buffer size of 'FullPath'.
193 : : *
194 : : ******************************************************************************/
195 : :
196 : : u32
197 : 74880 : acpi_ns_build_normalized_path(struct acpi_namespace_node *node,
198 : : char *full_path, u32 path_size, u8 no_trailing)
199 : : {
200 : 74880 : u32 length = 0, i;
201 : 74880 : char name[ACPI_NAMESEG_SIZE];
202 : 74880 : u8 do_no_trailing;
203 : 74880 : char c, *left, *right;
204 : 74880 : struct acpi_namespace_node *next_node;
205 : :
206 : 74880 : ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node);
207 : :
208 : : #define ACPI_PATH_PUT8(path, size, byte, length) \
209 : : do { \
210 : : if ((length) < (size)) \
211 : : { \
212 : : (path)[(length)] = (byte); \
213 : : } \
214 : : (length)++; \
215 : : } while (0)
216 : :
217 : : /*
218 : : * Make sure the path_size is correct, so that we don't need to
219 : : * validate both full_path and path_size.
220 : : */
221 [ + + ]: 74880 : if (!full_path) {
222 : 40896 : path_size = 0;
223 : : }
224 : :
225 [ + - ]: 74880 : if (!node) {
226 : 0 : goto build_trailing_null;
227 : : }
228 : :
229 : : next_node = node;
230 [ + - + + ]: 312924 : while (next_node && next_node != acpi_gbl_root_node) {
231 [ + + ]: 238044 : if (next_node != node) {
232 [ + + ]: 163344 : ACPI_PATH_PUT8(full_path, path_size,
233 : : AML_DUAL_NAME_PREFIX, length);
234 : : }
235 : :
236 : 238044 : ACPI_MOVE_32_TO_32(name, &next_node->name);
237 : 238044 : do_no_trailing = no_trailing;
238 [ + + ]: 1190220 : for (i = 0; i < 4; i++) {
239 : 952176 : c = name[4 - i - 1];
240 [ + + ]: 952176 : if (do_no_trailing && c != '_') {
241 : : do_no_trailing = FALSE;
242 : : }
243 [ + + ]: 765504 : if (!do_no_trailing) {
244 [ + + ]: 952176 : ACPI_PATH_PUT8(full_path, path_size, c, length);
245 : : }
246 : : }
247 : :
248 : 238044 : next_node = next_node->parent;
249 : : }
250 : :
251 [ + + ]: 74880 : ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length);
252 : :
253 : : /* Reverse the path string */
254 : :
255 [ + + ]: 74880 : if (length <= path_size) {
256 : 33984 : left = full_path;
257 : 33984 : right = full_path + length - 1;
258 : :
259 [ + + ]: 289908 : while (left < right) {
260 : 255924 : c = *left;
261 : 255924 : *left++ = *right;
262 : 255924 : *right-- = c;
263 : : }
264 : : }
265 : :
266 : : /* Append the trailing null */
267 : :
268 : 74880 : build_trailing_null:
269 [ + + ]: 74880 : ACPI_PATH_PUT8(full_path, path_size, '\0', length);
270 : :
271 : : #undef ACPI_PATH_PUT8
272 : :
273 : 74880 : return_UINT32(length);
274 : : }
275 : :
276 : : /*******************************************************************************
277 : : *
278 : : * FUNCTION: acpi_ns_get_normalized_pathname
279 : : *
280 : : * PARAMETERS: node - Namespace node whose pathname is needed
281 : : * no_trailing - Remove trailing '_' from each name segment
282 : : *
283 : : * RETURN: Pointer to storage containing the fully qualified name of
284 : : * the node, In external format (name segments separated by path
285 : : * separators.)
286 : : *
287 : : * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
288 : : * for error and debug statements. All trailing '_' will be
289 : : * removed from the full pathname if 'NoTrailing' is specified..
290 : : *
291 : : ******************************************************************************/
292 : :
293 : 25332 : char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node,
294 : : u8 no_trailing)
295 : : {
296 : 25332 : char *name_buffer;
297 : 25332 : acpi_size size;
298 : :
299 : 25332 : ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node);
300 : :
301 : : /* Calculate required buffer size based on depth below root */
302 : :
303 : 25332 : size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing);
304 [ + - ]: 25332 : if (!size) {
305 : : return_PTR(NULL);
306 : : }
307 : :
308 : : /* Allocate a buffer to be returned to caller */
309 : :
310 : 25332 : name_buffer = ACPI_ALLOCATE_ZEROED(size);
311 [ - + ]: 25332 : if (!name_buffer) {
312 : 0 : ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size));
313 : 0 : return_PTR(NULL);
314 : : }
315 : :
316 : : /* Build the path in the allocated buffer */
317 : :
318 : 25332 : (void)acpi_ns_build_normalized_path(node, name_buffer, size,
319 : : no_trailing);
320 : :
321 : : ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, "%s: Path \"%s\"\n",
322 : 25332 : ACPI_GET_FUNCTION_NAME, name_buffer));
323 : :
324 : 25332 : return_PTR(name_buffer);
325 : : }
326 : :
327 : : /*******************************************************************************
328 : : *
329 : : * FUNCTION: acpi_ns_build_prefixed_pathname
330 : : *
331 : : * PARAMETERS: prefix_scope - Scope/Path that prefixes the internal path
332 : : * internal_path - Name or path of the namespace node
333 : : *
334 : : * RETURN: None
335 : : *
336 : : * DESCRIPTION: Construct a fully qualified pathname from a concatenation of:
337 : : * 1) Path associated with the prefix_scope namespace node
338 : : * 2) External path representation of the Internal path
339 : : *
340 : : ******************************************************************************/
341 : :
342 : 0 : char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope,
343 : : const char *internal_path)
344 : : {
345 : 0 : acpi_status status;
346 : 0 : char *full_path = NULL;
347 : 0 : char *external_path = NULL;
348 : 0 : char *prefix_path = NULL;
349 : 0 : u32 prefix_path_length = 0;
350 : :
351 : : /* If there is a prefix, get the pathname to it */
352 : :
353 [ # # # # ]: 0 : if (prefix_scope && prefix_scope->scope.node) {
354 : 0 : prefix_path =
355 : 0 : acpi_ns_get_normalized_pathname(prefix_scope->scope.node,
356 : : TRUE);
357 [ # # ]: 0 : if (prefix_path) {
358 : 0 : prefix_path_length = strlen(prefix_path);
359 : : }
360 : : }
361 : :
362 : 0 : status = acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_path,
363 : : NULL, &external_path);
364 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
365 : 0 : goto cleanup;
366 : : }
367 : :
368 : : /* Merge the prefix path and the path. 2 is for one dot and trailing null */
369 : :
370 : 0 : full_path =
371 : 0 : ACPI_ALLOCATE_ZEROED(prefix_path_length + strlen(external_path) +
372 : : 2);
373 [ # # ]: 0 : if (!full_path) {
374 : 0 : goto cleanup;
375 : : }
376 : :
377 : : /* Don't merge if the External path is already fully qualified */
378 : :
379 [ # # # # : 0 : if (prefix_path && (*external_path != '\\') && (*external_path != '^')) {
# # ]
380 : 0 : strcat(full_path, prefix_path);
381 [ # # ]: 0 : if (prefix_path[1]) {
382 : 0 : strcat(full_path, ".");
383 : : }
384 : : }
385 : :
386 : 0 : acpi_ns_normalize_pathname(external_path);
387 : 0 : strcat(full_path, external_path);
388 : :
389 : 0 : cleanup:
390 [ # # ]: 0 : if (prefix_path) {
391 : 0 : ACPI_FREE(prefix_path);
392 : : }
393 [ # # ]: 0 : if (external_path) {
394 : 0 : ACPI_FREE(external_path);
395 : : }
396 : :
397 : 0 : return (full_path);
398 : : }
399 : :
400 : : /*******************************************************************************
401 : : *
402 : : * FUNCTION: acpi_ns_normalize_pathname
403 : : *
404 : : * PARAMETERS: original_path - Path to be normalized, in External format
405 : : *
406 : : * RETURN: The original path is processed in-place
407 : : *
408 : : * DESCRIPTION: Remove trailing underscores from each element of a path.
409 : : *
410 : : * For example: \A___.B___.C___ becomes \A.B.C
411 : : *
412 : : ******************************************************************************/
413 : :
414 : 0 : static void acpi_ns_normalize_pathname(char *original_path)
415 : : {
416 : 0 : char *input_path = original_path;
417 : 0 : char *new_path_buffer;
418 : 0 : char *new_path;
419 : 0 : u32 i;
420 : :
421 : : /* Allocate a temp buffer in which to construct the new path */
422 : :
423 : 0 : new_path_buffer = ACPI_ALLOCATE_ZEROED(strlen(input_path) + 1);
424 : 0 : new_path = new_path_buffer;
425 [ # # ]: 0 : if (!new_path_buffer) {
426 : : return;
427 : : }
428 : :
429 : : /* Special characters may appear at the beginning of the path */
430 : :
431 [ # # ]: 0 : if (*input_path == '\\') {
432 : 0 : *new_path = *input_path;
433 : 0 : new_path++;
434 : 0 : input_path++;
435 : : }
436 : :
437 [ # # ]: 0 : while (*input_path == '^') {
438 : 0 : *new_path = *input_path;
439 : 0 : new_path++;
440 : 0 : input_path++;
441 : : }
442 : :
443 : : /* Remainder of the path */
444 : :
445 [ # # ]: 0 : while (*input_path) {
446 : :
447 : : /* Do one nameseg at a time */
448 : :
449 [ # # # # ]: 0 : for (i = 0; (i < ACPI_NAMESEG_SIZE) && *input_path; i++) {
450 [ # # # # ]: 0 : if ((i == 0) || (*input_path != '_')) { /* First char is allowed to be underscore */
451 : 0 : *new_path = *input_path;
452 : 0 : new_path++;
453 : : }
454 : :
455 : 0 : input_path++;
456 : : }
457 : :
458 : : /* Dot means that there are more namesegs to come */
459 : :
460 [ # # ]: 0 : if (*input_path == '.') {
461 : 0 : *new_path = *input_path;
462 : 0 : new_path++;
463 : 0 : input_path++;
464 : : }
465 : : }
466 : :
467 : 0 : *new_path = 0;
468 : 0 : strcpy(original_path, new_path_buffer);
469 : 0 : ACPI_FREE(new_path_buffer);
470 : : }
|