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,6 +99,10 @@ 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
(logical unit). The default LUN is 0.

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;