Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_pal_linux_implementation_internal.c Source File

arm_uc_pal_linux_implementation_internal.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "arm_uc_config.h"
00020 #if defined(ARM_UC_FEATURE_PAL_LINUX) && (ARM_UC_FEATURE_PAL_LINUX == 1)
00021 #if defined(TARGET_IS_PC_LINUX)
00022 #define _FILE_OFFSET_BITS  64
00023 
00024 #include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h"
00025 
00026 #include "update-client-metadata-header/arm_uc_metadata_header_v2.h"
00027 #include "update-client-common/arm_uc_scheduler.h"
00028 
00029 #define __STDC_FORMAT_MACROS
00030 #include <inttypes.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033 #include <pthread.h>
00034 #include <stdlib.h>
00035 #include <sys/stat.h>
00036 #include <sys/wait.h>
00037 
00038 /* pointer to external callback handler */
00039 static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL;
00040 
00041 linux_worker_thread_info_t linux_worker_thread = { .attr_initialized = 0, .mutex = PTHREAD_MUTEX_INITIALIZER };
00042 
00043 // storage set aside for adding event_cb to the event queue
00044 static arm_uc_callback_t event_cb_storage = { 0 };
00045 
00046 void arm_uc_pal_linux_signal_callback(uint32_t event, bool from_thread)
00047 {
00048     if (arm_uc_pal_external_callback) {
00049         if (from_thread) {
00050             /* Run given callback in the update client's thread */
00051             ARM_UC_PostCallback(&event_cb_storage, arm_uc_pal_external_callback, event);
00052         } else {
00053             arm_uc_pal_external_callback(event);
00054         }
00055     }
00056     if (from_thread) {
00057         /* The last thing that the thread does is call arm_uc_pal_linux_signal_callback(),
00058          * so unlock the thread mutex so that another thread can be created if needed */
00059         pthread_mutex_unlock(&linux_worker_thread.mutex);
00060     }
00061 }
00062 
00063 void arm_uc_pal_linux_internal_set_callback(ARM_UC_PAAL_UPDATE_SignalEvent_t callback)
00064 {
00065     arm_uc_pal_external_callback = callback;
00066 }
00067 
00068 static uint32_t arm_uc_offset = 0;
00069 static arm_uc_buffer_t *arm_uc_buffer = NULL;
00070 static arm_uc_firmware_details_t *arm_uc_details = NULL;
00071 static arm_uc_installer_details_t *arm_uc_installer = NULL;
00072 static uint32_t *arm_uc_location = NULL;
00073 static uint32_t arm_uc_location_buffer = 0;
00074 
00075 void arm_uc_pal_linux_internal_set_offset(uint32_t offset)
00076 {
00077     arm_uc_offset = offset;
00078 }
00079 
00080 void arm_uc_pal_linux_internal_set_buffer(arm_uc_buffer_t *buffer)
00081 {
00082     arm_uc_buffer = buffer;
00083 }
00084 
00085 void arm_uc_pal_linux_internal_set_details(arm_uc_firmware_details_t *details)
00086 {
00087     arm_uc_details = details;
00088 }
00089 
00090 void arm_uc_pal_linux_internal_set_installer(arm_uc_installer_details_t *details)
00091 {
00092     arm_uc_installer = details;
00093 }
00094 
00095 void arm_uc_pal_linux_internal_set_location(uint32_t *location)
00096 {
00097     if (location) {
00098         arm_uc_location_buffer = *location;
00099         arm_uc_location = &arm_uc_location_buffer;
00100     } else {
00101         arm_uc_location = NULL;
00102     }
00103 }
00104 
00105 arm_uc_error_t arm_uc_pal_linux_internal_file_path(char *buffer,
00106                                                    size_t buffer_length,
00107                                                    const char *folder,
00108                                                    const char *type,
00109                                                    uint32_t *location)
00110 {
00111     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00112 
00113     if (buffer && folder && type) {
00114         int actual_length = 0;
00115 
00116         if (location) {
00117             /* construct file path using location */
00118             actual_length = snprintf(buffer, buffer_length,
00119                                      "%s/%s_%" PRIu32 ".bin", folder, type, *location);
00120         } else {
00121             /* construct file path without location */
00122             actual_length = snprintf(buffer, buffer_length,
00123                                      "%s/%s.bin", folder, type);
00124         }
00125 
00126         /* check that the buffer is large enough */
00127         if (actual_length < buffer_length) {
00128             result.code = ERR_NONE;
00129         }
00130     }
00131 
00132     return result;
00133 }
00134 
00135 static bool arm_uc_pal_linux_internal_command(arm_ucp_worker_t *parameters,
00136                                               char *command,
00137                                               size_t command_length)
00138 {
00139     /* default to failed */
00140     bool valid = false;
00141 
00142     if (parameters && command) {
00143         /* invert status */
00144         valid = true;
00145 
00146         int length = snprintf(command,
00147                               command_length,
00148                               "%s ",
00149                               parameters->command);
00150 
00151         /* initialize remaining */
00152         int remaining = command_length - length;
00153 
00154         /* add header parameter if requested */
00155         if ((remaining > 0) && (parameters->header)) {
00156             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00157 
00158             /* construct header file path */
00159             arm_uc_error_t result =
00160                 arm_uc_pal_linux_internal_file_path(file_path,
00161                                                     sizeof(file_path),
00162                                                     ARM_UC_HEADER_FOLDER_PATH,
00163                                                     "header",
00164                                                     arm_uc_location);
00165 
00166             /* generated valid file path */
00167             if (result.error == ERR_NONE) {
00168                 /* add parameter to command line */
00169                 length += snprintf(&command[length],
00170                                    remaining,
00171                                    "-h %s ",
00172                                    file_path);
00173             }
00174 
00175             /* update remaining */
00176             remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length;
00177 
00178             /* check validity */
00179             valid = ((result.error == ERR_NONE) && (remaining > 0));
00180         }
00181 
00182         /* add firmware parameter if requested */
00183         if ((valid) && (parameters->firmware)) {
00184             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00185 
00186             /* construct firmware file path */
00187             arm_uc_error_t result =
00188                 arm_uc_pal_linux_internal_file_path(file_path,
00189                                                     sizeof(file_path),
00190                                                     ARM_UC_FIRMWARE_FOLDER_PATH,
00191                                                     "firmware",
00192                                                     arm_uc_location);
00193 
00194             /* generated valid file path */
00195             if (result.error == ERR_NONE) {
00196                 /* add parameter to command line */
00197                 length += snprintf(&command[length],
00198                                    remaining,
00199                                    "-f %s ",
00200                                    file_path);
00201             }
00202 
00203             /* update remaining */
00204             remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length;
00205 
00206             /* check validity */
00207             valid = ((result.error == ERR_NONE) && (remaining > 0));
00208         }
00209 
00210         /* add location parameter if requested */
00211         if ((valid) && (parameters->location)) {
00212             /* add parameter to command line */
00213             length += snprintf(&command[length],
00214                                remaining,
00215                                "-l %" PRIu32 " ",
00216                                *arm_uc_location);
00217 
00218             /* update remaining */
00219             remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length;
00220 
00221             /* check validity */
00222             valid = (remaining > 0);
00223         }
00224 
00225         /* add offset parameter if requested */
00226         if ((valid) && (parameters->offset)) {
00227             /* add parameter to command line */
00228             length += snprintf(&command[length],
00229                                remaining,
00230                                "-o %" PRIu32 " ",
00231                                arm_uc_offset);
00232 
00233             /* update remaining */
00234             remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length;
00235 
00236             /* check validity */
00237             valid = (remaining > 0);
00238         }
00239 
00240         /* add size parameter if requested */
00241         if ((valid) && (parameters->size)) {
00242             if (arm_uc_buffer) {
00243                 /* add parameter to command line */
00244                 length += snprintf(&command[length],
00245                                    remaining,
00246                                    "-s %" PRIu32 " ",
00247                                    arm_uc_buffer->size_max);
00248 
00249                 /* update remaining */
00250                 remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length;
00251 
00252                 /* check validity */
00253                 valid = (remaining > 0);
00254             } else {
00255                 valid = false;
00256             }
00257         }
00258     }
00259 
00260     return valid;
00261 }
00262 
00263 arm_uc_error_t arm_uc_pal_linux_internal_read(const char *file_path,
00264                                               uint32_t offset,
00265                                               arm_uc_buffer_t *buffer)
00266 {
00267     /* default to failure result */
00268     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00269 
00270     if (file_path && buffer) {
00271         /* open file */
00272         errno = 0;
00273         FILE *descriptor = fopen(file_path, "rb");
00274 
00275         /* continue if file is open */
00276         if (descriptor != NULL) {
00277             /* set read position */
00278             int status = fseeko(descriptor, offset, SEEK_SET);
00279 
00280             /* continue if position is set */
00281             if (status == 0) {
00282                 /* read buffer */
00283                 errno = 0;
00284                 size_t xfer_size = fread(buffer->ptr,
00285                                          sizeof(uint8_t),
00286                                          buffer->size,
00287                                          descriptor);
00288 
00289                 /* set buffer size if read succeeded */
00290                 status = ferror(descriptor);
00291 
00292                 if (status == 0) {
00293                     buffer->size = xfer_size;
00294 
00295                     /* set successful result */
00296                     result.code = ERR_NONE;
00297                 } else {
00298                     /* set error code if read failed */
00299                     UC_PAAL_ERR_MSG("failed to read %s: %s", file_path, strerror(errno));
00300                     buffer->size = 0;
00301                 }
00302 
00303                 /* close file after read */
00304                 fclose(descriptor);
00305             } else {
00306                 UC_PAAL_ERR_MSG("failed to seek in: %s", file_path);
00307             }
00308         } else {
00309             UC_PAAL_ERR_MSG("failed to open %s: %s", file_path, strerror(errno));
00310         }
00311     }
00312 
00313     return result;
00314 }
00315 
00316 arm_uc_error_t arm_uc_pal_linux_internal_read_header(uint32_t *location,
00317                                                      arm_uc_firmware_details_t *details)
00318 {
00319     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00320 
00321     if (details) {
00322         /* construct header file path */
00323         char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00324 
00325         result = arm_uc_pal_linux_internal_file_path(file_path,
00326                                                      ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00327                                                      ARM_UC_HEADER_FOLDER_PATH,
00328                                                      "header",
00329                                                      location);
00330 
00331         /* file path is valid */
00332         if (result.error == ERR_NONE) {
00333             /* allocate external header sized read buffer since it will be
00334                large enough to hold either an internal or external header.
00335              */
00336             uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 };
00337 
00338             arm_uc_buffer_t buffer = {
00339                 .size_max = sizeof(read_buffer),
00340                 .size     = sizeof(read_buffer),
00341                 .ptr      = read_buffer
00342             };
00343 
00344             /* read metadata header */
00345             result = arm_uc_pal_linux_internal_read(file_path, 0, &buffer);
00346 
00347             /* check return code */
00348             if (result.error == ERR_NONE) {
00349                 UC_PAAL_TRACE("header bytes: %u", buffer.size);
00350 
00351                 /* read out header magic */
00352                 uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]);
00353 
00354                 /* read out header magic */
00355                 uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]);
00356 
00357                 /* choose version to decode */
00358                 if ((headerMagic == ARM_UC_INTERNAL_HEADER_MAGIC_V2) &&
00359                         (headerVersion == ARM_UC_INTERNAL_HEADER_VERSION_V2) &&
00360                         (buffer.size == ARM_UC_INTERNAL_HEADER_SIZE_V2)) {
00361                     result = arm_uc_parse_internal_header_v2(read_buffer, details);
00362                 } else if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) &&
00363                            (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2) &&
00364                            (buffer.size == ARM_UC_EXTERNAL_HEADER_SIZE_V2)) {
00365                     result = arm_uc_parse_external_header_v2(read_buffer, details);
00366                 } else {
00367                     if (location) {
00368                         UC_PAAL_ERR_MSG("invalid header in slot %" PRIu32, *location);
00369                     } else {
00370                         UC_PAAL_ERR_MSG("invalid header location");
00371                     }
00372 
00373                     /* invalid header format */
00374                     result.code = ERR_INVALID_PARAMETER;
00375                 }
00376             } else {
00377                 /* unsuccessful read */
00378                 if (location) {
00379                     UC_PAAL_ERR_MSG("unable to read header in slot %" PRIX32, *location);
00380                 } else {
00381                     UC_PAAL_ERR_MSG("unable to read from unspecified header location");
00382                 }
00383             }
00384         } else {
00385             UC_PAAL_ERR_MSG("header file name and path too long");
00386         }
00387     }
00388 
00389     return result;
00390 }
00391 
00392 arm_uc_error_t arm_uc_pal_linux_internal_read_installer(arm_uc_installer_details_t *details)
00393 {
00394     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00395 
00396     if (details) {
00397         /* construct file path */
00398         char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00399 
00400         result = arm_uc_pal_linux_internal_file_path(file_path,
00401                                                      ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00402                                                      ARM_UC_INSTALLER_FOLDER_PATH,
00403                                                      "installer",
00404                                                      NULL);
00405 
00406         /* file path is valid */
00407         if (result.error == ERR_NONE) {
00408             uint8_t read_buffer[2 * sizeof(arm_uc_hash_t) + sizeof(uint32_t)] = { 0 };
00409 
00410             arm_uc_buffer_t buffer = {
00411                 .size_max = sizeof(read_buffer),
00412                 .size     = 0,
00413                 .ptr      = read_buffer
00414             };
00415 
00416             /* read installer details */
00417             result = arm_uc_pal_linux_internal_read(file_path, 0, &buffer);
00418 
00419             UC_PAAL_TRACE("installer bytes: %u", buffer.size);
00420 
00421             /* check return code */
00422             if ((result.error == ERR_NONE) &&
00423                     (buffer.size == sizeof(read_buffer))) {
00424                 memcpy(details->arm_hash,
00425                        buffer.ptr,
00426                        sizeof(arm_uc_hash_t));
00427 
00428                 memcpy(details->oem_hash,
00429                        &buffer.ptr[sizeof(arm_uc_hash_t)],
00430                        sizeof(arm_uc_hash_t));
00431 
00432                 details->layout = arm_uc_parse_uint32(&buffer.ptr[2 * sizeof(arm_uc_hash_t)]);
00433             } else {
00434                 /* unsuccessful read */
00435                 UC_PAAL_ERR_MSG("unable to read installer details");
00436             }
00437         } else {
00438             UC_PAAL_ERR_MSG("installer file name and path too long");
00439         }
00440     }
00441 
00442     return result;
00443 }
00444 
00445 arm_uc_error_t arm_uc_pal_linux_internal_write_header(uint32_t *location,
00446                                                       const arm_uc_firmware_details_t *details)
00447 {
00448     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00449 
00450     if (details) {
00451         /* allocate external header sized buffer since it will be
00452            large enough to hold either an internal or external header.
00453          */
00454         uint8_t temp_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 };
00455 
00456         arm_uc_buffer_t buffer = {
00457             .size_max = sizeof(temp_buffer),
00458             .size     = 0,
00459             .ptr      = temp_buffer
00460         };
00461 
00462         /* encode firmware details in buffer */
00463 #if ARM_UC_USE_EXTERNAL_HEADER
00464         result = arm_uc_create_external_header_v2(details, &buffer);
00465 #else
00466         result = arm_uc_create_internal_header_v2(details, &buffer);
00467 #endif
00468 
00469         /* write header file */
00470         if (result.error == ERR_NONE) {
00471             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00472 
00473             /* construct header file path */
00474             result = arm_uc_pal_linux_internal_file_path(file_path,
00475                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00476                                                          ARM_UC_HEADER_FOLDER_PATH,
00477                                                          "header",
00478                                                          location);
00479 
00480             if (result.error == ERR_NONE) {
00481                 /* inverse result */
00482                 result.code = ERR_INVALID_PARAMETER;
00483 
00484                 /* open file and get file handler */
00485                 errno = 0;
00486                 FILE *file = fopen(file_path, "wb");
00487 
00488                 if (file != NULL) {
00489                     /* write buffer to file */
00490                     size_t xfer_size = fwrite(buffer.ptr,
00491                                               sizeof(uint8_t),
00492                                               buffer.size,
00493                                               file);
00494 
00495                     UC_PAAL_TRACE("written: %" PRIu64, xfer_size);
00496 
00497                     /* close file after write */
00498                     int status = fclose(file);
00499 
00500                     if ((xfer_size == buffer.size) &&
00501                             (status != EOF)) {
00502                         /* set return code if write was successful */
00503                         result.code = ERR_NONE;
00504                     } else {
00505                         UC_PAAL_ERR_MSG("failed to write header");
00506                     }
00507                 } else {
00508                     UC_PAAL_ERR_MSG("file open failed: %s", strerror(errno));
00509                 }
00510             } else {
00511                 UC_PAAL_ERR_MSG("header file name and path too long");
00512             }
00513         } else {
00514             UC_PAAL_ERR_MSG("header too large for buffer");
00515         }
00516 
00517     }
00518 
00519     return result;
00520 }
00521 
00522 arm_uc_error_t arm_uc_pal_linux_internal_write_manifest(uint32_t *location,
00523                                                         const arm_uc_buffer_t *manifest)
00524 {
00525     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00526 
00527     if (manifest) {
00528         /* write header file */
00529         char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00530 
00531         /* construct header file path */
00532         result = arm_uc_pal_linux_internal_file_path(file_path,
00533                                                         ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00534                                                         ARM_UC_HEADER_FOLDER_PATH,
00535                                                         "manifest",
00536                                                         location);
00537 
00538         if (result.error == ERR_NONE) {
00539             /* inverse result */
00540             result.code = ERR_INVALID_PARAMETER;
00541 
00542             /* open file and get file handler */
00543             errno = 0;
00544             FILE *file = fopen(file_path, "wb");
00545 
00546             if (file != NULL) {
00547                 /* write manifest to file */
00548                 size_t xfer_size = fwrite(manifest->ptr,
00549                                           sizeof(uint8_t),
00550                                           manifest->size,
00551                                           file);
00552 
00553                 UC_PAAL_TRACE("written: %" PRIu64, xfer_size);
00554 
00555                 /* close file after write */
00556                 int status = fclose(file);
00557 
00558                 if ((xfer_size == manifest->size) && (status != EOF)) {
00559                     /* set return code if write was successful */
00560                     result.code = ERR_NONE;
00561                 } else {
00562                     UC_PAAL_ERR_MSG("failed to write manifest");
00563                 }
00564             } else {
00565                 UC_PAAL_ERR_MSG("file open failed: %s", strerror(errno));
00566             }
00567         } else {
00568             UC_PAAL_ERR_MSG("manifest file name and path too long");
00569         }
00570     }
00571 
00572     return result;
00573 }
00574 
00575 /**
00576  * @brief Function to run script in a worker thread before file operations.
00577  *
00578  * @param params Pointer to arm_ucp_worker_t struct.
00579  */
00580 void *arm_uc_pal_linux_extended_pre_worker(void *params)
00581 {
00582     /* default to failure */
00583     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00584 
00585     /* get parameters */
00586     arm_ucp_worker_t *parameters = (arm_ucp_worker_t *) params;
00587 
00588     /* file path to script result */
00589     char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00590 
00591     /* construct script command */
00592     char command[ARM_UC_MAXIMUM_COMMAND_LENGTH] = { 0 };
00593 
00594     int valid = arm_uc_pal_linux_internal_command(parameters,
00595                                                   command,
00596                                                   ARM_UC_MAXIMUM_COMMAND_LENGTH);
00597 
00598     /* command is valid */
00599     if (valid) {
00600         UC_PAAL_TRACE("Extended pre-script command: %s", command);
00601 
00602         /* execute script */
00603         errno = 0;
00604         FILE *pipe = popen(command, "r");
00605 
00606         if (pipe) {
00607             /* read pipe */
00608             size_t xfer_size = fread(file_path,
00609                                      sizeof(uint8_t),
00610                                      ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00611                                      pipe);
00612 
00613             /* trim non-printable characters */
00614             for (size_t index = 0; index < xfer_size; index++) {
00615                 /* space is the first printable character */
00616                 if (file_path[index] < ' ') {
00617                     /* truncate string */
00618                     file_path[index] = '\0';
00619                     break;
00620                 }
00621             }
00622 
00623             int status = 0;
00624 
00625             /* check fread error status */
00626             status = ferror(pipe);
00627             if (status == 0) {
00628                 /* Wait for child thread termination and check exit status */
00629                 status = pclose(pipe);
00630 
00631                 /* make sure child thread terminated correctly and scirpt exit status is 0 */
00632                 if (status != -1 && WIFEXITED(status)) {
00633                     if (WEXITSTATUS(status) == 0) {
00634                         /* switch from boolean result to arm_uc_error_t */
00635                         result.code = ERR_NONE;
00636                     } else {
00637                         UC_PAAL_ERR_MSG("Script exited with non-zero status %" PRId32, status);
00638                     }
00639                 } else {
00640                     UC_PAAL_ERR_MSG("pipe terminated incorrectly %" PRId32, status);
00641                 }
00642             } else {
00643                 UC_PAAL_ERR_MSG("failed to read pipe: %" PRId32, status);
00644             }
00645         } else {
00646             UC_PAAL_ERR_MSG("failed to execute script: %" PRId32, errno);
00647         }
00648     }
00649 
00650     /* file path is valid */
00651     if (result.error == ERR_NONE) {
00652         /* invert status */
00653         result.code = ERR_INVALID_PARAMETER;
00654 
00655         extern arm_ucp_worker_config_t arm_uc_worker_parameters;
00656 
00657         /* perform read operation */
00658         if ((parameters == arm_uc_worker_parameters.read) &&
00659                 (arm_uc_buffer != NULL)) {
00660             result = arm_uc_pal_linux_internal_read(file_path, 0, arm_uc_buffer);
00661 
00662             /* reset global buffer */
00663             arm_uc_buffer = NULL;
00664         }
00665 
00666         /* read details */
00667         if ((parameters == arm_uc_worker_parameters.details) &&
00668                 (arm_uc_details != NULL)) {
00669             result = arm_uc_pal_linux_internal_read_header(arm_uc_location,
00670                                                            arm_uc_details);
00671 
00672             /* reset global details pointer */
00673             arm_uc_details = NULL;
00674         }
00675 
00676         /* read active details */
00677         if ((parameters == arm_uc_worker_parameters.active_details) &&
00678                 (arm_uc_details != NULL)) {
00679             result = arm_uc_pal_linux_internal_read_header(NULL,
00680                                                            arm_uc_details);
00681 
00682             /* reset global details pointer */
00683             arm_uc_details = NULL;
00684         }
00685 
00686         /* read installer details */
00687         if ((parameters == arm_uc_worker_parameters.installer) &&
00688                 (arm_uc_installer != NULL)) {
00689             result = arm_uc_pal_linux_internal_read_installer(arm_uc_installer);
00690 
00691             /* reset global installer pointer */
00692             arm_uc_installer = NULL;
00693         }
00694     }
00695 
00696     if (result.error == ERR_NONE) {
00697         UC_PAAL_TRACE("pre-script complete");
00698 
00699         arm_uc_pal_linux_signal_callback(parameters->success_event, true);
00700     } else {
00701         UC_PAAL_ERR_MSG("pre-script failed");
00702 
00703         arm_uc_pal_linux_signal_callback(parameters->failure_event, true);
00704     }
00705     return NULL;
00706 }
00707 
00708 /**
00709  * @brief Function to run script in a worker thread before file operations.
00710  *
00711  * @param params Pointer to arm_ucp_worker_t struct.
00712  */
00713 void *arm_uc_pal_linux_extended_post_worker(void *params)
00714 {
00715     /* get parameters */
00716     arm_ucp_worker_t *parameters = (arm_ucp_worker_t *) params;
00717 
00718     /* construct script command */
00719     char command[ARM_UC_MAXIMUM_COMMAND_LENGTH] = { 0 };
00720 
00721     int error = 0;
00722     int32_t event = 0;
00723     int valid = arm_uc_pal_linux_internal_command(parameters,
00724                                                   command,
00725                                                   ARM_UC_MAXIMUM_COMMAND_LENGTH);
00726 
00727     if (valid) {
00728         UC_PAAL_TRACE("Extended post-script command: %s", command);
00729 
00730         /* execute script command */
00731         error = system(command);
00732         error = WEXITSTATUS(error);
00733 
00734         /* update valid flag */
00735         valid = (error == 0);
00736     }
00737 
00738     if (valid) {
00739         UC_PAAL_TRACE("post-script completed");
00740 
00741         event = parameters->success_event;
00742 
00743         /* execute the post runner if it exists and the script succeeded */
00744         if (parameters->post_runner) {
00745             event = parameters->post_runner();
00746             UC_PAAL_TRACE("post runner returned event %" PRId32, event);
00747         }
00748     } else {
00749         UC_PAAL_ERR_MSG("post-script failed: %" PRId32, error);
00750 
00751         event = parameters->failure_event;
00752     }
00753 
00754     arm_uc_pal_linux_signal_callback(event, true);
00755 
00756     return NULL;
00757 }
00758 
00759 #endif /* TARGET_IS_PC_LINUX */
00760 #endif /* ARM_UC_FEATURE_PAL_LINUX */