Skip to content
Syno Package Land
Language: English

Run fixed administrator operations

Root operations let your app run a small set of shell scripts as root. You write the scripts in your project. An administrator approves them once. Your backend then runs one by name with root.run. Your app cannot run anything that is not in the approved set, and it cannot pass arguments.

Create a project with the capability, or add it to a native-go project:

Terminal window
synopkgland init -t native-go --with root-ops my-app
Terminal window
synopkgland add root-ops

Both write capabilities: {rootOps: true} to dsm-package.yaml. os_min_ver must be at least 7.1-42661: init uses that value by default, and add root-ops raises a lower value to it and prints the change. A new project contains the example root/whoami.sh, which prints the user id of the process:

#!/bin/sh
set -eu
id -u

rootOps: true requires at least one root/<name>.sh. A root/ directory without rootOps: true fails check.

RuleValue
File name^[a-z][a-z0-9_]{0,31}\.sh$, for example restart_service.sh
Other files in root/Not allowed
File typeRegular file. No symlinks or directories.
SizeAt most 16 KiB (16384 bytes)
First lineExactly #!/bin/sh, followed by a newline
ContentUTF-8 text with no NUL byte
ArgumentsNone. The script runs as /bin/sh with no arguments.
EnvironmentPATH=/usr/syno/bin:/usr/syno/sbin:/usr/bin:/bin, LANG=C, HOME=/. Working directory /.
Run time20 seconds, then the script is stopped
OutputStandard output and standard error are merged. At most 1 MiB is returned.

