Fix cd that does not persist in SysProcess calls

6 min read · Published November 3, 2026

A cd sent through the SysProcess library succeeds and then vanishes, because every call starts a fresh process and a working directory belongs to one process. AllowAll changes authorization and su root changes identity; neither gives the calls a shared session. Hold the browser location in your application, pass an explicit path to every command, and keep the file library for complete paths at or under 255 characters.

Your cd command works. It changes the working directory of the process that ran it, and that process has exited by the time you send pwd. Each call into the SysProcess library starts a fresh process; a working directory belongs to one process, and nothing copies it back to the runtime or forward to your next call. The [SysProcess] entry with Command = AllowAll decides which commands may run. su root decides who runs them. Neither setting gives your calls a shared session. Hold the browser location in your application, pass an explicit path to every command, and combine navigation with a listing in one shell invocation when a single command must do both.

Why the directory change disappears

A working directory is per-process state. A child process starts with the working directory of its parent, which here is the CODESYS runtime. When the child changes directory, it changes its own copy. When the child exits, that state is gone, and the parent's directory is untouched.

cd is a shell built-in for exactly that reason: it has to change the shell's own working directory, so it lives and dies with that shell. pwd, ls -l and whoami report the context they execute in. An interactive SSH terminal keeps one shell alive between your keystrokes, so cd, ls -l and cd .. behave like a session. A process-execution interface starts a new context for every request, so the same keystrokes sent as separate calls share nothing.

Privileges sit on a different layer. Running as root grants access to directories; it stores no directory state between processes. That is why a setup such as SysProcess 3.5.7.0 on an embedded Linux controller shows a successful cd followed by a pwd that prints the old directory. When a setting that looks correct changes nothing, the cause is usually a layer mismatch, and why a control application config setting is ignored works through that same trap in another configuration.

Read the installed help for the exact function you call. How it reports launch failure, how you wait for completion, where the exit status lands and which buffers hold standard output and standard error differ between the functions in the library.

Symptoms and what each points to

Symptom What it points to
cd returns no error; a later pwd prints the old directory Two separate processes. Session lifetime, not permissions.
cd fails inside one shell command The path itself: missing, inaccessible, or quoted so the shell parses it wrong.
The launch reports success and no listing appears You checked launch, not completion, and never read the captured standard output and standard error.
whoami prints root and navigation still fails Identity and directory state are separate. su root also ran in its own process.

The one-call test that settles it

Run one controlled test that separates a session-lifetime problem from a path problem. Pick a directory you can already inspect from the terminal.

  1. Read the signature of the SysProcess function you call, as described above, so you know its launch-failure reporting, its completion wait, its exit status and its output buffers before you send anything.
  2. Confirm the function invokes a shell instead of executing a program directly. Direct execution skips shell built-ins and operators, so cd and && never run at all.
  3. Send this in one invocation, with output capture on:
pwd; cd '/var/opt/plantfiles/line 3' && pwd && ls -l
  1. The semicolon prints the starting directory first. The && operators run the second pwd and the listing only after cd succeeds, which the shell reports as exit status 0. A failed cd stops the sequence before the listing can show you the wrong directory.
  2. Now send pwd alone in a second call. It prints the runtime's starting directory again. That missing persistence is how the interface works, and your test just proved it.

If the sequence works inside one invocation and fails across calls, the fault is in your state management, and the next section fixes it. If cd fails inside the sequence, read the error text and check the path, its access rights and its quoting before you touch any permission.

Hold the location in your application

Stop asking an external process to remember where the operator is. Your application owns that state.

  • Store the current directory in one variable. Size the declaration for the longest path you will build, and cross-check that length against the 255-character figure if you keep file calls in the same browser.
  • Give every listing the explicit stored path, or combine the navigation and the listing in a single shell invocation as in the test above.
  • Build parent navigation from the stored string. Update the stored location only after the operation succeeds.
  • On failure, keep the last valid location and show the error. Do not swap in an unrelated listing.
  • Constrain browsing to one root. Choose that root deliberately; where media should live on the controller covers the choice for video and image files.

