Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_pal_linux_implementation.c Source File

arm_uc_pal_linux_implementation.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 #if defined(TARGET_IS_PC_LINUX)
00020 
00021 #include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h"
00022 #include "update-client-pal-linux/arm_uc_pal_linux_implementation.h"
00023 #include "update-client-paal/arm_uc_paal_update_api.h"
00024 
00025 #include "update-client-common/arm_uc_trace.h"
00026 #include "update-client-common/arm_uc_utilities.h"
00027 #include "update-client-common/arm_uc_metadata_header_v2.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 /* worker struct, must be accessible externally */
00039 arm_ucp_worker_config_t arm_uc_worker_parameters = { 0 };
00040 
00041 static FILE* arm_uc_firmware_descriptor = NULL;
00042 
00043 /**
00044  * @brief Initialize the underlying storage and set the callback handler.
00045  *
00046  * @param callback Function pointer to event handler.
00047  * @return Returns ERR_NONE on accept, and signals the event handler with
00048  *         either DONE or ERROR when complete.
00049  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00050  */
00051 arm_uc_error_t ARM_UC_PAL_Linux_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback)
00052 {
00053     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00054 
00055     if (callback)
00056     {
00057         arm_uc_pal_linux_internal_set_callback(callback);
00058 
00059         /* create folder for headers if it does not already exist */
00060         errno = 0;
00061         int status = mkdir(ARM_UC_HEADER_FOLDER_PATH, 0700);
00062 
00063         if ((status == 0) || (errno == EEXIST))
00064         {
00065             /* create folder for firmwares if it does not already exist */
00066             errno = 0;
00067             status = mkdir(ARM_UC_FIRMWARE_FOLDER_PATH, 0700);
00068 
00069             if ((status == 0) || (errno == EEXIST))
00070             {
00071                 /* set return code on success */
00072                 result.code = ERR_NONE;
00073             }
00074         }
00075 
00076         /* signal completion or perform extended preparation */
00077         if (result.error == ERR_NONE)
00078         {
00079             /* set explicit ERR_NONE upon success */
00080             result.code = ERR_NONE;
00081 
00082             if (arm_uc_worker_parameters.initialize)
00083             {
00084                 /* use extended prepare, invoke script from worker thread */
00085                 pthread_t thread;
00086 
00087                 /* create a second thread which executes worker_parameters_prepare */
00088                 int status = pthread_create(&thread,
00089                                             NULL,
00090                                             arm_uc_pal_linux_extended_post_worker,
00091                                             arm_uc_worker_parameters.initialize);
00092 
00093                 /* check if thread was created successfully */
00094                 if (status != 0)
00095                 {
00096                     result.code = ERR_INVALID_PARAMETER;
00097                 }
00098             }
00099             else
00100             {
00101                 /* call event handler */
00102                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00103             }
00104         }
00105 
00106     }
00107 
00108     return result;
00109 }
00110 
00111 /**
00112  * @brief Get maximum number of supported storage locations.
00113  *
00114  * @return Number of storage locations.
00115  */
00116 uint32_t ARM_UC_PAL_Linux_GetMaxID(void)
00117 {
00118     return 1;
00119 }
00120 
00121 /**
00122  * @brief Prepare the storage layer for a new firmware image.
00123  * @details The storage location is set up to receive an image with
00124  *          the details passed in the details struct.
00125  *
00126  * @param location Storage location ID.
00127  * @param details Pointer to a struct with firmware details.
00128  * @param buffer Temporary buffer for formatting and storing metadata.
00129  * @return Returns ERR_NONE on accept, and signals the event handler with
00130  *         either DONE or ERROR when complete.
00131  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00132  */
00133 arm_uc_error_t ARM_UC_PAL_Linux_Prepare(uint32_t location,
00134                                         const arm_uc_firmware_details_t* details,
00135                                         arm_uc_buffer_t* buffer)
00136 {
00137     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00138 
00139     if (details && buffer)
00140     {
00141         UC_PAAL_TRACE("details size: %" PRIu64, details->size);
00142 
00143         /* write header */
00144         result = arm_uc_pal_linux_internal_write_header(&location, details);
00145 
00146         /* allocate space for firmware */
00147         if (result.error == ERR_NONE)
00148         {
00149             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00150 
00151             /* construct header file path */
00152             result = arm_uc_pal_linux_internal_file_path(file_path,
00153                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00154                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00155                                                          "firmware",
00156                                                          &location);
00157 
00158             UC_PAAL_TRACE("file path: %s", file_path);
00159 
00160             if (result.error == ERR_NONE)
00161             {
00162                 /* open file */
00163                 errno = 0;
00164                 FILE* descriptor = fopen(file_path, "wb");
00165 
00166                 if (descriptor != NULL)
00167                 {
00168                     /* allocate space by writing empty file */
00169                     memset(buffer->ptr, 0, buffer->size_max);
00170                     buffer->size = buffer->size_max;
00171 
00172                     uint64_t index = 0;
00173                     while (index < details->size)
00174                     {
00175                         /* calculate write size to handle overspill */
00176                         size_t actual_size = details->size - index;
00177 
00178                         if (actual_size > buffer->size)
00179                         {
00180                             actual_size = buffer->size;
00181                         }
00182 
00183                         /* write buffer */
00184                         size_t xfer_size = fwrite(buffer->ptr,
00185                                                   sizeof(uint8_t),
00186                                                   actual_size,
00187                                                   descriptor);
00188 
00189                         /* break out if write failed */
00190                         if (xfer_size == actual_size)
00191                         {
00192                             index += actual_size;
00193                         }
00194                         else
00195                         {
00196                             result.code = ERR_INVALID_PARAMETER;
00197                             break;
00198                         }
00199                     }
00200 
00201                     /* close file after write */
00202                     int status = fclose(descriptor);
00203 
00204                     if (status == EOF)
00205                     {
00206                         UC_PAAL_ERR_MSG("failed to allocate space for firmware");
00207                         result.code = ERR_INVALID_PARAMETER;
00208                     }
00209                 }
00210                 else
00211                 {
00212                     UC_PAAL_ERR_MSG("failed to open file: %s", strerror(errno));
00213                 }
00214             }
00215             else
00216             {
00217                 UC_PAAL_ERR_MSG("file name and path too long");
00218             }
00219         }
00220         else
00221         {
00222             UC_PAAL_ERR_MSG("could not write header");
00223         }
00224 
00225         /* signal completion or perform extended preparation */
00226         if (result.error == ERR_NONE)
00227         {
00228             /* set explicit ERR_NONE upon success */
00229             result.code = ERR_NONE;
00230 
00231             if (arm_uc_worker_parameters.prepare)
00232             {
00233                 /* use extended prepare, invoke script from worker thread */
00234                 pthread_t thread;
00235 
00236                 /* export location */
00237                 arm_uc_pal_linux_internal_set_location(&location);
00238 
00239                 /* create a second thread which executes worker_parameters_prepare */
00240                 int status = pthread_create(&thread,
00241                                             NULL,
00242                                             arm_uc_pal_linux_extended_post_worker,
00243                                             arm_uc_worker_parameters.prepare);
00244 
00245                 /* check if thread was created successfully */
00246                 if (status != 0)
00247                 {
00248                     result.code = ERR_INVALID_PARAMETER;
00249                 }
00250             }
00251             else
00252             {
00253                 /* call event handler */
00254                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00255             }
00256         }
00257     }
00258 
00259     return result;
00260 }
00261 
00262 /**
00263  * @brief Write a fragment to the indicated storage location.
00264  * @details The storage location must have been allocated using the Prepare
00265  *          call. The call is expected to write the entire fragment before
00266  *          signaling completion.
00267  *
00268  * @param location Storage location ID.
00269  * @param offset Offset in bytes to where the fragment should be written.
00270  * @param buffer Pointer to buffer struct with fragment.
00271  * @return Returns ERR_NONE on accept, and signals the event handler with
00272  *         either DONE or ERROR when complete.
00273  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00274  */
00275 arm_uc_error_t ARM_UC_PAL_Linux_Write(uint32_t location,
00276                                       uint32_t offset,
00277                                       const arm_uc_buffer_t* buffer)
00278 {
00279     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00280 
00281     if (buffer)
00282     {
00283         /* reverse default error code */
00284         result.code = ERR_NONE;
00285 
00286         /* open file if descriptor is not set */
00287         if (arm_uc_firmware_descriptor == NULL)
00288         {
00289             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00290 
00291             /* construct firmware file path */
00292             result = arm_uc_pal_linux_internal_file_path(file_path,
00293                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00294                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00295                                                          "firmware",
00296                                                          &location);
00297 
00298             if (result.error == ERR_NONE)
00299             {
00300                 /* open file */
00301                 if (arm_uc_worker_parameters.write)
00302                 {
00303                     /* in extended write, each fragment is stored in its own file */
00304                     arm_uc_firmware_descriptor = fopen(file_path, "w+b");
00305 
00306                     /* export offset before resetting it */
00307                     arm_uc_pal_linux_internal_set_offset(offset);
00308                     offset = 0;
00309                 }
00310                 else
00311                 {
00312                     /* in normal write, each fragment is added to an existing file */
00313                     arm_uc_firmware_descriptor = fopen(file_path, "r+b");
00314                 }
00315             }
00316             else
00317             {
00318                 UC_PAAL_ERR_MSG("firmware file name and path too long");
00319             }
00320         }
00321 
00322         /* continue if file is open */
00323         if (arm_uc_firmware_descriptor != NULL)
00324         {
00325             /* set write position */
00326             int status = fseek(arm_uc_firmware_descriptor,
00327                                offset,
00328                                SEEK_SET);
00329 
00330             /* continue if position is set */
00331             if (status == 0)
00332             {
00333                 /* write buffer */
00334                 size_t xfer_size = fwrite(buffer->ptr,
00335                                           sizeof(uint8_t),
00336                                           buffer->size,
00337                                           arm_uc_firmware_descriptor);
00338 
00339                 /* set error code if write failed */
00340                 if (xfer_size != buffer->size)
00341                 {
00342                     UC_PAAL_ERR_MSG("failed to write firmware");
00343                     result.code = ERR_INVALID_PARAMETER;
00344                 }
00345 
00346                 /* if using extended write */
00347                 if (arm_uc_worker_parameters.write)
00348                 {
00349                     /* close file after write */
00350                     int status = fclose(arm_uc_firmware_descriptor);
00351                     arm_uc_firmware_descriptor = NULL;
00352 
00353                     if (status == EOF)
00354                     {
00355                         UC_PAAL_ERR_MSG("failed to close firmware file");
00356                         result.code = ERR_INVALID_PARAMETER;
00357                     }
00358                 }
00359             }
00360             else
00361             {
00362                 UC_PAAL_ERR_MSG("failed to seek in firmware");
00363                 result.code = ERR_INVALID_PARAMETER;
00364             }
00365         }
00366 
00367         /* signal completion or perform extended write */
00368         if (result.error == ERR_NONE)
00369         {
00370             /* set explicit ERR_NONE */
00371             result.code = ERR_NONE;
00372 
00373             if (arm_uc_worker_parameters.write)
00374             {
00375                 /* use extended write, invoke script from worker thread */
00376                 pthread_t thread;
00377 
00378                 /* export location */
00379                 arm_uc_pal_linux_internal_set_location(&location);
00380 
00381                 /* create a second thread which executes worker_parameters_write */
00382                 int status = pthread_create(&thread,
00383                                             NULL,
00384                                             arm_uc_pal_linux_extended_post_worker,
00385                                             arm_uc_worker_parameters.write);
00386 
00387                 /* check if thread was successfully created */
00388                 if (status != 0)
00389                 {
00390                     result.code = ERR_INVALID_PARAMETER;
00391                 }
00392             }
00393             else
00394             {
00395                 /* call event handler */
00396                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE);
00397             }
00398         }
00399     }
00400 
00401     return result;
00402 }
00403 
00404 /**
00405  * @brief Close storage location for writing and flush pending data.
00406  *
00407  * @param location Storage location ID.
00408  * @return Returns ERR_NONE on accept, and signals the event handler with
00409  *         either DONE or ERROR when complete.
00410  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00411  */
00412 arm_uc_error_t ARM_UC_PAL_Linux_Finalize(uint32_t location)
00413 {
00414     arm_uc_error_t result = { .code = ERR_NONE };
00415 
00416     /* only close firmware file if descriptor is not NULL */
00417     if (arm_uc_firmware_descriptor != NULL)
00418     {
00419         /* close file */
00420         int status = fclose(arm_uc_firmware_descriptor);
00421         arm_uc_firmware_descriptor = NULL;
00422 
00423         if (status == EOF)
00424         {
00425             UC_PAAL_ERR_MSG("failed to close firmware file");
00426             result.code = ERR_INVALID_PARAMETER;
00427         }
00428     }
00429 
00430     /* signal completion or perform extended finalization */
00431     if (result.error == ERR_NONE)
00432     {
00433         /* explicitly set code to ERR_NONE */
00434         result.code = ERR_NONE;
00435 
00436         /* use extended finalize, invoke script from worker thread */
00437         if (arm_uc_worker_parameters.finalize)
00438         {
00439             pthread_t thread;
00440 
00441             /* export location */
00442             arm_uc_pal_linux_internal_set_location(&location);
00443 
00444             /* create a second thread which executes worker_parameters_finalize */
00445             int status = pthread_create(&thread,
00446                                         NULL,
00447                                         arm_uc_pal_linux_extended_post_worker,
00448                                         arm_uc_worker_parameters.finalize);
00449 
00450             /* check if thread was successfully created */
00451             if (status != 0)
00452             {
00453                 result.code = ERR_INVALID_PARAMETER;
00454             }
00455         }
00456         else
00457         {
00458             /* call event handler */
00459             arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE);
00460         }
00461     }
00462 
00463     return result;
00464 }
00465 
00466 /**
00467  * @brief Read a fragment from the indicated storage location.
00468  * @details The function will read until the buffer is full or the end of
00469  *          the storage location has been reached. The actual amount of
00470  *          bytes read is set in the buffer struct.
00471  *
00472  * @param locati
00473  * on Storage location ID.
00474  * @param offset Offset in bytes to read from.
00475  * @param buffer Pointer to buffer struct to store fragment.
00476  * @return Returns ERR_NONE on accept, and signals the event handler with
00477  *         either DONE or ERROR when complete.
00478  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00479  */
00480 arm_uc_error_t ARM_UC_PAL_Linux_Read(uint32_t location,
00481                                      uint32_t offset,
00482                                      arm_uc_buffer_t* buffer)
00483 {
00484     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00485 
00486     if (buffer)
00487     {
00488         /* use extended finalize, invoke script from worker thread */
00489         if (arm_uc_worker_parameters.read)
00490         {
00491             pthread_t thread;
00492 
00493             /* export location, offset and buffer */
00494             arm_uc_pal_linux_internal_set_location(&location);
00495             arm_uc_pal_linux_internal_set_offset(offset);
00496             arm_uc_pal_linux_internal_set_buffer(buffer);
00497 
00498             /* create a second thread which executes worker_parameters_read */
00499             int status = pthread_create(&thread,
00500                                         NULL,
00501                                         arm_uc_pal_linux_extended_pre_worker,
00502                                         arm_uc_worker_parameters.read);
00503 
00504             /* check if thread was successfully created */
00505             if (status == 0)
00506             {
00507                 result.code = ERR_NONE;
00508             }
00509         }
00510         else
00511         {
00512             /* normal read */
00513             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00514 
00515             /* construct firmware file path */
00516             result = arm_uc_pal_linux_internal_file_path(file_path,
00517                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00518                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00519                                                          "firmware",
00520                                                          &location);
00521 
00522             /* file path is valid */
00523             if (result.error == ERR_NONE)
00524             {
00525                 result = arm_uc_pal_linux_internal_read(file_path, offset, buffer);
00526 
00527                 /* signal completion */
00528                 if (result.error == ERR_NONE)
00529                 {
00530                     /* call event handler */
00531                     arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE);
00532                 }
00533             }
00534         }
00535     }
00536 
00537     return result;
00538 }
00539 
00540 /**
00541  * @brief Set the firmware image in the slot to be the new active image.
00542  * @details This call is responsible for initiating the process for
00543  *          applying a new/different image. Depending on the platform this
00544  *          could be:
00545  *           * An empty call, if the installer can deduce which slot to
00546  *             choose from based on the firmware details.
00547  *           * Setting a flag to indicate which slot to use next.
00548  *           * Decompressing/decrypting/installing the firmware image on
00549  *             top of another.
00550  *
00551  * @param location Storage location ID.
00552  * @return Returns ERR_NONE on accept, and signals the event handler with
00553  *         either DONE or ERROR when complete.
00554  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00555  */
00556 arm_uc_error_t ARM_UC_PAL_Linux_Activate(uint32_t location)
00557 {
00558     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00559 
00560     /* read firmware details from location */
00561     arm_uc_firmware_details_t details = { 0 };
00562     result = arm_uc_pal_linux_internal_read_header(&location, &details);
00563 
00564     if (result.error == ERR_NONE)
00565     {
00566         UC_PAAL_TRACE("version: %" PRIu64, details.version);
00567         UC_PAAL_TRACE("size: %"PRIu64, details.size);
00568 
00569         /* write details to active location */
00570         result = arm_uc_pal_linux_internal_write_header(NULL, &details);
00571 
00572         if (result.error == ERR_NONE)
00573         {
00574             /* explicitly set code to ERR_NONE */
00575             result.code = ERR_NONE;
00576 
00577             /* use extended activate, invoke script from worker thread */
00578             if (arm_uc_worker_parameters.activate)
00579             {
00580                 pthread_t thread;
00581 
00582                 /* export location */
00583                 arm_uc_pal_linux_internal_set_location(&location);
00584 
00585                 /* create a second thread which executes worker_parameters_read */
00586                 int status = pthread_create(&thread,
00587                                             NULL,
00588                                             arm_uc_pal_linux_extended_post_worker,
00589                                             arm_uc_worker_parameters.activate);
00590 
00591                 /* check if thread was successfully created */
00592                 if (status != 0)
00593                 {
00594                     result.code = ERR_INVALID_PARAMETER;
00595                 }
00596             }
00597             else
00598             {
00599                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE);
00600             }
00601         }
00602     }
00603 
00604     return result;
00605 }
00606 
00607 /**
00608  * @brief Get firmware details for the actively running firmware.
00609  * @details This call populates the passed details struct with information
00610  *          about the currently active firmware image. Only the fields
00611  *          marked as supported in the capabilities bitmap will have valid
00612  *          values.
00613  *
00614  * @param details Pointer to firmware details struct to be populated.
00615  * @return Returns ERR_NONE on accept, and signals the event handler with
00616  *         either DONE or ERROR when complete.
00617  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00618  */
00619 arm_uc_error_t ARM_UC_PAL_Linux_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details)
00620 {
00621     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00622 
00623     if (details)
00624     {
00625         /* use extended get firmware details, invoke script from worker thread */
00626         if (arm_uc_worker_parameters.active_details)
00627         {
00628             pthread_t thread;
00629 
00630             /* export details */
00631             arm_uc_pal_linux_internal_set_details(details);
00632 
00633             /* create a second thread which executes worker_parameters_read */
00634             int status = pthread_create(&thread,
00635                                         NULL,
00636                                         arm_uc_pal_linux_extended_pre_worker,
00637                                         arm_uc_worker_parameters.active_details);
00638 
00639             /* check if thread was created successfully */
00640             if (status == 0)
00641             {
00642                 result.code = ERR_NONE;
00643             }
00644         }
00645         else
00646         {
00647             /* normal read */
00648             result = arm_uc_pal_linux_internal_read_header(NULL, details);
00649 
00650             if (result.error == ERR_NONE)
00651             {
00652                 UC_PAAL_TRACE("version: %" PRIu64, details->version);
00653                 UC_PAAL_TRACE("size: %"PRIu64, details->size);
00654 
00655                 if (result.error == ERR_NONE)
00656                 {
00657                     arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE);
00658                 }
00659             }
00660         }
00661     }
00662 
00663     return result;
00664 }
00665 
00666 /**
00667  * @brief Get firmware details for the firmware image in the slot passed.
00668  * @details This call populates the passed details struct with information
00669  *          about the firmware image in the slot passed. Only the fields
00670  *          marked as supported in the capabilities bitmap will have valid
00671  *          values.
00672  *
00673  * @param details Pointer to firmware details struct to be populated.
00674  * @return Returns ERR_NONE on accept, and signals the event handler with
00675  *         either DONE or ERROR when complete.
00676  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00677  */
00678 arm_uc_error_t ARM_UC_PAL_Linux_GetFirmwareDetails(uint32_t location,
00679                                                    arm_uc_firmware_details_t* details)
00680 {
00681     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00682 
00683     if (details)
00684     {
00685         /* use extended get firmware details, invoke script from worker thread */
00686         if (arm_uc_worker_parameters.details)
00687         {
00688             pthread_t thread;
00689 
00690             /* export location and details */
00691             arm_uc_pal_linux_internal_set_location(&location);
00692             arm_uc_pal_linux_internal_set_details(details);
00693 
00694             /* create a second thread which executes worker_parameters_read */
00695             int status = pthread_create(&thread,
00696                                         NULL,
00697                                         arm_uc_pal_linux_extended_pre_worker,
00698                                         arm_uc_worker_parameters.details);
00699 
00700             /* check if thread was created successfully */
00701             if (status == 0)
00702             {
00703                 result.code = ERR_NONE;
00704             }
00705         }
00706         else
00707         {
00708             /* normal read */
00709             result = arm_uc_pal_linux_internal_read_header(&location, details);
00710 
00711             if (result.error == ERR_NONE)
00712             {
00713                 UC_PAAL_TRACE("version: %" PRIu64, details->version);
00714                 UC_PAAL_TRACE("size: %"PRIu64, details->size);
00715 
00716                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE);
00717             }
00718         }
00719     }
00720 
00721     return result;
00722 }
00723 
00724 /**
00725  * @brief Get details for the component responsible for installation.
00726  * @details This call populates the passed details struct with information
00727  *          about the local installer. Only the fields marked as supported
00728  *          in the capabilities bitmap will have valid values. The
00729  *          installer could be the bootloader, a recovery image, or some
00730  *          other component responsible for applying the new firmware
00731  *          image.
00732  *
00733  * @param details Pointer to installer details struct to be populated.
00734  * @return Returns ERR_NONE on accept, and signals the event handler with
00735  *         either DONE or ERROR when complete.
00736  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00737  */
00738 arm_uc_error_t ARM_UC_PAL_Linux_GetInstallerDetails(arm_uc_installer_details_t* details)
00739 {
00740     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00741 
00742     if (details)
00743     {
00744         /* use extended installer details, invoke script from worker thread */
00745         if (arm_uc_worker_parameters.installer)
00746         {
00747             pthread_t thread;
00748 
00749             /* export installer details */
00750             arm_uc_pal_linux_internal_set_installer(details);
00751 
00752             /* create a second thread which executes worker_parameters_read */
00753             int status = pthread_create(&thread,
00754                                         NULL,
00755                                         arm_uc_pal_linux_extended_pre_worker,
00756                                         arm_uc_worker_parameters.installer);
00757 
00758             /* check if threas was created successfully */
00759             if (status == 0)
00760             {
00761                 result.code = ERR_NONE;
00762             }
00763         }
00764         else
00765         {
00766             /* normal read */
00767             result = arm_uc_pal_linux_internal_read_installer(details);
00768 
00769             if (result.error == ERR_NONE)
00770             {
00771                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE);
00772             }
00773         }
00774     }
00775 
00776     return result;
00777 }
00778 
00779 #endif