The administrator approves the package once, with the DSM password, in the app’s Administrator setup panel. In a Vue UI this is the SDK’s ExecutorSettings, and the DSM window adds no panel of its own. The generated Vue project holds its pages in ExecutorGate.vue with the SDK’s ExecutorApproval until the executor is approved, with preload: the pages mount hidden while the executor’s first status is read, so their own reads run alongside it. A page that opens a dialog by itself on mount waits until the SDK’s useExecutorPreload() is false. In a plain UI the DSM window shows the approval panel in the DSM language, and the administrator enters the password inside it. An empty password sends nothing. Approval records a digest (SHA-256) of every root/*.sh file, so only the exact scripts the administrator approved can run.

The Vue approval view explains why the app needs system privileges before asking for the password. ExecutorApproval uses a centered consent card; ExecutorSettings and the ExecutorNotice dialog use the inline layout. Administrators enter their current DSM account password and select Approve. DSM checks it directly; the app’s service does not receive or store it. About this approval expands the declared-task limits, update behavior and uninstall steps. Ordinary users see instructions to ask an administrator, without a password field.

An empty submission shows a field message and sends no request. A password refusal appears under the field and keeps the entered value for retry. Other setup failures retain their specific error message. purpose on ExecutorApproval, ExecutorNotice and ExecutorSettings supplies the app’s own reason for using system privileges; AppShell’s built-in notice uses the generic reason. Background saves supply their file-work purpose automatically.

These changes force a new approval:

ChangeNew approval
Any edit to any root/*.sh fileYes
Adding or removing a root/*.sh fileYes
Changing entry in dsm-package.yamlYes
Changing the delegate scope, destinations, operations or lifetimeYes
Changing the version number or the UI onlyNo

synopkgland status shows needs-admin-approval until the administrator approves, and ready when the approval matches the installed package.

The executor reads its approval tasks back itself: at start, every 10 minutes after a pass and every minute after a failure. executor.status reports the verdict as tasks (checking, ready, stale or failed). When the pinned, running executor reports ready, the DSM window shows an administrator the app without reading Task Scheduler and EventScheduler itself. A task another administrator changes after a readback is seen at the next one, up to 15 minutes later; until then a changed control task is still refused before the next start, stop or purge. Approval, the control task’s start, stop and purge, and a scope selection always read both tasks back first.

DSM 7.1 has no SYNO.Core.TaskScheduler.Root or SYNO.Core.EventScheduler.Root, so approval there uses older APIs:

StepDSM 7.1DSM 7.2 and later
Check the passwordPasswordConfirm v1PasswordConfirm v2, which returns a one-use token
Create the tasksEventScheduler create v1 and TaskScheduler create v3EventScheduler.Root and TaskScheduler.Root, with the token
Read the tasks backTaskScheduler list v2 and get v3TaskScheduler list v3 and get v4

The app, status, deploy and uninstall use the DSM 7.1 APIs only when DSM answers a scheduler read or the password check with an unsupported version: error 104 (the version is above the API’s maximum, as for PasswordConfirm v2 and TaskScheduler get v4) or error 103 (the method is missing at that version, as for TaskScheduler list v3). Other errors, such as a wrong password (3121) or a permission or session error, are reported and never retried with another version, and a create is never retried. On both paths both tasks are read back, and nothing runs until their owner, type and script match exactly.

If approval stops after it created one task, for example the boot task was created and the control task was not, the app deletes the tasks it created in that attempt, so no root boot task is left without its control task. The same happens when both tasks were created and read back but the executor then does not start or report healthy: without a running executor there is no task inventory, so uninstall could not find them. Tasks from an earlier approval stay. When approval fails, the app’s settings show the reason with its DSM error code, and after a wrong password or a withdrawn approval the window panel and the settings still offer to approve again.

On DSM 7.1 the password is checked, but DSM does not tie the creation of the root tasks to that check. Any signed-in administrator session can create root tasks on DSM 7.1 without your app. The check records the administrator’s consent; it is not the server-enforced proof that DSM 7.2 and later give.

The DSM 7.1 path is tested against the API set and error codes measured on DSM 7.1.1-42962. With the 104 fallback it is not yet verified on a NAS.

EventEffect
Stop the packageRoot operations pause. The approval is kept.
UpgradeOperations resume only if the approved policy and scripts still match; a new executor that matches the INFO anchor needs no approval. Otherwise the app stays at needs-admin-approval.
UninstallThe approval, the root tasks and the app’s Application Privileges rules are removed, and a portal address stops. A reinstall needs a new approval. See Data and removal.

The generated root.run route exists in native-go projects. The generated UI has no button for it. Call it from your own UI code. Only administrators can call it.

const result = await ctx.call<{ output: string }>('root.run', { name: 'whoami' })

name is the file name without .sh. The result is { output }, the merged output of the script.

executor.status returns whether the approval is ready, with tasks, the executor’s own readback of its approval tasks, and is available to every signed-in user. While the package is stopped, or an upgrade waits for approval, the executor is paused and the status is ready: false, state: "paused", with the next step in next: start the package, or, when the package is running, approve again; the root-only /usr/local/etc/synopkgland/<package>/executor.log names the cause.

LimitValue
Minimum DSM7.1-42661
Architecturesx86_64, aarch64 and armv7. armv7 is not yet verified on a NAS.
Script size16 KiB
Run time20 seconds
Output returned1 MiB
ArgumentsNone
Who can call root.runAdministrators
Symptom or codeCauseFix
internal from root.runEvery failure of a root operation reaches your app as internal: unknown name, non-zero exit, timeout, missing approval, or the executor not running.Check synopkgland status, run the script by hand with sh, and keep it under 20 seconds.
admin_requiredThe caller is not an administrator.Call root.run from an administrator’s session.
session_requiredNo live DSM session.Sign in to DSM again.
STANDALONE_ROOT_OPS_UNUSEDroot/ exists but rootOps: true is missing.Add the capability, or delete root/.
needs-admin-approval in synopkgland statusNo approval, or a script or policy changed.An administrator approves again in Administrator setup.
check rejects a scriptThe name, size or first line breaks a rule in the table.Fix the file.
Uninstall takes longThe executor deletes the boot and control tasks through DSM, then its protected folders.Read the system log for synopkgland-executor lines: task cleanup timing gives lookup, delete and verify time per task, and purge timing the task and file phases, each with the package name. On DSM 7.1 these lines are only in the journal, not in /var/log/messages: run journalctl -t synopkgland-executor.

See Errors for every code.