Informix Error -26
-26 Text file busy.
An operating-system error code with the meaning shown was unexpectedly returned to the database server. If the current operation requires the use of a text file (such as the input file to LOAD or to a PRINT FILE statement in a report), retry the operation later. Look for other operating-system error messages that might give more information.
Oninit® Troubleshooting Guidance
This is an operating-system error number, not an Informix diagnosis.
The same errno is returned by many different operations, so on its own it says what the operating system refused, not what Informix was trying to do. Informix will usually have reported a more specific error alongside it — in the message log, in the SQL or ISAM error pair, or in the accompanying assert failure — and that error normally defines the real cause far more precisely than the errno does. Find it before diagnosing from this number alone.
This matters less than it used to. Later versions of the engine trap many of these conditions and report them as specific Informix errors naming the operation, the object and the context, so a bare errno in this range is increasingly a sign of an older version, an unusual code path, or a failure early in startup before the better reporting is available. If you are seeing one on a current version, the more specific error is worth looking for even harder.
Operating-System Meaning
errno 26 is ETXTBSY — Text file busy. The wording has survived unchanged since early Unix and is widely misread, including, it appears, by the official explanation above.
"Text" here means the text segment — the executable code of a running program. It has nothing to do with text files, plain text, or data files of any kind. A more useful rendering would be "executable busy".
The error occurs in exactly two situations:
| Direction | What happens |
|---|---|
| Writing to a file that is currently being executed | Refused — you cannot modify a binary while it runs |
| Executing a file that is currently open for writing | Refused — you cannot run a binary something is still writing |
Both exist to stop a program's code changing underneath it while it runs.
On the official guidance
The official explanation suggests that if the operation "requires the use of a text file (such as the input file to LOAD or to a PRINT FILE statement in a report), retry the operation later."
That advice follows from reading "text file" literally, and it will not help. A LOAD input file and a PRINT FILE output are ordinary data files; writing to them, or reading them while something else writes, does not produce ETXTBSY. A busy data file gives -16 (EBUSY) or a locking error instead.
Equally, "retry later" only helps if the process holding the executable has exited in the meantime. Retrying while the engine is still running will fail identically every time.
What This Means in Informix
Patching or upgrading in place while the instance runs
This is the case that matters. Copying new binaries into $INFORMIXDIR/bin while the engine is running fails with ETXTBSY for any file currently executing — oninit above all.
It is a protective refusal. A partially overwritten oninit while the server is running would be considerably worse than a failed copy, so the kernel prevents it.
Why mv succeeds where cp fails
This is the practical detail worth carrying away, because it explains inconsistent results during a deployment:
cpwrites into the existing inode. That inode is the running program's text segment, so the write is refused withETXTBSY.mv(arename()) replaces the directory entry. The running process keeps its original inode — still mapped, still executing — while the name now points at the new file. No write to the running image occurs, so it succeeds.
The consequence is easily missed: after a successful mv, the running process is still executing the old code. The upgrade looks complete and is not in effect until a restart. A deployment that uses mv to avoid the error has not avoided the problem, only the error message.
install and package managers generally use the rename approach for the same reason, which is why an RPM upgrade of a running service succeeds where a manual cp does not.
Other contexts
- A partially copied binary being executed — a deployment launching something while the transfer is still in progress
- A script overwritten while it is running, which can also produce strange behaviour short of this error, since the shell reads scripts incrementally
- Utilities in use by a backup or monitoring job at the moment of patching
Common Causes
- Copying over a running binary during an in-place patch or upgrade.
- A deployment overwriting
$INFORMIXDIR/binwhile the instance is up. - Executing a file still being written by a transfer.
- A script replaced while running.
- A utility in use by a scheduled job at the moment of the update.
Diagnostic Checks
Find what is executing the file. fuser marks it with e for "executable":
fuser -v /informix/bin/oninit
# USER PID ACCESS COMMAND
# /informix/bin/oninit: ifxprod 3312 ...e. oninit
lsof /informix/bin/oninit
lsof +D "$INFORMIXDIR/bin" 2>/dev/null | head -20
Every process currently executing a given binary, from /proc:
ls -l /proc/*/exe 2>/dev/null | grep -F "$INFORMIXDIR/bin/oninit"
for p in /proc/[0-9]*; do
t=$(readlink "$p/exe" 2>/dev/null) || continue
case "$t" in "$INFORMIXDIR"/bin/*) printf '%-8s %s\n' "${p##*/}" "$t" ;; esac
done
Check whether the instance is actually down before concluding a patch can proceed:
onstat -
ps -o pid,user,cmd -C oninit
ipcs -m | grep -i "$(id -un)"
For the other direction — executing a file something still has open for writing:
fuser -v /path/to/binary # look for 'w' in the ACCESS column
lsof /path/to/binary | awk '$4 ~ /w/'
Confirm whether a binary was actually replaced, since a successful mv leaves the running process on the old inode:
ls -li "$INFORMIXDIR/bin/oninit" # inode of the file on disk
ls -li /proc/$(pgrep -o oninit)/exe # inode the process is running
readlink /proc/$(pgrep -o oninit)/exe # may show "(deleted)"
A (deleted) suffix, or differing inode numbers, means the running server is executing a version that is no longer the one in the directory — the upgrade is staged but not active.
Solutions / Resolution
- Do not patch a running installation. This is the actual answer in almost every case: shut the instance down, apply the change, restart. The error is preventing something that should not be attempted.
- If a binary genuinely must be replaced without stopping, use rename semantics rather than an in-place write — and understand the consequence:
The running process continues on the old code until it is restarted. Plan that restart; do not treat the successfulcp new_oninit "$INFORMIXDIR/bin/oninit.new" # preserve ownership and mode from the original chown --reference="$INFORMIXDIR/bin/oninit" "$INFORMIXDIR/bin/oninit.new" chmod --reference="$INFORMIXDIR/bin/oninit" "$INFORMIXDIR/bin/oninit.new" mv "$INFORMIXDIR/bin/oninit.new" "$INFORMIXDIR/bin/oninit"mvas completion. - Check the staged-versus-running state with the inode comparison above after any such replacement, and after package upgrades of a running instance.
- Wait for the writer in the execute-a-file-being-written case — and fix the deployment so it does not launch before the transfer completes. A checksum verification step before execution removes the race entirely.
- Do not force it. There is no flag that makes writing to a running executable safe.
- Retrying later helps only if the holder has exited. If the engine is still up, every retry produces the same result.
Examples
Patching while the instance is up
$ cp /tmp/patch/oninit "$INFORMIXDIR/bin/oninit"
cp: cannot create regular file '/opt/informix/bin/oninit': Text file busy
$ fuser -v "$INFORMIXDIR/bin/oninit"
USER PID ACCESS COMMAND
/opt/informix/bin/oninit:
ifxprod 3312 ....e oninit
ifxprod 3318 ....e oninit
Two processes are executing the binary. The copy is refused, correctly. The remedy is a maintenance window, not a workaround.
The upgrade that appeared to work
$ mv /tmp/patch/oninit "$INFORMIXDIR/bin/oninit"
$ echo $?
0
$ ls -li "$INFORMIXDIR/bin/oninit"
917512 -rwxr-xr-x 1 ifxprod ifxprod 9214088 Sep 9 15:02 /opt/informix/bin/oninit
$ ls -li /proc/$(pgrep -o oninit)/exe
916104 -rwxr-xr-x 1 ifxprod ifxprod 9102344 Mar 11 08:14 /proc/3312/exe
$ readlink /proc/$(pgrep -o oninit)/exe
/opt/informix/bin/oninit (deleted)
The mv succeeded and reported nothing wrong. The running server is on inode 916104 — the March binary — while the directory now points at 917512. Anyone checking ls -l would conclude the patch is applied. It is staged, and takes effect at the next restart.
Executing a file still being copied
$ /informix/bin/custom_loader
-bash: /informix/bin/custom_loader: Text file busy
$ fuser -v /informix/bin/custom_loader
USER PID ACCESS COMMAND
/informix/bin/custom_loader:
deploy 8812 F.w.. scp
A deployment is still writing the file. Running it now would execute a partial binary, so the kernel refuses. Waiting for the transfer — and verifying it — is the fix.
Platform Note
errno 26 is ETXTBSY on Linux, AIX, Solaris, HP-UX and the BSD-derived systems, so the number is reliable. The wording is identical everywhere and equally misleading everywhere: it refers to the executable text segment.
One behavioural difference matters during deployments. Not every platform enforces both directions with the same strictness — some are stricter about writing to a running executable than about executing one open for writing, and some filesystems (notably network filesystems) do not enforce it at all. A deployment that succeeds against an NFS-mounted $INFORMIXDIR may be doing exactly the thing this error exists to prevent, with no error to show for it.
Finding the holder:
| Task | Linux | Solaris | AIX |
|---|---|---|---|
| Who is executing a file | fuser -v, /proc/*/exe |
fuser -u, pfiles |
fuser -V |
| Running vs on-disk image | ls -li /proc/<pid>/exe |
pmap <pid> |
procmap <pid> |
| Who has it open for write | lsof, fuser -v |
fuser -u |
fuser -V |
Related Errors / Related Topics
- -16 — Device or resource busy. The error a genuinely busy data file produces, and the one the official explanation above is really describing.
- -13 — Permission denied. Worth ruling out when a patch fails and nothing appears to be executing the target.
- -8 — Exec format error, the other error that commonly appears during upgrades and migrations when binaries are replaced.
- -1 — Operation not permitted, which can also block an in-place update when ownership is wrong.
Where -26 appears during a planned upgrade, the finding is usually the procedure rather than the error. An upgrade path that relies on overwriting a running installation will either be blocked by this error or, worse, quietly succeed through rename semantics and leave the old code running until something restarts.