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