bashsedpuppetaugeasfstab

Use sed (or awk) to add entry in fstab when match found


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
  1. Note that the volume group in the first block could be any name
  2. The KEYWORD in the string would (in this example) be /tmp (but careful not to match /var/tmp unless specified)
  3. The filesystem could be anything (not necessarily xfs)
  4. Any 'exec' or 'suid' present (for example) needs to be replaced if present and even if not, 'noexec' or 'nosuid' inserted.
  5. The trailing '0 0' needs to be retained.

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:


Solution

  • 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.