Initial remote interface error message localization support (#555)

* Extracted code

* Initial support for (optional) recursive image file listings

* Manpage update

* Added support for image file filter

* Updated filtering

* Made image scan depth configurable

* Code cleanup, initial support for creating nested file

* Check for existing folder

* Cleanup

* Cleanup

* Copy/rename/create

* Updated delete operation

* Delete empty folders

* Code cleanup

* Fixed typo

* Check image file nesting level

* Updated error handling

* Fixed warning

* Renaming

* Error message update

* Interface comment updates

* Added depth to image info

* Fixed scan depth check

* Squashed commit of the following:

commit 94786aec54
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Tue Dec 21 08:43:21 2021 +0100

    Added support for operation meta data, code cleanup (#534)

    * Added messages

    * Comment update

    * Interface update

    * Support for localized descriptions

    * Sort operations

    * Completed meta data

    * rasctl -s returns operation meta data

    * Manpage update

    * Type update

    * Comment update

    * Description updates

    * Comment update

    * Added convenience method

    * Added convenience method

    * Code cleanup

    * Comment update

    * Display permitted values

    * For completeness sake added permitted boolean values

    * Added support for default value

    * Removed redundant message field

    * Description update

    * Description upddate

    * Squashed commit of the following:

    commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:43:14 2021 +0100

        The data type is implicit

    commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:37:49 2021 +0100

        Renaming

    commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:29:54 2021 +0100

        Comment update

    commit 5f699aad2f835f72accdb445d1e59f094aeb108f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:24:25 2021 +0100

        Signature update

    commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:22:45 2021 +0100

        Signature update

    commit a8148ef802ca809e5a305d2caa69856c9033d932
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:16:46 2021 +0100

        Comment update

    commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:15:46 2021 +0100

        Use map instead of list

    commit 454c0438f3589904f5dbe5253963dd200ea416dd
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 10:47:36 2021 +0100

        Updated size check

    commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 01:23:43 2021 +0100

        Initial improvements

    * Default value update

    * Comment update

    * Comment update

    * Map operations by ordinal

    * Added safeguard against unknown operations

    * Added cast

    * Data type update

    * Sort map by operation name

    * Renaming

    * Code cleanup

    * Comment update

    * Renaming

    * Comment update

    * Description updates

    * Fixed typo

    * Added operation

    * Logging update

    * Interface comment update

    * Fixed typo

    * Aded operation parameters

    * Updated handling of mandatory parameters

    * Updated assertion handling

    * Added missing condition

    * Removed duplicate cod3

    * Code cleanup

    * Logging update

    * Removed duplicate code

    * Code cleanup

    * Squashed commit of the following:

    commit 4ae273ccbd
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:30:22 2021 -0600

        Loopback tester pcb (#545)

    commit 46c5c1966f
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:29:59 2021 -0600

        RaSCSI Zero version 1.0 (#546)

    commit d09df31d67
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 20:25:23 2021 -0800

        Remove redundant code from OLED script (#547)

    commit d8828da690
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 21:02:50 2021 -0600

        Added list of sponsors

    commit bcd7e8396d
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:51:45 2021 -0800

        Second attempt at properly creating the manpage dir (#542)

    commit c887edfc8c
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:50:03 2021 -0800

        Remove special elevated privileges for the Web Interface (#536)

        * Use the pi_shutdown method to restart the rascsi service

        * Use the pi_shutdown method to restart the rascsi service

        * Remove modifications to sudoers no longer needed

        * Introduce sleeps attempting to connect to socket; reduce overall number of retries

        * Remove systemd helped methods and the functionality that depends on it

        * Attempts to speed up splash code

        * Remove unneccessary verbosity

        * Attempt to optimize service definition

    commit 801aebfb96
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:22 2021 -0800

        More readable message when downloading a file (#531)

    commit 29cf58288f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:03 2021 -0800

        Add a warning notice when ejecting removable media (#526)

    commit 7efa895239
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:46:22 2021 -0800

        Unzip zipfiles before storing to iso (#525)

        * Unzip zipfiles before storing to iso

        * Add helptext

        * Skip unzip for MacZip format

        * Should not be an fstring

    commit 39bc485671
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:28:22 2021 -0800

        Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

        * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

        * Cleanup

    * Shutdown functionality is only available if started with root permissions

    * Only restrict shutdown parameters, not everything if not root

    * Updated operation count check

commit 693ade2967
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 12:04:23 2021 -0800

    Bump Macproxy version to 21.12.2 (#550)

commit 958fb95908
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Mon Dec 20 12:50:14 2021 -0600

    Adjust bus settle delay to match SCSI standard (#544)

    * Move the GCC v10 compiler flags into makefile instead of easyinstall.sh

    * #504 - Update the bus settle time to match the SCSI standard

    Co-authored-by: RaSCSI User <user@rascsi.com>

commit 200bc7251f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 06:20:22 2021 -0800

    More helpful error message when IP does not resolve for OLED screen (#541)

    * More helpful error message

    * Remove confusing fallback IP

    * Tweak message

commit 4ae273ccbd
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

commit 46c5c1966f
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:29:59 2021 -0600

    RaSCSI Zero version 1.0 (#546)

commit d09df31d67
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 20:25:23 2021 -0800

    Remove redundant code from OLED script (#547)

commit d8828da690
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 21:02:50 2021 -0600

    Added list of sponsors

commit bcd7e8396d
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:51:45 2021 -0800

    Second attempt at properly creating the manpage dir (#542)

commit c887edfc8c
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:50:03 2021 -0800

    Remove special elevated privileges for the Web Interface (#536)

    * Use the pi_shutdown method to restart the rascsi service

    * Use the pi_shutdown method to restart the rascsi service

    * Remove modifications to sudoers no longer needed

    * Introduce sleeps attempting to connect to socket; reduce overall number of retries

    * Remove systemd helped methods and the functionality that depends on it

    * Attempts to speed up splash code

    * Remove unneccessary verbosity

    * Attempt to optimize service definition

commit 801aebfb96
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:03 2021 -0800

    Add a warning notice when ejecting removable media (#526)

commit 7efa895239
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:46:22 2021 -0800

    Unzip zipfiles before storing to iso (#525)

    * Unzip zipfiles before storing to iso

    * Add helptext

    * Skip unzip for MacZip format

    * Should not be an fstring

commit 39bc485671
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:28:22 2021 -0800

    Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

    * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

    * Cleanup

commit ec31198d83
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:54:10 2021 +0100

    Optional authentication by access token (#529)

    * Added authentication by access token

    * No authentication is required for getting the rascsi version

    * Added comment

    * Interface description update

    * Manpage update

    * Added error code

    * Enum value update (backwards compatible)

    * Error code update

    * Error code update

    * Added CHECK_AUTHENTICATION

    * Comment update

    * VERSION_INFO also requires authentication

    * rasctl: Made token an optional parameter for -P

    * Fixed interface comment

commit e32211ef73
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:49:17 2021 +0100

    Recursive image file scan and image file filter (#532)

    * Extracted code

    * Initial support for (optional) recursive image file listings

    * Manpage update

    * Added support for image file filter

    * Updated filtering

    * Made image scan depth configurable

* Squashed commit of the following:

commit 192b14169f
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Tue Dec 21 09:19:05 2021 +0100

    Meta data update

commit b319d72601
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Tue Dec 21 09:02:39 2021 +0100

    Squashed commit of the following:

    commit 0ab4918c5a59f978f48cf26f431ff809e9ddae33
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Mon Dec 20 16:52:03 2021 +0100

        Scan depth determines availability of folder filter

    commit 16590cc4e4420a348fae610d749082c9d718be0a
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Mon Dec 20 15:47:08 2021 +0100

        Updated operation count check

    commit 82f7c99755f535a7a5c30fe66e377705c5306faa
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Mon Dec 20 15:41:32 2021 +0100

        Only restrict shutdown parameters, not everything if not root

    commit 9bd50d37b11c48b2130e4f6e66d12def88ddc38f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Mon Dec 20 15:28:08 2021 +0100

        Shutdown functionality is only available if started with root permissions

    commit aa5f3331abf4c178e8ce738c14fd584bd41d1b94
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Mon Dec 20 10:26:14 2021 +0100

        Squashed commit of the following:

        commit 4ae273ccbd
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 22:30:22 2021 -0600

            Loopback tester pcb (#545)

        commit 46c5c1966f
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 22:29:59 2021 -0600

            RaSCSI Zero version 1.0 (#546)

        commit d09df31d67
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 20:25:23 2021 -0800

            Remove redundant code from OLED script (#547)

        commit d8828da690
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 21:02:50 2021 -0600

            Added list of sponsors

        commit bcd7e8396d
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:51:45 2021 -0800

            Second attempt at properly creating the manpage dir (#542)

        commit c887edfc8c
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:50:03 2021 -0800

            Remove special elevated privileges for the Web Interface (#536)

            * Use the pi_shutdown method to restart the rascsi service

            * Use the pi_shutdown method to restart the rascsi service

            * Remove modifications to sudoers no longer needed

            * Introduce sleeps attempting to connect to socket; reduce overall number of retries

            * Remove systemd helped methods and the functionality that depends on it

            * Attempts to speed up splash code

            * Remove unneccessary verbosity

            * Attempt to optimize service definition

        commit 801aebfb96
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:47:22 2021 -0800

            More readable message when downloading a file (#531)

        commit 29cf58288f
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:47:03 2021 -0800

            Add a warning notice when ejecting removable media (#526)

        commit 7efa895239
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:46:22 2021 -0800

            Unzip zipfiles before storing to iso (#525)

            * Unzip zipfiles before storing to iso

            * Add helptext

            * Skip unzip for MacZip format

            * Should not be an fstring

        commit 39bc485671
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:28:22 2021 -0800

            Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

            * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

            * Cleanup

    commit a1f4b28f92bd9f7cdba18c04f61d3721fc7c720f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 21:50:15 2021 +0100

        Comment update

    commit 9cbc06caf5f00ce85e0f7f984c871ed614e2e483
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 21:49:09 2021 +0100

        Option update

    commit c4aa39c2285c5c72e2ea28ad749f5670dd10e89f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 21:46:37 2021 +0100

        Merged feature_folder_filter

    commit ea386fc74c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 19:05:07 2021 +0100

        Code cleanup

    commit 17c3201135
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 19:03:13 2021 +0100

        Removed duplicate code

    commit 296f816dd3
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 18:40:49 2021 +0100

        Logging update

    commit 73e0df8557
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 17:28:02 2021 +0100

        Code cleanup

    commit 405dbb034c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 17:13:40 2021 +0100

        Removed duplicate cod3

    commit c7c168a942
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 17:08:02 2021 +0100

        Added missing condition

    commit 6af5394f78
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 16:16:12 2021 +0100

        Updated assertion handling

    commit 632fe1acd8
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 14:33:01 2021 +0100

        Updated handling of mandatory parameters

    commit a4e0d506c6
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 14:14:09 2021 +0100

        Aded operation parameters

    commit fc783e6a43
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:38:35 2021 +0100

        Fixed typo

    commit cb1b498459
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:37:13 2021 +0100

        Interface comment update

    commit e2d4347ce6
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:35:50 2021 +0100

        Logging update

    commit cecb72df3e
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:13:44 2021 +0100

        Added operation

    commit bbf153ccd6
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:09:49 2021 +0100

        Fixed typo

    commit 29fa5c2f96
    Merge: 28a36fa ec31198
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sun Dec 19 12:07:34 2021 +0100

        Merge branch 'develop' into feature_meta_data

    commit 28a36fa308
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 15:51:02 2021 +0100

        Description updates

    commit 73df9f136c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:37:58 2021 +0100

        Comment update

    commit c3ea3c8b37
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:34:48 2021 +0100

        Renaming

    commit 6a84edd0fb
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:22:31 2021 +0100

        Comment update

    commit c0d6e66afe
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:20:20 2021 +0100

        Code cleanup

    commit cc81b588eb
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:18:31 2021 +0100

        Renaming

    commit c88628e12a
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 14:17:50 2021 +0100

        Sort map by operation name

    commit b64001e8a4
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:39:44 2021 +0100

        Data type update

    commit 8177cd3062
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:37:23 2021 +0100

        Added cast

    commit b8599ba088
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:35:40 2021 +0100

        Added safeguard against unknown operations

    commit 6b14ba6511
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:26:21 2021 +0100

        Map operations by ordinal

    commit ee101f2c6b
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:14:31 2021 +0100

        Comment update

    commit 67c958ed37
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:13:06 2021 +0100

        Comment update

    commit d1a9c40745
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 13:04:58 2021 +0100

        Default value update

    commit d9dbbc0bb3
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:47:36 2021 +0100

        Squashed commit of the following:

        commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:43:14 2021 +0100

            The data type is implicit

        commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:37:49 2021 +0100

            Renaming

        commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:29:54 2021 +0100

            Comment update

        commit 5f699aad2f835f72accdb445d1e59f094aeb108f
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:24:25 2021 +0100

            Signature update

        commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:22:45 2021 +0100

            Signature update

        commit a8148ef802ca809e5a305d2caa69856c9033d932
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:16:46 2021 +0100

            Comment update

        commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:15:46 2021 +0100

            Use map instead of list

        commit 454c0438f3589904f5dbe5253963dd200ea416dd
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 10:47:36 2021 +0100

            Updated size check

        commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 01:23:43 2021 +0100

            Initial improvements

    commit 5d6862b6b0
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 23:22:27 2021 +0100

        Description upddate

    commit 69263b3e4b
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 23:21:38 2021 +0100

        Description update

    commit 49e14f7078
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 23:19:08 2021 +0100

        Removed redundant message field

    commit ff468aafa8
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 23:09:18 2021 +0100

        Added support for default value

    commit 2da717a0a0
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 22:57:59 2021 +0100

        For completeness sake added permitted boolean values

    commit 5d894d2e4f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 22:53:07 2021 +0100

        Display permitted values

    commit acc7d3cba5
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 20:37:03 2021 +0100

        Comment update

    commit f846242aea
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 20:35:07 2021 +0100

        Code cleanup

    commit 5a9592f102
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 20:24:33 2021 +0100

        Added convenience method

    commit 9d258d9979
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 20:05:53 2021 +0100

        Added convenience method

    commit 6c4103989b
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:45:20 2021 +0100

        Comment update

    commit 7d543451f0
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:27:50 2021 +0100

        Description updates

    commit f4b0e50e66
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:23:29 2021 +0100

        Comment update

    commit 35dd3f6282
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:21:12 2021 +0100

        Type update

    commit 7a94c0e6e0
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:17:05 2021 +0100

        Manpage update

    commit 4179110bac
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:13:42 2021 +0100

        rasctl -s returns operation meta data

    commit eed83bb005
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 19:05:29 2021 +0100

        Completed meta data

    commit 4a7528d9d3
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 18:39:18 2021 +0100

        Sort operations

    commit d3af9a142c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 18:29:22 2021 +0100

        Support for localized descriptions

    commit b4ff4f52ab
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 17:53:11 2021 +0100

        Interface update

    commit e8d9e97fe5
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 16:59:49 2021 +0100

        Comment update

    commit 22753b1547
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Fri Dec 17 16:57:39 2021 +0100

        Added messages

commit b3a9292458
Merge: ea3bb83 94786ae
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Tue Dec 21 08:57:56 2021 +0100

    Merge branch 'develop' into feature_folder_filter

commit ea3bb8363a
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Tue Dec 21 08:53:30 2021 +0100

    Squashed commit of the following:

    commit 94786aec54
    Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
    Date:   Tue Dec 21 08:43:21 2021 +0100

        Added support for operation meta data, code cleanup (#534)

        * Added messages

        * Comment update

        * Interface update

        * Support for localized descriptions

        * Sort operations

        * Completed meta data

        * rasctl -s returns operation meta data

        * Manpage update

        * Type update

        * Comment update

        * Description updates

        * Comment update

        * Added convenience method

        * Added convenience method

        * Code cleanup

        * Comment update

        * Display permitted values

        * For completeness sake added permitted boolean values

        * Added support for default value

        * Removed redundant message field

        * Description update

        * Description upddate

        * Squashed commit of the following:

        commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:43:14 2021 +0100

            The data type is implicit

        commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:37:49 2021 +0100

            Renaming

        commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:29:54 2021 +0100

            Comment update

        commit 5f699aad2f835f72accdb445d1e59f094aeb108f
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:24:25 2021 +0100

            Signature update

        commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:22:45 2021 +0100

            Signature update

        commit a8148ef802ca809e5a305d2caa69856c9033d932
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:16:46 2021 +0100

            Comment update

        commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 12:15:46 2021 +0100

            Use map instead of list

        commit 454c0438f3589904f5dbe5253963dd200ea416dd
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 10:47:36 2021 +0100

            Updated size check

        commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
        Author: Uwe Seimet <Uwe.Seimet@seimet.de>
        Date:   Sat Dec 18 01:23:43 2021 +0100

            Initial improvements

        * Default value update

        * Comment update

        * Comment update

        * Map operations by ordinal

        * Added safeguard against unknown operations

        * Added cast

        * Data type update

        * Sort map by operation name

        * Renaming

        * Code cleanup

        * Comment update

        * Renaming

        * Comment update

        * Description updates

        * Fixed typo

        * Added operation

        * Logging update

        * Interface comment update

        * Fixed typo

        * Aded operation parameters

        * Updated handling of mandatory parameters

        * Updated assertion handling

        * Added missing condition

        * Removed duplicate cod3

        * Code cleanup

        * Logging update

        * Removed duplicate code

        * Code cleanup

        * Squashed commit of the following:

        commit 4ae273ccbd
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 22:30:22 2021 -0600

            Loopback tester pcb (#545)

        commit 46c5c1966f
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 22:29:59 2021 -0600

            RaSCSI Zero version 1.0 (#546)

        commit d09df31d67
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 20:25:23 2021 -0800

            Remove redundant code from OLED script (#547)

        commit d8828da690
        Author: akuker <34318535+akuker@users.noreply.github.com>
        Date:   Sun Dec 19 21:02:50 2021 -0600

            Added list of sponsors

        commit bcd7e8396d
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:51:45 2021 -0800

            Second attempt at properly creating the manpage dir (#542)

        commit c887edfc8c
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:50:03 2021 -0800

            Remove special elevated privileges for the Web Interface (#536)

            * Use the pi_shutdown method to restart the rascsi service

            * Use the pi_shutdown method to restart the rascsi service

            * Remove modifications to sudoers no longer needed

            * Introduce sleeps attempting to connect to socket; reduce overall number of retries

            * Remove systemd helped methods and the functionality that depends on it

            * Attempts to speed up splash code

            * Remove unneccessary verbosity

            * Attempt to optimize service definition

        commit 801aebfb96
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:47:22 2021 -0800

            More readable message when downloading a file (#531)

        commit 29cf58288f
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:47:03 2021 -0800

            Add a warning notice when ejecting removable media (#526)

        commit 7efa895239
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:46:22 2021 -0800

            Unzip zipfiles before storing to iso (#525)

            * Unzip zipfiles before storing to iso

            * Add helptext

            * Skip unzip for MacZip format

            * Should not be an fstring

        commit 39bc485671
        Author: Daniel Markstedt <markstedt@gmail.com>
        Date:   Sun Dec 19 15:28:22 2021 -0800

            Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

            * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

            * Cleanup

        * Shutdown functionality is only available if started with root permissions

        * Only restrict shutdown parameters, not everything if not root

        * Updated operation count check

    commit 693ade2967
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Mon Dec 20 12:04:23 2021 -0800

        Bump Macproxy version to 21.12.2 (#550)

    commit 958fb95908
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Mon Dec 20 12:50:14 2021 -0600

        Adjust bus settle delay to match SCSI standard (#544)

        * Move the GCC v10 compiler flags into makefile instead of easyinstall.sh

        * #504 - Update the bus settle time to match the SCSI standard

        Co-authored-by: RaSCSI User <user@rascsi.com>

    commit 200bc7251f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Mon Dec 20 06:20:22 2021 -0800

        More helpful error message when IP does not resolve for OLED screen (#541)

        * More helpful error message

        * Remove confusing fallback IP

        * Tweak message

    commit 4ae273ccbd
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:30:22 2021 -0600

        Loopback tester pcb (#545)

    commit 46c5c1966f
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:29:59 2021 -0600

        RaSCSI Zero version 1.0 (#546)

    commit d09df31d67
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 20:25:23 2021 -0800

        Remove redundant code from OLED script (#547)

    commit d8828da690
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 21:02:50 2021 -0600

        Added list of sponsors

    commit bcd7e8396d
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:51:45 2021 -0800

        Second attempt at properly creating the manpage dir (#542)

    commit c887edfc8c
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:50:03 2021 -0800

        Remove special elevated privileges for the Web Interface (#536)

        * Use the pi_shutdown method to restart the rascsi service

        * Use the pi_shutdown method to restart the rascsi service

        * Remove modifications to sudoers no longer needed

        * Introduce sleeps attempting to connect to socket; reduce overall number of retries

        * Remove systemd helped methods and the functionality that depends on it

        * Attempts to speed up splash code

        * Remove unneccessary verbosity

        * Attempt to optimize service definition

    commit 801aebfb96
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:22 2021 -0800

        More readable message when downloading a file (#531)

    commit 29cf58288f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:03 2021 -0800

        Add a warning notice when ejecting removable media (#526)

    commit 7efa895239
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:46:22 2021 -0800

        Unzip zipfiles before storing to iso (#525)

        * Unzip zipfiles before storing to iso

        * Add helptext

        * Skip unzip for MacZip format

        * Should not be an fstring

    commit 39bc485671
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:28:22 2021 -0800

        Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

        * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

        * Cleanup

commit 94786aec54
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Tue Dec 21 08:43:21 2021 +0100

    Added support for operation meta data, code cleanup (#534)

    * Added messages

    * Comment update

    * Interface update

    * Support for localized descriptions

    * Sort operations

    * Completed meta data

    * rasctl -s returns operation meta data

    * Manpage update

    * Type update

    * Comment update

    * Description updates

    * Comment update

    * Added convenience method

    * Added convenience method

    * Code cleanup

    * Comment update

    * Display permitted values

    * For completeness sake added permitted boolean values

    * Added support for default value

    * Removed redundant message field

    * Description update

    * Description upddate

    * Squashed commit of the following:

    commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:43:14 2021 +0100

        The data type is implicit

    commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:37:49 2021 +0100

        Renaming

    commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:29:54 2021 +0100

        Comment update

    commit 5f699aad2f835f72accdb445d1e59f094aeb108f
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:24:25 2021 +0100

        Signature update

    commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:22:45 2021 +0100

        Signature update

    commit a8148ef802ca809e5a305d2caa69856c9033d932
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:16:46 2021 +0100

        Comment update

    commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 12:15:46 2021 +0100

        Use map instead of list

    commit 454c0438f3589904f5dbe5253963dd200ea416dd
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 10:47:36 2021 +0100

        Updated size check

    commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
    Author: Uwe Seimet <Uwe.Seimet@seimet.de>
    Date:   Sat Dec 18 01:23:43 2021 +0100

        Initial improvements

    * Default value update

    * Comment update

    * Comment update

    * Map operations by ordinal

    * Added safeguard against unknown operations

    * Added cast

    * Data type update

    * Sort map by operation name

    * Renaming

    * Code cleanup

    * Comment update

    * Renaming

    * Comment update

    * Description updates

    * Fixed typo

    * Added operation

    * Logging update

    * Interface comment update

    * Fixed typo

    * Aded operation parameters

    * Updated handling of mandatory parameters

    * Updated assertion handling

    * Added missing condition

    * Removed duplicate cod3

    * Code cleanup

    * Logging update

    * Removed duplicate code

    * Code cleanup

    * Squashed commit of the following:

    commit 4ae273ccbd
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:30:22 2021 -0600

        Loopback tester pcb (#545)

    commit 46c5c1966f
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:29:59 2021 -0600

        RaSCSI Zero version 1.0 (#546)

    commit d09df31d67
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 20:25:23 2021 -0800

        Remove redundant code from OLED script (#547)

    commit d8828da690
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 21:02:50 2021 -0600

        Added list of sponsors

    commit bcd7e8396d
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:51:45 2021 -0800

        Second attempt at properly creating the manpage dir (#542)

    commit c887edfc8c
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:50:03 2021 -0800

        Remove special elevated privileges for the Web Interface (#536)

        * Use the pi_shutdown method to restart the rascsi service

        * Use the pi_shutdown method to restart the rascsi service

        * Remove modifications to sudoers no longer needed

        * Introduce sleeps attempting to connect to socket; reduce overall number of retries

        * Remove systemd helped methods and the functionality that depends on it

        * Attempts to speed up splash code

        * Remove unneccessary verbosity

        * Attempt to optimize service definition

    commit 801aebfb96
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:22 2021 -0800

        More readable message when downloading a file (#531)

    commit 29cf58288f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:03 2021 -0800

        Add a warning notice when ejecting removable media (#526)

    commit 7efa895239
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:46:22 2021 -0800

        Unzip zipfiles before storing to iso (#525)

        * Unzip zipfiles before storing to iso

        * Add helptext

        * Skip unzip for MacZip format

        * Should not be an fstring

    commit 39bc485671
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:28:22 2021 -0800

        Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

        * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

        * Cleanup

    * Shutdown functionality is only available if started with root permissions

    * Only restrict shutdown parameters, not everything if not root

    * Updated operation count check

commit 693ade2967
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 12:04:23 2021 -0800

    Bump Macproxy version to 21.12.2 (#550)

commit 958fb95908
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Mon Dec 20 12:50:14 2021 -0600

    Adjust bus settle delay to match SCSI standard (#544)

    * Move the GCC v10 compiler flags into makefile instead of easyinstall.sh

    * #504 - Update the bus settle time to match the SCSI standard

    Co-authored-by: RaSCSI User <user@rascsi.com>

commit 200bc7251f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 06:20:22 2021 -0800

    More helpful error message when IP does not resolve for OLED screen (#541)

    * More helpful error message

    * Remove confusing fallback IP

    * Tweak message

commit f59eeb842e
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 10:25:28 2021 +0100

    Squashed commit of the following:

    commit 4ae273ccbd
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:30:22 2021 -0600

        Loopback tester pcb (#545)

    commit 46c5c1966f
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 22:29:59 2021 -0600

        RaSCSI Zero version 1.0 (#546)

    commit d09df31d67
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 20:25:23 2021 -0800

        Remove redundant code from OLED script (#547)

    commit d8828da690
    Author: akuker <34318535+akuker@users.noreply.github.com>
    Date:   Sun Dec 19 21:02:50 2021 -0600

        Added list of sponsors

    commit bcd7e8396d
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:51:45 2021 -0800

        Second attempt at properly creating the manpage dir (#542)

    commit c887edfc8c
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:50:03 2021 -0800

        Remove special elevated privileges for the Web Interface (#536)

        * Use the pi_shutdown method to restart the rascsi service

        * Use the pi_shutdown method to restart the rascsi service

        * Remove modifications to sudoers no longer needed

        * Introduce sleeps attempting to connect to socket; reduce overall number of retries

        * Remove systemd helped methods and the functionality that depends on it

        * Attempts to speed up splash code

        * Remove unneccessary verbosity

        * Attempt to optimize service definition

    commit 801aebfb96
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:22 2021 -0800

        More readable message when downloading a file (#531)

    commit 29cf58288f
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:47:03 2021 -0800

        Add a warning notice when ejecting removable media (#526)

    commit 7efa895239
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:46:22 2021 -0800

        Unzip zipfiles before storing to iso (#525)

        * Unzip zipfiles before storing to iso

        * Add helptext

        * Skip unzip for MacZip format

        * Should not be an fstring

    commit 39bc485671
    Author: Daniel Markstedt <markstedt@gmail.com>
    Date:   Sun Dec 19 15:28:22 2021 -0800

        Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

        * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

        * Cleanup

commit 4ae273ccbd
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

commit 46c5c1966f
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:29:59 2021 -0600

    RaSCSI Zero version 1.0 (#546)

commit d09df31d67
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 20:25:23 2021 -0800

    Remove redundant code from OLED script (#547)

commit d8828da690
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 21:02:50 2021 -0600

    Added list of sponsors

commit bcd7e8396d
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:51:45 2021 -0800

    Second attempt at properly creating the manpage dir (#542)

commit c887edfc8c
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:50:03 2021 -0800

    Remove special elevated privileges for the Web Interface (#536)

    * Use the pi_shutdown method to restart the rascsi service

    * Use the pi_shutdown method to restart the rascsi service

    * Remove modifications to sudoers no longer needed

    * Introduce sleeps attempting to connect to socket; reduce overall number of retries

    * Remove systemd helped methods and the functionality that depends on it

    * Attempts to speed up splash code

    * Remove unneccessary verbosity

    * Attempt to optimize service definition

commit 801aebfb96
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:03 2021 -0800

    Add a warning notice when ejecting removable media (#526)

commit 7efa895239
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:46:22 2021 -0800

    Unzip zipfiles before storing to iso (#525)

    * Unzip zipfiles before storing to iso

    * Add helptext

    * Skip unzip for MacZip format

    * Should not be an fstring

commit 39bc485671
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:28:22 2021 -0800

    Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

    * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

    * Cleanup

commit 670356e0e2
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sun Dec 19 20:26:03 2021 +0100

    Code cleanup

commit 4fc8f67975
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sun Dec 19 20:21:10 2021 +0100

    Manpage update

commit 29603a327a
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sun Dec 19 19:49:56 2021 +0100

    Added optional folder name filter

commit ec31198d83
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:54:10 2021 +0100

    Optional authentication by access token (#529)

    * Added authentication by access token

    * No authentication is required for getting the rascsi version

    * Added comment

    * Interface description update

    * Manpage update

    * Added error code

    * Enum value update (backwards compatible)

    * Error code update

    * Error code update

    * Added CHECK_AUTHENTICATION

    * Comment update

    * VERSION_INFO also requires authentication

    * rasctl: Made token an optional parameter for -P

    * Fixed interface comment

commit e32211ef73
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:49:17 2021 +0100

    Recursive image file scan and image file filter (#532)

    * Extracted code

    * Initial support for (optional) recursive image file listings

    * Manpage update

    * Added support for image file filter

    * Updated filtering

    * Made image scan depth configurable

* Interface update

* Squashed commit of the following:

commit 6c98228726
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 22:45:24 2021 +0100

    Fixed scan depth check

commit 87e8b3be6a
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 20:46:36 2021 +0100

    Added depth to image info

commit 7c08fa6569
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 20:38:53 2021 +0100

    Interface comment updates

commit 29d919d30e
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 20:06:02 2021 +0100

    Error message update

commit fe76a1a577
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:56:36 2021 +0100

    Renaming

commit 412b53ddf1
Merge: bf9d906 958fb95
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:50:53 2021 +0100

    Merge branch 'develop' into feature_file_operations_with_folders

commit 958fb95908
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Mon Dec 20 12:50:14 2021 -0600

    Adjust bus settle delay to match SCSI standard (#544)

    * Move the GCC v10 compiler flags into makefile instead of easyinstall.sh

    * #504 - Update the bus settle time to match the SCSI standard

    Co-authored-by: RaSCSI User <user@rascsi.com>

commit bf9d90664c
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:42:36 2021 +0100

    Fixed warning

commit 362a90f3dc
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:37:32 2021 +0100

    Updated error handling

commit 66c380bd97
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:33:01 2021 +0100

    Check image file nesting level

commit c98a2b9069
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:06:18 2021 +0100

    Fixed typo

commit a36dabc002
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 19:03:18 2021 +0100

    Code cleanup

commit 46fc22f72a
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 18:58:27 2021 +0100

    Delete empty folders

commit d55bf3e06f
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 18:33:59 2021 +0100

    Updated delete operation

commit 5afce5f50f
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 18:31:55 2021 +0100

    Copy/rename/create

commit b969d3990a
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 15:21:17 2021 +0100

    Cleanup

commit 200bc7251f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Mon Dec 20 06:20:22 2021 -0800

    More helpful error message when IP does not resolve for OLED screen (#541)

    * More helpful error message

    * Remove confusing fallback IP

    * Tweak message

commit 6a6efa6bdd
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 12:58:29 2021 +0100

    Cleanup

commit 72ab669158
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 12:58:03 2021 +0100

    Check for existing folder

commit 6a9ac4d0da
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Mon Dec 20 12:52:26 2021 +0100

    Code cleanup, initial support for creating nested file

commit 4ae273ccbd
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

commit 46c5c1966f
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:29:59 2021 -0600

    RaSCSI Zero version 1.0 (#546)

commit d09df31d67
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 20:25:23 2021 -0800

    Remove redundant code from OLED script (#547)

commit d8828da690
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 21:02:50 2021 -0600

    Added list of sponsors

commit bcd7e8396d
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:51:45 2021 -0800

    Second attempt at properly creating the manpage dir (#542)

commit c887edfc8c
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:50:03 2021 -0800

    Remove special elevated privileges for the Web Interface (#536)

    * Use the pi_shutdown method to restart the rascsi service

    * Use the pi_shutdown method to restart the rascsi service

    * Remove modifications to sudoers no longer needed

    * Introduce sleeps attempting to connect to socket; reduce overall number of retries

    * Remove systemd helped methods and the functionality that depends on it

    * Attempts to speed up splash code

    * Remove unneccessary verbosity

    * Attempt to optimize service definition

commit 801aebfb96
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:03 2021 -0800

    Add a warning notice when ejecting removable media (#526)

commit 7efa895239
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:46:22 2021 -0800

    Unzip zipfiles before storing to iso (#525)

    * Unzip zipfiles before storing to iso

    * Add helptext

    * Skip unzip for MacZip format

    * Should not be an fstring

commit 39bc485671
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:28:22 2021 -0800

    Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

    * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

    * Cleanup

commit ec31198d83
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:54:10 2021 +0100

    Optional authentication by access token (#529)

    * Added authentication by access token

    * No authentication is required for getting the rascsi version

    * Added comment

    * Interface description update

    * Manpage update

    * Added error code

    * Enum value update (backwards compatible)

    * Error code update

    * Error code update

    * Added CHECK_AUTHENTICATION

    * Comment update

    * VERSION_INFO also requires authentication

    * rasctl: Made token an optional parameter for -P

    * Fixed interface comment

commit e32211ef73
Author: Uwe Seimet <48174652+uweseimet@users.noreply.github.com>
Date:   Sun Dec 19 11:49:17 2021 +0100

    Recursive image file scan and image file filter (#532)

    * Extracted code

    * Initial support for (optional) recursive image file listings

    * Manpage update

    * Added support for image file filter

    * Updated filtering

    * Made image scan depth configurable

* Code cleanup

* Resolved merged issues

* Fixed merge issue

* Comment update

* Message update

* Fixed typo

* Logging update

* Logging update

* Logging update

* Fixed merge issue

* Set pattern param for SERVER_INFO

* Added missing break

* Updated error handling

* Logging update

* Error message update

* Removed initial approach for localization in remote interface

* Added command context

* Initialize context

* Initial localization support class

* Localized authentication error

* Comment update

* Added TODO

* Merge with develop

* Only localize remote interface errors, but not log messages

* Removed TODO

* Use enum as localization key

* Added consistency checks

* Updated consitency checks

* Fixed initial entries

* Added fallback

* Locales are always treated lower case

* Support for string parameters

* Added convenience method

* Added localization support to rasctl

* Error message update

* Error handling update

* Error handling update

* Concatenate strings instead of using stream for error messages

* Error message handling update

* Error handling update

* Comment update

* Removed obsolete method

* Logging update

* Code cleanup

* Added assertions

* Code cleanup

* Updated empty string handling

* Code cleanup

* Added localized messages

* Added error messages

* Added more error messages

* Fixed typo

* Translation update

* Translation update

* Uodated default locale handling

* Updated locale handling

* Manpage update

* Removed debug code

* Added translations

* Added translations

* Add Swedish localization

* Swedish fix

* Added -z option to rascsi

* Manpage update

Co-authored-by: Daniel Markstedt <markstedt@gmail.com>
This commit is contained in:
Uwe Seimet 2021-12-23 08:49:04 +01:00 committed by GitHub
parent b5f71fb3b8
commit 47282c43b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 475 additions and 221 deletions

View File

@ -13,6 +13,7 @@ rascsi \- Emulates SCSI devices using the Raspberry Pi GPIO pins
[\fB\-r\fR \fIRESERVED_IDS\fR]
[\fB\-n\fR \fITYPE\fR]
[\fB\-v\fR]
[\fB\-z\fR \fILOCALE\fR]
[\fB\-IDn:[u]\fR \fIFILE\fR]
[\fB\-HDn[:u]\fR \fIFILE\fR]...
.SH DESCRIPTION
@ -77,6 +78,9 @@ The optional case-insensitive device type (SAHD, SCHD, SCRM, SCCD, SCMO, SCBR, S
.BR \-v\fI " " \fI
Display the rascsi version.
.TP
.BR \-z\fI " "\fILOCALE
Overrides the default locale for client-faces error messages. The client can override the locale.
.TP
.BR \-ID\fIn[:u] " " \fIFILE
n is the SCSI ID number (0-7). u (0-31) is the optional LUN (logical unit). The default LUN is 0.
.IP

View File

@ -8,8 +8,8 @@ NAME
SYNOPSIS
rascsi [-F[u00AE] FOLDER] [-L[u00AE] LOG_LEVEL] [-P[u00AE] ACCESS_TO
KEN_FILE] [-R SCAN_DEPTH] [-h] [-n VENDOR:PRODUCT:REVISION] [-p[u00AE]
PORT] [-r RESERVED_IDS] [-n TYPE] [-v] [-IDn:[u] FILE] [-HDn[:u]
FILE]...
PORT] [-r RESERVED_IDS] [-n TYPE] [-v] [-z LOCALE] [-IDn:[u] FILE]
[-HDn[:u] FILE]...
DESCRIPTION
rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins.
@ -99,18 +99,22 @@ OPTIONS
-v Display the rascsi version.
-z LOCALE
Overrides the default locale for client-faces error messages.
The client can override the locale.
-IDn[:u] FILE
n is the SCSI ID number (0-7). u (0-31) is the optional LUN
n is the SCSI ID number (0-7). u (0-31) is the optional LUN
(logical unit). The default LUN is 0.
FILE is the name of the image file to use for the SCSI device.
For devices that do not support an image file (SCBR, SCDP) a
FILE is the name of the image file to use for the SCSI device.
For devices that do not support an image file (SCBR, SCDP) a
dummy name must be provided.
-HDn[:u] FILE
n is the SASI ID number (0-15). The effective SASI ID is calcu
lated as n/2, the effective SASI LUN is calculated is the re
mainder of n/2. Alternatively the n:u syntax can be used, where
n is the SASI ID number (0-15). The effective SASI ID is calcu
lated as n/2, the effective SASI LUN is calculated is the re
mainder of n/2. Alternatively the n:u syntax can be used, where
ns is the SASI ID (0-7) and u the LUN (0-1).
FILE is the name of the image file to use for the SASI device.
@ -127,7 +131,7 @@ EXAMPLES
rascsi -ID0 /path/to/harddrive.hda -ID2 /path/to/cdimage.iso
Launch RaSCSI with a removable SCSI drive image as ID 0 and the raw de
vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter
vice file /dev/hdb (e.g. a USB stick) and a DaynaPort network adapter
as ID 6:
rascsi -ID0 -t scrm /dev/hdb -ID6 -t scdp DUMMY_FILENAME

View File

@ -32,6 +32,7 @@ rasctl \- Sends management commands to the rascsi process
[\fB\-t\fR \fITYPE\fR]
[\fB\-u\fR \fIUNIT\fR]
[\fB\-x\fR \fICURRENT_NAME:NEW_NAME\fR]
[\fB\-z\fR \fILOCALE\fR]
.SH DESCRIPTION
.B rasctl
Sends commands to the rascsi process to make configuration adjustments at runtime or to check the status of the devices.
@ -116,6 +117,9 @@ Delete an image file in the default image folder.
.BR \-x\fI " "\fICURRENT_NAME:NEW_NAME
Copy an image file in the default image folder.
.TP
.BR \-z\fI " "\fILOCALE
Overrides the default locale for client-facing error messages.
.TP
.BR \-i\fI " " \fIID
ID is the SCSI ID that you want to control. (0-7)
.TP

View File

@ -10,7 +10,7 @@ SYNOPSIS
-X | [-C FILENAME:FILESIZE] [-E FILENAME] [-F IMAGE_FOLDER] [-R CUR
RENT_NAME:NEW_NAME] [-c CMD] [-f FILE|PARAM] [-g LOG_LEVEL] [-h HOST]
[-i ID [-n NAME] [-p PORT] [-r RESERVED_IDS] [-t TYPE] [-u UNIT] [-x
CURRENT_NAME:NEW_NAME]
CURRENT_NAME:NEW_NAME] [-z LOCALE]
DESCRIPTION
rasctl Sends commands to the rascsi process to make configuration ad
@ -90,6 +90,9 @@ OPTIONS
-x CURRENT_NAME:NEW_NAME
Copy an image file in the default image folder.
-z LOCALE
Overrides the default locale for client-facing error messages.
-i ID ID is the SCSI ID that you want to control. (0-7)
-c CMD Command is the operation being requested. Options are:

View File

@ -95,7 +95,8 @@ SRC_RASCSI = \
rascsi_image.cpp \
rascsi_response.cpp \
rasutil.cpp \
protobuf_util.cpp
protobuf_util.cpp \
localizer.cpp
SRC_RASCSI += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI += $(shell find ./devices -name '*.cpp')
SRC_RASCSI += $(SRC_PROTOBUF)
@ -114,7 +115,8 @@ SRC_RASCTL = \
rasctl_display.cpp \
rascsi_version.cpp \
rasutil.cpp \
protobuf_util.cpp
protobuf_util.cpp \
localizer.cpp
SRC_RASCTL += $(SRC_PROTOBUF)
SRC_RASDUMP = \

View File

@ -0,0 +1,17 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include <string>
struct CommandContext {
int fd;
std::string locale;
};

View File

@ -0,0 +1,130 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "localizer.h"
#include <cassert>
#include <string>
#include <map>
#include <algorithm>
#include <regex>
using namespace std;
Localizer::Localizer()
{
// Supported locales, always lower case
supported_languages = { "en", "de", "sv" };
// Positional string arguments are %1, %2, %3
Add(ERROR_AUTHENTICATION, "en", "Authentication failed");
Add(ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
Add(ERROR_AUTHENTICATION, "sv", "Autentisering misslyckades");
Add(ERROR_OPERATION, "en", "Unknown operation");
Add(ERROR_OPERATION, "de", "Unbekannte Operation");
Add(ERROR_OPERATION, "sv", "Okänd operation");
Add(ERROR_LOG_LEVEL, "en", "Invalid log level %1");
Add(ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
Add(ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
Add(ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
Add(ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
Add(ERROR_MISSING_DEVICE_ID, "sv", "Enhetens ID saknas");
Add(ERROR_MISSING_FILENAME, "en", "Missing filename");
Add(ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
Add(ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
Add(ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
Add(ERROR_IMAGE_IN_USE, "sv", "Skivbildfilen '%1' används redan av ID %2, LUN %3");
Add(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
Add(ERROR_RESERVED_ID, "sv", "Enhets-ID %1 är reserverat");
Add(ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
Add(ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
Add(ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för avsaknat ID %1");
Add(ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
Add(ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
Add(ERROR_NON_EXISTING_UNIT, "sv", "Kommando för avsaknat ID %1, LUN %2");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
Add(ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
Add(ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
Add(ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
Add(ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
Add(ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat ID %1, LUN %2");
Add(ERROR_SASI_SCSI, "en", "SASI and SCSI can't be used at the same time");
Add(ERROR_SASI_SCSI, "de", "SASI und SCSI können nicht gleichzeitig verwendet werden");
Add(ERROR_SASI_SCSI, "sv", "SASI och SCSI kan ej användas samtidigt");
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
Add(ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
Add(ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
Add(ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
Add(ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
Add(ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
Add(ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
Add(ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
Add(ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
Add(ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
Add(ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
Add(ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
Add(ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
Add(ERROR_SHUTDOWN_PERMISSION, "sv", "Root-rättigheter saknas för att kunna stänga av eller starta om systemet");
Add(ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
Add(ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
Add(ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
Add(ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
Add(ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
Add(ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
}
void Localizer::Add(LocalizationKey key, const string& locale, const string& value)
{
// Safeguards against empty messages, duplicate entries and unsupported locales
assert(locale.size());
assert(value.size());
assert(supported_languages.find(locale) != supported_languages.end());
assert(localized_messages[locale][key].empty());
localized_messages[locale][key] = value;
}
string Localizer::Localize(LocalizationKey key, const string& locale, const string& arg1, const string& arg2,
const string &arg3)
{
string locale_lower = locale;
transform(locale_lower.begin(), locale_lower.end(), locale_lower.begin(), ::tolower);
map<LocalizationKey, string> messages = localized_messages[locale_lower];
if (messages.empty()) {
// Try to fall back to country-indepedent locale (e.g. "en" instead of "en_US")
if (locale_lower.length() > 2) {
messages = localized_messages[locale_lower.substr(0, 2)];
}
if (messages.empty()) {
messages = localized_messages["en"];
}
}
assert(!messages.empty());
string message = messages[key];
if (messages.empty()) {
return "Missing localization for enum value " + to_string(key);
}
message = regex_replace(message, regex("%1"), arg1);
message = regex_replace(message, regex("%2"), arg2);
message = regex_replace(message, regex("%3"), arg3);
return message;
}

View File

@ -0,0 +1,59 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
// Message localization support. Currently only for messages with up to 3 string parameters.
//
//---------------------------------------------------------------------------
#pragma once
#include <string>
#include <set>
#include <map>
using namespace std;
enum LocalizationKey {
ERROR_AUTHENTICATION,
ERROR_OPERATION,
ERROR_LOG_LEVEL,
ERROR_MISSING_DEVICE_ID,
ERROR_MISSING_FILENAME,
ERROR_IMAGE_IN_USE,
ERROR_RESERVED_ID,
ERROR_NON_EXISTING_DEVICE,
ERROR_NON_EXISTING_UNIT,
ERROR_UNKNOWN_DEVICE_TYPE,
ERROR_MISSING_DEVICE_TYPE,
ERROR_DUPLICATE_ID,
ERROR_SASI_SCSI,
ERROR_EJECT_REQUIRED,
ERROR_DEVICE_NAME_UPDATE,
ERROR_SHUTDOWN_MODE_MISSING,
ERROR_SHUTDOWN_MODE_INVALID,
ERROR_SHUTDOWN_PERMISSION,
ERROR_FILE_OPEN,
ERROR_BLOCK_SIZE,
ERROR_BLOCK_SIZE_NOT_CONFIGURABLE
};
class Localizer
{
public:
Localizer();
~Localizer() {};
string Localize(LocalizationKey, const string&, const string& = "", const string& = "", const string& = "");
private:
void Add(LocalizationKey, const string&, const string&);
map<string, map<LocalizationKey, string>> localized_messages;
set<string> supported_languages;
};

View File

@ -11,6 +11,7 @@
#include "os.h"
#include "log.h"
#include "rascsi_interface.pb.h"
#include "localizer.h"
#include "exceptions.h"
#include "protobuf_util.h"
@ -19,6 +20,8 @@ using namespace rascsi_interface;
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
Localizer localizer;
const string protobuf_util::GetParam(const PbCommand& command, const string& key)
{
auto map = command.params();
@ -119,14 +122,30 @@ int protobuf_util::ReadNBytes(int fd, uint8_t *buf, int n)
return offset;
}
bool protobuf_util::ReturnStatus(int fd, bool status, const string msg, const PbErrorCode error_code)
bool protobuf_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
const string& arg1, const string& arg2, const string& arg3)
{
if (!status && !msg.empty()) {
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
}
bool protobuf_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
const PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
{
// For the logfile always use English
LOGERROR("%s", localizer.Localize(key, "en", arg1, arg2, arg3).c_str());
return ReturnStatus(context, false, localizer.Localize(key, context.locale, arg1, arg2, arg3), error_code, false);
}
bool protobuf_util::ReturnStatus(const CommandContext& context, bool status, const string& msg,
const PbErrorCode error_code, bool log)
{
// Do not log twice if logging has already been done in the localized error handling above
if (log && !status && !msg.empty()) {
LOGERROR("%s", msg.c_str());
}
if (fd == -1) {
if (context.fd == -1) {
if (!msg.empty()) {
if (status) {
FPRT(stderr, "Error: ");
@ -144,13 +163,8 @@ bool protobuf_util::ReturnStatus(int fd, bool status, const string msg, const Pb
result.set_status(status);
result.set_error_code(error_code);
result.set_msg(msg);
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
}
return status;
}
bool protobuf_util::ReturnStatus(int fd, bool status, const ostringstream& msg)
{
return ReturnStatus(fd, status, msg.str());
}

View File

@ -13,6 +13,8 @@
#include "google/protobuf/message.h"
#include "rascsi_interface.pb.h"
#include "command_context.h"
#include "localizer.h"
#include <sstream>
#include <string>
@ -29,6 +31,10 @@ namespace protobuf_util
void SerializeMessage(int, const google::protobuf::Message&);
void DeserializeMessage(int, google::protobuf::Message&);
int ReadNBytes(int, uint8_t *, int);
bool ReturnStatus(int, bool = true, const string = "", const PbErrorCode error_code = PbErrorCode::NO_ERROR_CODE);
bool ReturnStatus(int, bool, const ostringstream&);
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const string& = "", const string& = "",
const string& = "");
bool ReturnLocalizedError(const CommandContext&, const LocalizationKey, const PbErrorCode, const string& = "",
const string& = "", const string& = "");
bool ReturnStatus(const CommandContext&, bool = true, const string& = "",
const PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
}

View File

@ -442,10 +442,7 @@ string ValidateLunSetup(const PbCommand& command, const vector<Device *>& existi
}
if (!is_consecutive) {
ostringstream error;
error << "LUNs for device ID " << id << " are not consecutive";
return error.str();
return "LUNs for device ID " + to_string(id) + " are not consecutive";
}
}
@ -557,16 +554,14 @@ void DetachAll()
FileSupport::UnreserveAll();
}
bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dryRun)
bool Attach(const CommandContext& context, const PbDeviceDefinition& pb_device, Device *map[], bool dryRun)
{
const int id = pb_device.id();
const int unit = pb_device.unit();
const PbDeviceType type = pb_device.type();
ostringstream error;
if (map[id * UnitNum + unit]) {
error << "Duplicate ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_DUPLICATE_ID, to_string(id), to_string(unit));
}
string filename = GetParam(pb_device, "file");
@ -575,10 +570,10 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
Device *device = device_factory.CreateDevice(type, filename);
if (!device) {
if (type == UNDEFINED) {
return ReturnStatus(fd, false, "Device type required for unknown extension of file '" + filename + "'");
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_TYPE, filename);
}
else {
return ReturnStatus(fd, false, "Unknown device type " + PbDeviceType_Name(type));
return ReturnLocalizedError(context, ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
}
}
@ -586,6 +581,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
if (unit >= supported_luns) {
delete device;
ostringstream error;
error << "Invalid unit " << unit << " for device type " << PbDeviceType_Name(type);
if (supported_luns == 1) {
error << " (0)";
@ -593,7 +589,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
else {
error << " (0-" << (supported_luns -1) << ")";
}
return ReturnStatus(fd, false, error.str());
return ReturnStatus(context, false, error.str());
}
// If no filename was provided the medium is considered removed
@ -620,7 +616,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
}
}
catch(const illegal_argument_exception& e) {
return ReturnStatus(fd, false, e.getmsg());
return ReturnStatus(context, false, e.getmsg());
}
if (pb_device.block_size()) {
@ -629,14 +625,13 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
if (!disk->SetConfiguredSectorSize(pb_device.block_size())) {
delete device;
error << "Invalid block size " << pb_device.block_size() << " bytes";
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
}
}
else {
delete device;
return ReturnStatus(fd, false, "Block size is not configurable for device type " + PbDeviceType_Name(type));
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, PbDeviceType_Name(type));
}
}
@ -644,7 +639,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
if (file_support && !device->IsRemovable() && filename.empty()) {
delete device;
return ReturnStatus(fd, false, "Device type " + PbDeviceType_Name(type) + " requires a filename");
return ReturnStatus(context, false, "Device type " + PbDeviceType_Name(type) + " requires a filename");
}
Filepath filepath;
@ -657,8 +652,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
delete device;
error << "Image file '" << filename << "' is already used by ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
try {
@ -672,8 +666,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
delete device;
error << "Image file '" << filename << "' is already used by ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
file_support->Open(filepath);
@ -682,7 +675,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
catch(const io_exception& e) {
delete device;
return ReturnStatus(fd, false, "Tried to open an invalid or non-existing file '" + initial_filename + "': " + e.getmsg());
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.getmsg());
}
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
@ -703,11 +696,10 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
std::map<string, string> params = { pb_device.params().begin(), pb_device.params().end() };
if (!device->Init(params)) {
error << "Initialization of " << device->GetType() << " device, ID " << id << ", unit " << unit << " failed";
delete device;
return ReturnStatus(fd, false, error);
return ReturnStatus(context, false, "Initialization of " + device->GetType() + " device, ID " +to_string(id) +
", unit " +to_string(unit) + " failed");
}
// Replace with the newly created unit
@ -729,10 +721,10 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
return true;
}
return ReturnStatus(fd, false, "SASI and SCSI can't be mixed");
return ReturnLocalizedError(context, ERROR_SASI_SCSI);
}
bool Detach(int fd, Device *device, Device *map[], bool dryRun)
bool Detach(const CommandContext& context, Device *device, Device *map[], bool dryRun)
{
if (!dryRun) {
for (auto const& d : devices) {
@ -756,19 +748,19 @@ bool Detach(int fd, Device *device, Device *map[], bool dryRun)
return true;
}
bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dryRun)
bool Insert(const CommandContext& context, const PbDeviceDefinition& pb_device, Device *device, bool dryRun)
{
if (!device->IsRemoved()) {
return ReturnStatus(fd, false, "Existing medium must first be ejected");
return ReturnLocalizedError(context, ERROR_EJECT_REQUIRED);
}
if (!pb_device.vendor().empty() || !pb_device.product().empty() || !pb_device.revision().empty()) {
return ReturnStatus(fd, false, "Once set the device name cannot be changed anymore");
return ReturnLocalizedError(context, ERROR_DEVICE_NAME_UPDATE);
}
string filename = GetParam(pb_device, "file");
if (filename.empty()) {
return ReturnStatus(fd, false, "Missing filename for " + PbOperation_Name(INSERT));
return ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
}
if (dryRun) {
@ -782,13 +774,11 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr
Disk *disk = dynamic_cast<Disk *>(device);
if (disk && disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(pb_device.block_size())) {
ostringstream error;
error << "Invalid block size " << pb_device.block_size() << " bytes";
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE, to_string(pb_device.block_size()));
}
}
else {
return ReturnStatus(fd, false, "Block size is not configurable for device type " + device->GetType());
return ReturnLocalizedError(context, ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, device->GetType());
}
}
@ -799,9 +789,7 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr
string initial_filename = filepath.GetPath();
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
ostringstream error;
error << "Image file '" << filename << "' is already used by ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
FileSupport *file_support = dynamic_cast<FileSupport *>(device);
@ -814,16 +802,14 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr
filepath.SetPath((rascsi_image.GetDefaultImageFolder() + "/" + filename).c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
ostringstream error;
error << "Image file '" << filename << "' is already used by ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_IMAGE_IN_USE, filename, to_string(id), to_string(unit));
}
file_support->Open(filepath);
}
}
catch(const io_exception& e) {
return ReturnStatus(fd, false, "Tried to open an invalid or non-existing file '" + initial_filename + "': " + e.getmsg());
return ReturnLocalizedError(context, ERROR_FILE_OPEN, initial_filename, e.getmsg());
}
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
@ -850,7 +836,7 @@ void TerminationHandler(int signum)
//
//---------------------------------------------------------------------------
bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& command, bool dryRun)
bool ProcessCmd(const CommandContext& context, const PbDeviceDefinition& pb_device, const PbCommand& command, bool dryRun)
{
ostringstream error;
@ -896,20 +882,20 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& co
LOGINFO("%s", s.str().c_str());
// Check the Controller Number
if (id < 0 || id >= CtrlMax) {
error << "Invalid device ID " << id << " (0-" << CtrlMax - 1 << ")";
return ReturnStatus(fd, false, error);
if (id < 0) {
return ReturnLocalizedError(context, ERROR_MISSING_DEVICE_ID);
}
if (id >= CtrlMax) {
return ReturnStatus(context, false, "Invalid device ID " + to_string(id) + " (0-" + to_string(CtrlMax - 1) + ")");
}
if (operation == ATTACH && reserved_ids.find(id) != reserved_ids.end()) {
error << "Device ID " << id << " is reserved";
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_RESERVED_ID, to_string(id));
}
// Check the Unit Number
if (unit < 0 || unit >= UnitNum) {
error << "Invalid unit " << unit << " (0-" << UnitNum - 1 << ")";
return ReturnStatus(fd, false, error);
return ReturnStatus(context, false, "Invalid unit " + to_string(unit) + " (0-" + to_string(UnitNum - 1) + ")");
}
// Copy the devices
@ -919,39 +905,37 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& co
}
if (operation == ATTACH) {
return Attach(fd, pb_device, map, dryRun);
return Attach(context, pb_device, map, dryRun);
}
// Does the controller exist?
if (!dryRun && !controllers[id]) {
error << "Received a command for non-existing ID " << id;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_NON_EXISTING_DEVICE, to_string(id));
}
// Does the unit exist?
Device *device = devices[id * UnitNum + unit];
if (!device) {
error << "Received a command for a non-existing device or unit, ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, error);
return ReturnLocalizedError(context, ERROR_NON_EXISTING_UNIT, to_string(id), to_string(unit));
}
if (operation == DETACH) {
return Detach(fd, device, map, dryRun);
return Detach(context, device, map, dryRun);
}
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
return ReturnStatus(fd, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't stoppable)");
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't stoppable)");
}
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
return ReturnStatus(fd, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't removable)");
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't removable)");
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
return ReturnStatus(fd, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't protectable)");
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't protectable)");
}
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
return ReturnStatus(fd, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't ready)");
return ReturnStatus(context, false, PbOperation_Name(operation) + " operation denied (" + device->GetType() + " isn't ready)");
}
switch (operation) {
@ -975,7 +959,7 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& co
break;
case INSERT:
return Insert(fd, pb_device, device, dryRun);
return Insert(context, pb_device, device, dryRun);
case EJECT:
if (!dryRun) {
@ -1018,44 +1002,44 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& co
break;
default:
return ReturnStatus(fd, false, "Unknown operation");
return ReturnLocalizedError(context, ERROR_OPERATION);
}
return true;
}
bool ProcessCmd(const int fd, const PbCommand& command)
bool ProcessCmd(const CommandContext& context, const PbCommand& command)
{
switch (command.operation()) {
case DETACH_ALL:
DetachAll();
return ReturnStatus(fd);
return ReturnStatus(context);
case RESERVE_IDS: {
const string ids = GetParam(command, "ids");
string error = SetReservedIds(ids);
if (!error.empty()) {
return ReturnStatus(fd, false, error);
return ReturnStatus(context, false, error);
}
return ReturnStatus(fd);
return ReturnStatus(context);
}
case CREATE_IMAGE:
return rascsi_image.CreateImage(fd, command);
return rascsi_image.CreateImage(context, command);
case DELETE_IMAGE:
return rascsi_image.DeleteImage(fd, command);
return rascsi_image.DeleteImage(context, command);
case RENAME_IMAGE:
return rascsi_image.RenameImage(fd, command);
return rascsi_image.RenameImage(context, command);
case COPY_IMAGE:
return rascsi_image.CopyImage(fd, command);
return rascsi_image.CopyImage(context, command);
case PROTECT_IMAGE:
case UNPROTECT_IMAGE:
return rascsi_image.SetImagePermissions(fd, command);
return rascsi_image.SetImagePermissions(context, command);
default:
// This is a device-specific command handled below
@ -1065,7 +1049,7 @@ bool ProcessCmd(const int fd, const PbCommand& command)
// Remember the list of reserved files, than run the dry run
const auto reserved_files = FileSupport::GetReservedFiles();
for (const auto& device : command.devices()) {
if (!ProcessCmd(fd, device, command, true)) {
if (!ProcessCmd(context, device, command, true)) {
// Dry run failed, restore the file list
FileSupport::SetReservedFiles(reserved_files);
return false;
@ -1077,26 +1061,26 @@ bool ProcessCmd(const int fd, const PbCommand& command)
string result = ValidateLunSetup(command, devices);
if (!result.empty()) {
return ReturnStatus(fd, false, result);
return ReturnStatus(context, false, result);
}
for (const auto& device : command.devices()) {
if (!ProcessCmd(fd, device, command, false)) {
if (!ProcessCmd(context, device, command, false)) {
return false;
}
}
// ATTACH and DETACH return the device list
if (fd != -1 && (command.operation() == ATTACH || command.operation() == DETACH)) {
if (context.fd != -1 && (command.operation() == ATTACH || command.operation() == DETACH)) {
// A new command with an empty device list is required here in order to return data for all devices
PbCommand command;
PbResult result;
rascsi_response.GetDevicesInfo(result, command, devices, UnitNum);
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
return true;
}
return ReturnStatus(fd);
return ReturnStatus(context);
}
bool ProcessId(const string id_spec, PbDeviceType type, int& id, int& unit)
@ -1130,9 +1114,9 @@ bool ProcessId(const string id_spec, PbDeviceType type, int& id, int& unit)
return true;
}
void ShutDown(int fd, const string& mode) {
void ShutDown(const CommandContext& context, const string& mode) {
if (mode.empty()) {
ReturnStatus(fd, false, "Can't shut down: Missing shutdown mode");
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_MISSING);
return;
}
@ -1142,21 +1126,21 @@ void ShutDown(int fd, const string& mode) {
if (mode == "rascsi") {
LOGINFO("RaSCSI shutdown requested");
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
TerminationHandler(0);
}
// The root user has UID 0
if (getuid()) {
ReturnStatus(fd, false, "Can't shut down or reboot system: Missing root permissions");
ReturnLocalizedError(context, ERROR_SHUTDOWN_PERMISSION);
return;
}
if (mode == "system") {
LOGINFO("System shutdown requested");
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
DetachAll();
@ -1167,7 +1151,7 @@ void ShutDown(int fd, const string& mode) {
else if (mode == "reboot") {
LOGINFO("System reboot requested");
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
DetachAll();
@ -1176,7 +1160,7 @@ void ShutDown(int fd, const string& mode) {
}
}
else {
ReturnStatus(fd, false, "Invalid shutdown mode '" + mode + "'hi");
ReturnLocalizedError(context, ERROR_SHUTDOWN_MODE_INVALID);
}
}
@ -1195,9 +1179,14 @@ bool ParseArgument(int argc, char* argv[], int& port)
string name;
string log_level;
string locale = setlocale(LC_MESSAGES, "");
if (locale == "C") {
locale = "en";
}
opterr = 1;
int opt;
while ((opt = getopt(argc, argv, "-IiHhb:d:n:p:r:t:D:F:L:P:R:")) != -1) {
while ((opt = getopt(argc, argv, "-IiHhb:d:n:p:r:t:z:D:F:L:P:R:")) != -1) {
switch (opt) {
// The three options below are kind of a compound option with two letters
case 'i':
@ -1229,6 +1218,10 @@ bool ParseArgument(int argc, char* argv[], int& port)
continue;
}
case 'z':
locale = optarg;
continue;
case 'F': {
string result = rascsi_image.SetDefaultImageFolder(optarg);
if (!result.empty()) {
@ -1337,7 +1330,10 @@ bool ParseArgument(int argc, char* argv[], int& port)
// Attach all specified devices
command.set_operation(ATTACH);
if (!ProcessCmd(-1, command)) {
CommandContext context;
context.fd = -1;
context.locale = locale;
if (!ProcessCmd(context, command)) {
return false;
}
@ -1397,21 +1393,22 @@ static void *MonThread(void *param)
listen(monsocket, 1);
while (true) {
int fd = -1;
CommandContext context;
context.fd = -1;
try {
// Wait for connection
struct sockaddr_in client;
socklen_t socklen = sizeof(client);
memset(&client, 0, socklen);
fd = accept(monsocket, (struct sockaddr*)&client, &socklen);
if (fd < 0) {
context.fd = accept(monsocket, (struct sockaddr*)&client, &socklen);
if (context.fd < 0) {
throw io_exception("accept() failed");
}
// Read magic string
char magic[6];
int bytes_read = ReadNBytes(fd, (uint8_t *)magic, sizeof(magic));
int bytes_read = ReadNBytes(context.fd, (uint8_t *)magic, sizeof(magic));
if (!bytes_read) {
continue;
}
@ -1421,19 +1418,22 @@ static void *MonThread(void *param)
// Fetch the command
PbCommand command;
DeserializeMessage(fd, command);
DeserializeMessage(context.fd, command);
if (!access_token.empty()) {
if (access_token != GetParam(command, "token")) {
ReturnStatus(fd, false, "Authentication failed", PbErrorCode::UNAUTHORIZED);
continue;
}
context.locale = GetParam(command, "locale");
if (context.locale.empty()) {
context.locale = "en";
}
if (!access_token.empty() && access_token != GetParam(command, "token")) {
ReturnLocalizedError(context, ERROR_AUTHENTICATION, UNAUTHORIZED);
continue;
}
if (!PbOperation_IsValid(command.operation())) {
LOGERROR("Received unknown command with operation opcode %d", command.operation());
ReturnStatus(fd, false, "Unknown command", UNKNOWN_OPERATION);
ReturnLocalizedError(context, ERROR_OPERATION, UNKNOWN_OPERATION);
continue;
}
@ -1446,10 +1446,10 @@ static void *MonThread(void *param)
string log_level = GetParam(command, "level");
bool status = SetLogLevel(log_level);
if (!status) {
ReturnStatus(fd, false, "Invalid log level: " + log_level);
ReturnLocalizedError(context, ERROR_LOG_LEVEL, log_level);
}
else {
ReturnStatus(fd);
ReturnStatus(context);
}
break;
}
@ -1457,23 +1457,23 @@ static void *MonThread(void *param)
case DEFAULT_FOLDER: {
string result = rascsi_image.SetDefaultImageFolder(GetParam(command, "folder"));
if (!result.empty()) {
ReturnStatus(fd, false, result);
ReturnStatus(context, false, result);
}
else {
ReturnStatus(fd);
ReturnStatus(context);
}
break;
}
case DEVICES_INFO: {
rascsi_response.GetDevicesInfo(result, command, devices, UnitNum);
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case DEVICE_TYPES_INFO: {
result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result, command));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
@ -1481,19 +1481,19 @@ static void *MonThread(void *param)
result.set_allocated_server_info(rascsi_response.GetServerInfo(
result, devices, reserved_ids, current_log_level, GetParam(command, "folder_pattern"),
GetParam(command, "file_pattern"), rascsi_image.GetDepth()));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case VERSION_INFO: {
result.set_allocated_version_info(rascsi_response.GetVersionInfo(result));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case LOG_LEVEL_INFO: {
result.set_allocated_log_level_info(rascsi_response.GetLogLevelInfo(result, current_log_level));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
@ -1501,14 +1501,14 @@ static void *MonThread(void *param)
result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
GetParam(command, "folder_pattern"), GetParam(command, "file_pattern"),
rascsi_image.GetDepth()));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case IMAGE_FILE_INFO: {
string filename = GetParam(command, "file");
if (filename.empty()) {
ReturnStatus(fd, false, "Can't get image file info: Missing filename");
ReturnLocalizedError(context, ERROR_MISSING_FILENAME);
}
else {
PbImageFile* image_file = new PbImageFile();
@ -1516,10 +1516,10 @@ static void *MonThread(void *param)
if (status) {
result.set_status(true);
result.set_allocated_image_file_info(image_file);
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
}
else {
ReturnStatus(fd, false, "Can't get image file info for '" + filename + "'");
ReturnStatus(context, false, "Can't get image file info for '" + filename + "'");
}
}
break;
@ -1527,31 +1527,31 @@ static void *MonThread(void *param)
case NETWORK_INTERFACES_INFO: {
result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case MAPPING_INFO: {
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case OPERATION_INFO: {
result.set_allocated_operation_info(rascsi_response.GetOperationInfo(result,
rascsi_image.GetDepth()));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case RESERVED_IDS_INFO: {
result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result, reserved_ids));
SerializeMessage(fd, result);
SerializeMessage(context.fd, result);
break;
}
case SHUT_DOWN: {
ShutDown(fd, GetParam(command, "mode"));
ShutDown(context, GetParam(command, "mode"));
break;
}
@ -1561,7 +1561,7 @@ static void *MonThread(void *param)
usleep(500 * 1000);
}
ProcessCmd(fd, command);
ProcessCmd(context, command);
break;
}
}
@ -1572,8 +1572,8 @@ static void *MonThread(void *param)
// Fall through
}
if (fd >= 0) {
close(fd);
if (context.fd >= 0) {
close(context.fd);
}
}

View File

@ -16,7 +16,6 @@
#include "devices/file_support.h"
#include "protobuf_util.h"
#include "rascsi_image.h"
#include <sstream>
#include <string>
#include <filesystem>
@ -53,7 +52,7 @@ bool RascsiImage::CheckDepth(const string& filename)
return count(filename.begin(), filename.end(), '/') <= depth;
}
bool RascsiImage::CreateImageFolder(int fd, const string& filename)
bool RascsiImage::CreateImageFolder(const CommandContext& context, const string& filename)
{
size_t filename_start = filename.rfind('/');
if (filename_start != string::npos) {
@ -65,7 +64,7 @@ bool RascsiImage::CreateImageFolder(int fd, const string& filename)
std::error_code error;
filesystem::create_directories(folder, error);
if (error) {
ReturnStatus(fd, false, "Can't create image folder '" + folder + "': " + strerror(errno));
ReturnStatus(context, false, "Can't create image folder '" + folder + "': " + strerror(errno));
return false;
}
}
@ -130,25 +129,25 @@ bool RascsiImage::IsValidDstFilename(const string& filename)
return stat(filename.c_str(), &st);
}
bool RascsiImage::CreateImage(int fd, const PbCommand& command)
bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& command)
{
string filename = GetParam(command, "file");
if (filename.empty()) {
return ReturnStatus(fd, false, "Can't create image file: Missing image filename");
return ReturnStatus(context, false, "Can't create image file: Missing image filename");
}
if (!CheckDepth(filename)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
}
string full_filename = default_image_folder + "/" + filename;
if (!IsValidDstFilename(full_filename)) {
return ReturnStatus(fd, false, "Can't create image file: '" + full_filename + "': File already exists");
return ReturnStatus(context, false, "Can't create image file: '" + full_filename + "': File already exists");
}
const string size = GetParam(command, "size");
if (size.empty()) {
return ReturnStatus(fd, false, "Can't create image file '" + full_filename + "': Missing image size");
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Missing image size");
}
off_t len;
@ -156,18 +155,16 @@ bool RascsiImage::CreateImage(int fd, const PbCommand& command)
len = stoull(size);
}
catch(const invalid_argument& e) {
return ReturnStatus(fd, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
}
catch(const out_of_range& e) {
return ReturnStatus(fd, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
}
if (len < 512 || (len & 0x1ff)) {
ostringstream error;
error << "Invalid image file size " << len << " (not a multiple of 512)";
return ReturnStatus(fd, false, error.str());
return ReturnStatus(context, false, "Invalid image file size " + to_string(len) + " (not a multiple of 512)");
}
if (!CreateImageFolder(fd, full_filename)) {
if (!CreateImageFolder(context, full_filename)) {
return false;
}
@ -178,7 +175,7 @@ bool RascsiImage::CreateImage(int fd, const PbCommand& command)
int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
if (image_fd == -1) {
return ReturnStatus(fd, false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
}
if (fallocate(image_fd, 0, 0, len)) {
@ -186,27 +183,26 @@ bool RascsiImage::CreateImage(int fd, const PbCommand& command)
unlink(full_filename.c_str());
return ReturnStatus(fd, false, "Can't allocate space for image file '" + full_filename + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't allocate space for image file '" + full_filename + "': " + string(strerror(errno)));
}
close(image_fd);
ostringstream msg;
msg << "Created " << (permissions & S_IWUSR ? "": "read-only ") << "image file '" << full_filename + "' with a size of " << len << " bytes";
LOGINFO("%s", msg.str().c_str());
LOGINFO("%s", string("Created " + string(permissions & S_IWUSR ? "": "read-only ") + "image file '" + full_filename +
"' with a size of " + to_string(len) + " bytes").c_str());
return ReturnStatus(fd);
return ReturnStatus(context);
}
bool RascsiImage::DeleteImage(int fd, const PbCommand& command)
bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& command)
{
string filename = GetParam(command, "file");
if (filename.empty()) {
return ReturnStatus(fd, false, "Missing image filename");
return ReturnStatus(context, false, "Missing image filename");
}
if (!CheckDepth(filename)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
}
string full_filename = default_image_folder + "/" + filename;
@ -216,13 +212,12 @@ bool RascsiImage::DeleteImage(int fd, const PbCommand& command)
Filepath filepath;
filepath.SetPath(full_filename.c_str());
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
ostringstream msg;
msg << "Can't delete image file '" << full_filename << "', it is currently being used by device ID " << id << ", unit " << unit;
return ReturnStatus(fd, false, msg.str());
return ReturnStatus(context, false, "Can't delete image file '" + full_filename +
"', it is currently being used by device ID " + to_string(id) + ", unit " + to_string(unit));
}
if (remove(full_filename.c_str())) {
return ReturnStatus(fd, false, "Can't delete image file '" + full_filename + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't delete image file '" + full_filename + "': " + string(strerror(errno)));
}
// Delete empty subfolders
@ -237,7 +232,7 @@ bool RascsiImage::DeleteImage(int fd, const PbCommand& command)
}
if (remove(full_folder.c_str())) {
return ReturnStatus(fd, false, "Can't delete empty image folder '" + full_folder + "'");
return ReturnStatus(context, false, "Can't delete empty image folder '" + full_folder + "'");
}
last_slash = folder.rfind('/');
@ -245,105 +240,105 @@ bool RascsiImage::DeleteImage(int fd, const PbCommand& command)
LOGINFO("Deleted image file '%s'", full_filename.c_str());
return ReturnStatus(fd);
return ReturnStatus(context);
}
bool RascsiImage::RenameImage(int fd, const PbCommand& command)
bool RascsiImage::RenameImage(const CommandContext& context, const PbCommand& command)
{
string from = GetParam(command, "from");
if (from.empty()) {
return ReturnStatus(fd, false, "Can't rename image file: Missing source filename");
return ReturnStatus(context, false, "Can't rename/move image file: Missing source filename");
}
if (!CheckDepth(from)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
}
from = default_image_folder + "/" + from;
if (!IsValidSrcFilename(from)) {
return ReturnStatus(fd, false, "Can't rename image file: '" + from + "': Invalid name or type");
return ReturnStatus(context, false, "Can't rename/move image file: '" + from + "': Invalid name or type");
}
string to = GetParam(command, "to");
if (to.empty()) {
return ReturnStatus(fd, false, "Can't rename image file '" + from + "': Missing destination filename");
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "': Missing destination filename");
}
if (!CheckDepth(to)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
}
to = default_image_folder + "/" + to;
if (!IsValidDstFilename(to)) {
return ReturnStatus(fd, false, "Can't rename image file '" + from + "' to '" + to + "': File already exists");
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "' to '" + to + "': File already exists");
}
if (!CreateImageFolder(fd, to)) {
if (!CreateImageFolder(context, to)) {
return false;
}
if (rename(from.c_str(), to.c_str())) {
return ReturnStatus(fd, false, "Can't rename image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
}
LOGINFO("Renamed image file '%s' to '%s'", from.c_str(), to.c_str());
LOGINFO("Renamed/Moved image file '%s' to '%s'", from.c_str(), to.c_str());
return ReturnStatus(fd);
return ReturnStatus(context);
}
bool RascsiImage::CopyImage(int fd, const PbCommand& command)
bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& command)
{
string from = GetParam(command, "from");
if (from.empty()) {
return ReturnStatus(fd, false, "Can't copy image file: Missing source filename");
return ReturnStatus(context, false, "Can't copy image file: Missing source filename");
}
if (!CheckDepth(from)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
}
from = default_image_folder + "/" + from;
if (!IsValidSrcFilename(from)) {
return ReturnStatus(fd, false, "Can't copy image file: '" + from + "': Invalid name or type");
return ReturnStatus(context, false, "Can't copy image file: '" + from + "': Invalid name or type");
}
string to = GetParam(command, "to");
if (to.empty()) {
return ReturnStatus(fd, false, "Can't copy image file '" + from + "': Missing destination filename");
return ReturnStatus(context, false, "Can't copy image file '" + from + "': Missing destination filename");
}
if (!CheckDepth(to)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
}
to = default_image_folder + "/" + to;
if (!IsValidDstFilename(to)) {
return ReturnStatus(fd, false, "Can't copy image file '" + from + "' to '" + to + "': File already exists");
return ReturnStatus(context, false, "Can't copy image file '" + from + "' to '" + to + "': File already exists");
}
struct stat st;
if (lstat(from.c_str(), &st)) {
return ReturnStatus(fd, false, "Can't access source image file '" + from + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't access source image file '" + from + "': " + string(strerror(errno)));
}
if (!CreateImageFolder(fd, to)) {
if (!CreateImageFolder(context, to)) {
return false;
}
// Symbolic links need a special handling
if ((st.st_mode & S_IFMT) == S_IFLNK) {
if (symlink(filesystem::read_symlink(from).c_str(), to.c_str())) {
return ReturnStatus(fd, false, "Can't copy symlink '" + from + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't copy symlink '" + from + "': " + string(strerror(errno)));
}
LOGINFO("Copied symlink '%s' to '%s'", from.c_str(), to.c_str());
return ReturnStatus(fd);
return ReturnStatus(context);
}
int fd_src = open(from.c_str(), O_RDONLY, 0);
if (fd_src == -1) {
return ReturnStatus(fd, false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
}
string permission = GetParam(command, "read_only");
@ -355,7 +350,7 @@ bool RascsiImage::CopyImage(int fd, const PbCommand& command)
if (fd_dst == -1) {
close(fd_src);
return ReturnStatus(fd, false, "Can't open destination image file '" + to + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't open destination image file '" + to + "': " + string(strerror(errno)));
}
if (sendfile(fd_dst, fd_src, 0, st.st_size) == -1) {
@ -364,7 +359,7 @@ bool RascsiImage::CopyImage(int fd, const PbCommand& command)
unlink(to.c_str());
return ReturnStatus(fd, false, "Can't copy image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
return ReturnStatus(context, false, "Can't copy image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
}
close(fd_dst);
@ -372,23 +367,23 @@ bool RascsiImage::CopyImage(int fd, const PbCommand& command)
LOGINFO("Copied image file '%s' to '%s'", from.c_str(), to.c_str());
return ReturnStatus(fd);
return ReturnStatus(context);
}
bool RascsiImage::SetImagePermissions(int fd, const PbCommand& command)
bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCommand& command)
{
string filename = GetParam(command, "file");
if (filename.empty()) {
return ReturnStatus(fd, false, "Missing image filename");
return ReturnStatus(context, false, "Missing image filename");
}
if (!CheckDepth(filename)) {
return ReturnStatus(fd, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
}
filename = default_image_folder + "/" + filename;
if (!IsValidSrcFilename(filename)) {
return ReturnStatus(fd, false, "Can't modify image file '" + filename + "': Invalid name or type");
return ReturnStatus(context, false, "Can't modify image file '" + filename + "': Invalid name or type");
}
bool protect = command.operation() == PROTECT_IMAGE;
@ -396,9 +391,8 @@ bool RascsiImage::SetImagePermissions(int fd, const PbCommand& command)
int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if (chmod(filename.c_str(), permissions) == -1) {
ostringstream error;
error << "Can't " << (protect ? "protect" : "unprotect") << " image file '" << filename << "': " << strerror(errno);
return ReturnStatus(fd, false, error.str());
return ReturnStatus(context, false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
strerror(errno));
}
if (protect) {
@ -408,5 +402,5 @@ bool RascsiImage::SetImagePermissions(int fd, const PbCommand& command)
LOGINFO("Unprotected image file '%s'", filename.c_str());
}
return ReturnStatus(fd);
return ReturnStatus(context);
}

View File

@ -10,6 +10,7 @@
#pragma once
#include "rascsi_interface.pb.h"
#include "command_context.h"
#include <string>
using namespace std;
@ -25,16 +26,16 @@ public:
void SetDepth(int depth) { this->depth = depth; }
int GetDepth() { return depth; }
bool CheckDepth(const string&);
bool CreateImageFolder(int, const string&);
bool CreateImageFolder(const CommandContext&, const string&);
string GetDefaultImageFolder() const { return default_image_folder; }
string SetDefaultImageFolder(const string&);
bool IsValidSrcFilename(const string&);
bool IsValidDstFilename(const string&);
bool CreateImage(int, const PbCommand&);
bool DeleteImage(int, const PbCommand&);
bool RenameImage(int, const PbCommand&);
bool CopyImage(int, const PbCommand&);
bool SetImagePermissions(int, const PbCommand&);
bool CreateImage(const CommandContext&, const PbCommand&);
bool DeleteImage(const CommandContext&, const PbCommand&);
bool RenameImage(const CommandContext&, const PbCommand&);
bool CopyImage(const CommandContext&, const PbCommand&);
bool SetImagePermissions(const CommandContext&, const PbCommand&);
private:

View File

@ -3,7 +3,8 @@
// A message starts with a little endian 32 bit header which contains the protobuf message size.
// Unless explicitly specified the order of repeated data returned is undefined.
// All operations accept an optional access token, specified by the "token" parameter.
// Only the VERSION_INFO operation never requires authentication.
// All operations also accept an optional locale, specified with the "locale" parameter. If there is
// a localized error message rascsi returns it, with English being the fallback language.
//
syntax = "proto3";

View File

@ -16,7 +16,6 @@
#include "rascsi_interface.pb.h"
#include "rascsi_image.h"
#include "rascsi_response.h"
#include <sstream>
using namespace rascsi_interface;
using namespace protobuf_util;
@ -261,10 +260,8 @@ void RascsiResponse::GetDevicesInfo(PbResult& result, const PbCommand& command,
id_sets.insert(make_pair(device.id(), device.unit()));
}
else {
ostringstream error;
error << "No device for ID " << device.id() << ", unit " << device.unit();
result.set_status(false);
result.set_msg(error.str());
result.set_msg("No device for ID " + to_string(device.id()) + ", unit " + to_string(device.unit()));
return;
}
}

View File

@ -16,6 +16,7 @@
#include "rasutil.h"
#include "rasctl_commands.h"
#include "rascsi_interface.pb.h"
#include <clocale>
#include <iostream>
#include <list>
@ -118,7 +119,8 @@ int main(int argc, char* argv[])
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
cerr << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
cerr << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] ";
cerr << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] ";
cerr << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] ";
cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [o] [-O] [-s] [-v] [-V] [-y] [-X]" << endl;
cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0-31}, default is 0" << endl;
@ -154,9 +156,14 @@ int main(int argc, char* argv[])
string token;
bool list = false;
string locale = setlocale(LC_MESSAGES, "");
if (locale == "C") {
locale = "en";
}
opterr = 1;
int opt;
while ((opt = getopt(argc, argv, "e::lmos::vDINOTVXa:b:c:d:f:h:i:n:p:r:t:u:x:C:E:F:L:P::R:")) != -1) {
while ((opt = getopt(argc, argv, "e::lmos::vDINOTVXa:b:c:d:f:h:i:n:p:r:t:u:x:z:C:E:F:L:P::R:")) != -1) {
switch (opt) {
case 'i': {
int id;
@ -350,6 +357,10 @@ int main(int argc, char* argv[])
command.set_operation(SHUT_DOWN);
AddParam(command, "mode", "rascsi");
break;
case 'z':
locale = optarg;
break;
}
}
@ -361,7 +372,7 @@ int main(int argc, char* argv[])
if (list) {
PbCommand command_list;
command_list.set_operation(DEVICES_INFO);
RasctlCommands rasctl_commands(command_list, hostname, port, token);
RasctlCommands rasctl_commands(command_list, hostname, port, token, locale);
rasctl_commands.CommandDevicesInfo();
exit(EXIT_SUCCESS);
}
@ -372,7 +383,7 @@ int main(int argc, char* argv[])
AddParam(*device, "file", param);
}
RasctlCommands rasctl_commands(command, hostname, port, token);
RasctlCommands rasctl_commands(command, hostname, port, token, locale);
switch(command.operation()) {
case LOG_LEVEL:

View File

@ -25,12 +25,14 @@ using namespace std;
using namespace rascsi_interface;
using namespace protobuf_util;
RasctlCommands::RasctlCommands(PbCommand& command, const string& hostname, int port, const string& token)
RasctlCommands::RasctlCommands(PbCommand& command, const string& hostname, int port, const string& token,
const string& locale)
{
this->command = command;
this->hostname = hostname;
this->port = port;
this->token = token;
this->locale = locale;
}
void RasctlCommands::SendCommand()
@ -39,6 +41,10 @@ void RasctlCommands::SendCommand()
AddParam(command, "token", token);
}
if (!locale.empty()) {
AddParam(command, "locale", locale);
}
// Send command
int fd = -1;
try {

View File

@ -20,7 +20,7 @@ class RasctlCommands
{
public:
RasctlCommands(PbCommand&, const string&, int, const string&);
RasctlCommands(PbCommand&, const string&, int, const string&, const string&);
~RasctlCommands() {};
void SendCommand();
@ -50,6 +50,7 @@ private:
string hostname;
int port;
string token;
string locale;
PbResult result;