Treat filenames as data. Spaces, quotes and shell metacharacters change how a command line is read, so quote shell-correctly, or use argument-safe execution and the file library where you can. A persistent shell is a legitimate design too, but then you own process lifetime, input and output synchronization, recovery after termination and cleanup. A series of independent SysProcess calls is not that design.

If the gathered paths feed images into a visualization, HMI image path troubleshooting after migration shows where those lookups usually break.

Example: a 92-character path against the 255-character limit

Inputs, each with its source:

  • Browsing root stored in the application: /var/opt/plantfiles, 19 characters, from your design.
  • First descent: /line 3, 7 characters, from the operator's selection.
  • Second descent: /camera frame captures, 22 characters, from the operator's selection.
  • Selected file with its leading separator: /station 12 weld 2025-03-14 frame 000147.png, 44 characters, from the directory listing.
  • The limit: 255 characters on the complete path handed to the file library's open operation, the limitation that pushed you toward SysProcess.

The rule in words: add the lengths of the parts, and compare the total with the limit.

19 + 7 + 22 + 44 = 92 characters.

255 - 92 = 163 characters of headroom.

The decision: 92 sits at or under 255, so the file library opens this path without complaint. Browse this tree with file calls and keep process calls out of it. When a complete path passes 255 characters, the open call refuses it. At that point pass explicit full paths to process calls, or open the deepest reachable directory and enumerate its children, where your API documents handle-based enumeration.

Check every limit before you drop the file library

The 255-character figure applies to the complete path string supplied to the open operation. A process call sidesteps that one interface and inherits other limits:

  • Your declarations: the strings that hold the selected path, the generated command and the returned listing each have their own length.
  • The process interface: the installed function help states the command length and output buffer limits.
  • The operating system and filesystem: check the full-path and per-filename limits on the mounted filesystem.
  • The listing format: ls -l prints columns for people. A filename with spaces splits across fields, and dates and sizes vary in format. Use it to eyeball a directory in the test; for the browser, prefer enumeration that returns entry names and attributes as separate values.

Confirming the fix

Send cd with your stored path in one call and pwd in the next. The second pwd prints the runtime's starting directory, and your browser still lists the directory named in your state variable, because the listing used the explicit path. Rename the target directory and browse again: the display keeps the last valid listing and shows the failure. That is the behavior you want an operator to see.

The decision

Recommendation: Hold the browser location in application state and give every listing an explicit path. Combine cd and ls -l in one shell invocation only when a single command must do both. Keep the file library for any tree whose complete paths stay at or under 255 characters, and reserve process calls for longer paths and for commands the file library cannot express. Take Command = AllowAll and root out of the design once browsing works.

Questions

Does Command = AllowAll create a persistent shell for SysProcess calls?

No. That entry widens command authorization: it lets the runtime launch commands it would otherwise refuse. Every launch is still its own process with its own working directory. Authorization and session lifetime are separate layers, so no authorization setting can join two calls into one session. AllowAll also permits every command, so keep it in place only while the project needs it and remove it once browsing works.

Why does whoami print root while cd still fails?

su root starts another process, and whoami reports the user of the process that ran it, inside that same call. Your next SysProcess call starts fresh under the runtime's account, with the runtime's starting directory. Identity answers who may open a path; it carries no directory state between processes. Interactive password prompts also have no terminal to answer on, so leave them out of a browser design.

Is ls -l output safe to parse into a file browser?

Not as a structured source. The columns are formatted for people: a filename with spaces splits across fields, dates and sizes vary in format, and alignment tells you nothing about the bytes in a name. Use ls -l to eyeball a directory during the one-call test. For the browser itself, use an enumeration that returns each entry name and its attributes as separate values, which keeps names intact whatever they contain.

How do I browse paths longer than 255 characters without SysProcess?

Open the deepest directory your complete path can still reach, then work from that open directory: enumerate its children and navigate by handle or by entry names, where your file library documents those operations. The 255-character figure applies to the complete path string passed to the open operation, so holding an open directory avoids rebuilding that string at every step. Confirm the behavior in the help for your installed version before you redesign around it.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote