I have a need to edit lines in /etc/fstab and add/change fsoptions to lines where a matching volume is found. I have tried using sed and putting found blocks into registers to place them back, but am finding this one a challenge. Perhaps sed is not the best tool - I tried augeas and while it appends it did not replace and also failed if a matching line wasn't found but needed to be added (eg was only visible using the 'mount' command such as /dev/shm).
for example, if /etc/fstab has a line:
/dev/mapper/VolGroup1-tmp /tmp xfs dev,nosuid 0 0
I want to make it
/dev/mapper/VolGroup1-tmp /tmp xfs nodev,nosuid,noexec 0 0
I'm sure I am missing an easy way to do this. Using 'mount -o remount,noexec /tmp' doesn't write to /etc/fstab so I guess the only way to make changes persistent is to edit /etc/fstab directly?
I am actually going to wrap the solution in Puppet. The augeas example below fails in 2 regards:
if a line (eg /dev/shm) does not exist in /etc/fstab, it fails
if a line exists and has 'exec' it appends 'noexec' but leaves the exec also
augeas{ "/etc/fstab - ${opt} on ${mount}":
context => '/files/etc/fstab',
changes => [
"ins opt after /files/etc/fstab/*[file = '${mount}']/opt[last()]",
"set *[file = '${mount}']/opt[last()] ${opt}",
],
onlyif => "match *[file = '${mount}']/opt[. = '${opt}'] size == 0",
notify => Exec["remount_${mount}_${opt}"],
}
I'm sure I am missing an easy way to do this. Using 'mount -o remount,noexec /tmp' doesn't write to /etc/fstab so I guess the only way to make changes persistent is to edit /etc/fstab directly?
There is no for-purpose CLI for modifying mount records in /etc/fstab, if that's what you mean. Editing the file manually with a text editor is the old-school way.
As I mentioned in comments, the standard Puppet approach for working with mount records is via Mount
resources. As long as I'm writing an answer, I repeat that using these is the way you should be going about the job.
You objected in comments that
the issue is that the first string (fsname) could be anything, as could the fstype. I also want to preserve existing fsoptions that don't clash with new desired settings.
That is the issue, but not in the way I think you mean. You are in a tight spot because you are trying to accommodate multiple authorities over this aspect of your nodes' configurations. The best practice would be to give the responsibility over the mounts of interest wholly over to Puppet. It has more than enough flexibility to provide for different mount configurations on different machines.
However, if you are determined to use Puppet in this way, then it can be done. But although the task is relatively easy to describe, the particulars make it relatively complex. A sed
-based approach is possible, but would be comparatively lengthy and extremely cryptic. A better command-line tool for the main job would be awk
, and in particular, this awk
script will do the job for the case you've presented:
$1 ~ /^#.*/ || $2 != "/tmp" {print; next}
$4 ~ /.*nosuid.*/ && $4 ~ /.*noexec.*/ {print; next}
{
split($4, opts, ",")
printf "%s %s %s ", $1, $2, $3
for (i in opts) {
if (opts[i] !~ /(no)?(exec|suid)/) {
printf "%s,", opts[i]
}
}
printf "noexec,nosuid %s %s\n", $5, $6
}
Wrapping that into an Exec
resource and making any other adaptations to your specific requirements are left as an exercise.