FIXPERMS(1)toolbelt manualFIXPERMS(1)

fixperms

Set folders to 755 and files to 644, with a preview.

Synopsis

fixperms [options] path ...

Description

Files copied from a USB stick, a Windows share or a zip file often arrive with the wrong modes. Everything is 777, or everything is 600 and the web server cannot read it. fixperms puts a tree back to the usual modes. Folders get 755, files get 644, and scripts and programs keep their execute bit and get 755.

It never changes anything before you see what will change. It counts the folders and files, shows how many of each would change and what modes they have now, and asks once:

site has 4 folders and 5 files.
  folders to 755        3  now 777
  files to 644          3  now 666, 600
  files to 755          2  deploy.sh, css/main.css
Change 8 modes? [y/N]

The now column lists the most common current modes, up to three. The files to 755 line lists the first three names instead, because those are the files it treats as programs, and you should see which ones.

A path that already has the right mode is left alone, so a second run prints Nothing to change.

Options

What changes

OptionWhat it does
-d, --dirsChange folders only.
-f, --filesChange files only. With both -d and -f, it changes both.
--privateUse 700 for folders and 600 for files, and 700 for programs. For notes, keys and anything only you should read.
--dir-mode MODEThe mode for folders, 755 by default. Three octal digits, such as 750.
--file-mode MODEThe mode for files, 644 by default.
--no-execGive every file the file mode, scripts too.
-x, --exclude PATLeave matching names alone, and everything inside a matching folder. Can repeat.

Running

OptionWhat it does
-n, --dry-runShow what would change and stop.
--forceAllow a system folder or your home folder.
-y, --yesChange without asking. The safety checks still refuse.
-q, --quietShow only the result line.
-v, --verboseShow each step, and each find command before it runs.
-h, --helpShow the help.

How it decides

The execute rule has one catch. A file that arrived as 777, such as main.css above, has execute bits too, so it counts as a program and gets 755. When a whole tree came in as 777, run it with --no-exec first, then chmod +x the few scripts that need it:

fixperms -y --no-exec site
chmod +x site/deploy.sh

With -x, a pattern without a / matches a name anywhere in the tree, the way find -name does. A pattern with a / matches the path, the way find -path does. Quote patterns with * so the shell leaves them alone.

fixperms also takes a single file. fixperms notes.txt sets that one file.

Safety checks

The checks look at the path you type and at the real path behind it. /bin on Debian 13 is a link to /usr/bin, and both are refused as system folders.

Pass-through

fixperms takes no options for find or chmod. Use -x to skip names.

Needs

find, chmod and stat, from findutils and coreutils. Every distro has them. BusyBox has all three, and its find supports the -perm /mode tests that fixperms uses.

Examples

Fix a site copied from a USB stick

fixperms site
site has 4 folders and 5 files.
  folders to 755        3  now 777
  files to 644          3  now 666, 600
  files to 755          2  deploy.sh, css/main.css
Change 8 modes? [y/N] y
8 changed.
fixperms site
site has 4 folders and 5 files.
Nothing to change, every mode is already right.

Only the files, with no programs

fixperms -n --files --no-exec site
site has 4 folders and 5 files.
  files to 644          5  now 666, 777, 775
Dry run, nothing changed.

Leave the git folder and the scripts alone

fixperms -n -x .git -x '*.sh' site
site has 3 folders and 4 files.
  folders to 755        3  now 777
  files to 644          3  now 666, 600
  files to 755          1  css/main.css
Dry run, nothing changed.

Make a folder private

fixperms -v --private site
fixperms: counting what would change
site has 4 folders and 5 files.
  folders to 700        4  now 777, 755
  files to 600          2  now 666
  files to 700          2  deploy.sh, css/main.css
Change 8 modes? [y/N] y
+ find -P site -type d '!' -perm /7000 '!' -perm 700 -exec chmod 700 '{}' +
+ find -P site -type f '!' -perm /7000 -perm /111 '!' -perm 700 -exec chmod 700 '{}' +
+ find -P site -type f '!' -perm /7000 '!' -perm /111 '!' -perm 600 -exec chmod 600 '{}' +
8 changed.

A shared folder keeps its setgid bit

fixperms -n site
site has 5 folders and 5 files.
  folders to 755        3  now 777
  files to 644          3  now 666, 600
  files to 755          2  deploy.sh, css/main.css
  left alone            1  setuid, setgid or sticky bit
Dry run, nothing changed.

Refusals

fixperms /etc
fixperms: refused, /etc is a system folder and its modes come from your packages. Pass --force if you are sure
fixperms ~
fixperms: refused, /home/khadir is your home folder and ~/.ssh needs 700 and 600. Pick a folder inside it, or pass --force
fixperms link
fixperms: refused, link is a symlink to site. fixperms never follows links, give the real path

Troubleshooting

fixperms: 12 changed, 3 could not change. They belong to another user, so run it with sudo
Only the owner and root can change a mode. For a tree that belongs to www-data, run sudo fixperms /srv/www/shop.
A web server still returns 403
Every folder above the site needs the x bit for the server's user too. namei -l /srv/www/shop/index.html shows the mode of each folder on the way. On Fedora and RHEL, SELinux can also block reads. Check with ls -Z and fix the label with restorecon -R /srv/www/shop.
A script stopped running after --no-exec
--no-exec takes the x bit off every file. Put it back with chmod +x script.sh.
ssh says bad permissions after --force on your home
Run fixperms -y --private ~/.ssh, which sets the folder to 700 and the keys to 600.

Exit status

CodeMeaning
0It worked, or there was nothing to change.
1It failed. A path is missing, or some modes could not change.
2Bad usage, such as a mode like 7777 or no path.
3find, chmod or stat is missing.
4Refused. A system folder, your home folder, a symlink, or no terminal to ask in.
5You answered no.

See also

chmod(1), find(1), namei(1)