Compare commits
95 Commits
Author | SHA1 | Date |
---|---|---|
Harald Welte | 260f4786c0 | |
Harald Welte | 73d86aeb20 | |
Janek Bevendorff | 0cc469f2b5 | |
Janek Bevendorff | a8b36864e6 | |
Janek Bevendorff | c7427cf61d | |
Janek Bevendorff | 0a3d0cff18 | |
Janek Bevendorff | 8416d9a088 | |
Janek Bevendorff | 4f35991986 | |
Janek Bevendorff | 51f514506c | |
Janek Bevendorff | 5f03542d07 | |
Janek Bevendorff | 1a0c1b984f | |
Janek Bevendorff | 78853b7703 | |
Janek Bevendorff | fbe3702c90 | |
Janek Bevendorff | f22b634607 | |
Janek Bevendorff | 0f1b35e57c | |
Janek Bevendorff | 4b84ad5997 | |
Janek Bevendorff | 2c4d2915e5 | |
Janek Bevendorff | 52d0a17cae | |
Janek Bevendorff | 9c9eb7b98a | |
Janek Bevendorff | 3fae0fa63a | |
Janek Bevendorff | e68fed9277 | |
Janek Bevendorff | 18a2cc2774 | |
Janek Bevendorff | 2ac6c3fb6c | |
Janek Bevendorff | fe570455cf | |
Janek Bevendorff | 6ba2d541fa | |
Janek Bevendorff | 585cfa4a81 | |
Janek Bevendorff | d6e66ec303 | |
Janek Bevendorff | 0f0f43fc47 | |
Janek Bevendorff | 71a5983d27 | |
Janek Bevendorff | 5da9c7f6a7 | |
Janek Bevendorff | e9dc07e3e2 | |
Janek Bevendorff | 0f1cb0be0d | |
Janek Bevendorff | c502982cac | |
Janek Bevendorff | 785c0245f0 | |
Janek Bevendorff | a87b975a72 | |
Janek Bevendorff | fea3b8e4cd | |
Janek Bevendorff | 8b7a244c27 | |
Janek Bevendorff | 876a1968da | |
Janek Bevendorff | 0e70386f81 | |
Janek Bevendorff | c02c79108e | |
Janek Bevendorff | 62a83a2a6c | |
Janek Bevendorff | d70dda84e3 | |
Janek Bevendorff | 3ee4d4b71e | |
Janek Bevendorff | 5f85b35a22 | |
Janek Bevendorff | f3182973d9 | |
Janek Bevendorff | 75d2c11ace | |
Janek Bevendorff | 181b05d116 | |
Janek Bevendorff | 755f2c62a0 | |
Janek Bevendorff | 801366d781 | |
Janek Bevendorff | b5cd13472f | |
Janek Bevendorff | ad633b262a | |
Janek Bevendorff | 1c2933e48c | |
Janek Bevendorff | 6baf317f41 | |
Janek Bevendorff | 64a7c12886 | |
Janek Bevendorff | 715c1d393c | |
Janek Bevendorff | 8b41ff5c86 | |
Janek Bevendorff | 62e4dc4c99 | |
Janek Bevendorff | 15d6f110ca | |
Janek Bevendorff | 39680df809 | |
Janek Bevendorff | 1d1a09f89a | |
Janek Bevendorff | 917966b2af | |
Janek Bevendorff | e8dd2d3ed9 | |
Janek Bevendorff | 15356c8ce5 | |
Janek Bevendorff | a2b5ac8d87 | |
Janek Bevendorff | a7d5ef2f06 | |
Janek Bevendorff | 0984a79fee | |
Janek Bevendorff | d1196fa3db | |
Janek Bevendorff | 3bd8fbc511 | |
Janek Bevendorff | 65ec9170de | |
Janek Bevendorff | bfcdf48381 | |
Janek Bevendorff | 66e3839f55 | |
Janek Bevendorff | b81371afca | |
Janek Bevendorff | f8c24cb457 | |
Janek Bevendorff | 9705fa78dc | |
Janek Bevendorff | dc8a35e78d | |
Janek Bevendorff | c68fbedb26 | |
Janek Bevendorff | 031c437f5b | |
Janek Bevendorff | 86f5ccdef3 | |
Janek Bevendorff | 0a7ba16686 | |
Janek Bevendorff | 8221e5acb3 | |
Janek Bevendorff | b719226c73 | |
Janek Bevendorff | 33f85d5d93 | |
Janek Bevendorff | 460d545a40 | |
Janek Bevendorff | 1b03f13769 | |
Janek Bevendorff | 7075faeb7a | |
Janek Bevendorff | cf078a123c | |
Janek Bevendorff | 2eae6e45de | |
Janek Bevendorff | 22f454657d | |
Janek Bevendorff | dca81553b6 | |
Janek Bevendorff | b82fb3d80b | |
Janek Bevendorff | 86803bf206 | |
Janek Bevendorff | fafe3d8275 | |
Janek Bevendorff | 840e6db3c6 | |
Janek Bevendorff | 49001dd638 | |
Janek Bevendorff | aedc33c88d |
|
@ -6,6 +6,4 @@ desktop.ini
|
|||
Desktop.ini
|
||||
.DS_Store
|
||||
|
||||
server/etc/rs-backup/server-config
|
||||
client/etc/rs-backup/client-config
|
||||
client/etc/rs-backup/include-files
|
||||
|
|
132
README.md
132
README.md
|
@ -7,11 +7,13 @@ rs-backup-suite is designed for push backups, which means the client pushes its
|
|||
|
||||
It is also a user-centric backup system. That means each user creates his own backup on the NAS instead of root backing up the whole machine at once (although this is possible). That also means that each user has a UNIX account on the NAS. The NAS username is usually `<hostname>-<local user name>` (e.g. `mymachine-johndoe`).
|
||||
|
||||
On the client machine(s) each user can create a file called `.rs-backup-include` (name is configurable) inside his home directory which includes the list of files that should be considered by the backup. Additionally root can maintain a similar file located at `/usr/local/etc/rs-backup/include-files` for the system files.
|
||||
On the client machine(s) each user can create a file called `.rs-backup/include` (name is configurable) inside his home directory which includes the list of files that should be considered by the backup. Additionally root can maintain a similar file located at `/etc/rs-backup/include-files` for the system files.
|
||||
|
||||
## Setup (please read this carefully before performing any actions!)
|
||||
rs-backup-suite is split into two parts: a client part for pushing the backup to the NAS and a server part which runs on the NAS itself.
|
||||
|
||||
**NOTE:** Any command that necessarily needs to be run as root is preceded by `sudo` in this document. If `sudo` is not available on your system, make sure you are running the command in a root shell (e.g. using `su`).
|
||||
|
||||
### Server
|
||||
For installing the server component run
|
||||
|
||||
|
@ -32,38 +34,46 @@ If you need to tweak the server settings, simply edit `/etc/rs-backup/server-con
|
|||
#### Adding a backup user
|
||||
A backup user is an unprivileged UNIX account on the server. Normally each user on each client has one corresponding backup user which he uses to log into the NAS. A backup user can be created by running
|
||||
|
||||
rs-add-user hostname username [ssh-public-key-file]
|
||||
sudo rs-add-user hostname username [ssh-public-key-file]
|
||||
|
||||
on the server where `hostname` is the name of the client host and `username` is the name of the user on that machine for whom this account is made. Of course you can use any other names for `hostname` and `username` as well, but it's generally a good idea to stick to this naming convention. The resulting UNIX username will be the combination of both.
|
||||
|
||||
The optional third parameter specifies the path to the SSH public key file which the user will use to log into the NAS. If you don't specify it, the user won't be able to log in at all. But you can add one later at any time by running
|
||||
|
||||
rs-add-ssh-key hostname username ssh-public-key-file
|
||||
sudo rs-add-ssh-key hostname username ssh-public-key-file
|
||||
|
||||
`hostname` and `username` are the same as above and mandatory for identifying the user that should get the new key.
|
||||
|
||||
**TIP:** If you don't remember the parameters for all these commands, simply run them without any and you'll get simple usage instructions.
|
||||
|
||||
#### Making the chroot work
|
||||
rs-backup-suite can chroot backup users into the backup home base directory. For this to work you need to add a few lines to your `/etc/fstab` and run `mount -a` afterwards (replace `/bkp` with your backup path):
|
||||
rs-backup-suite can chroot backup users into the backup home base directory. For this to work you need to create a few bind mounts. The install script already created the respective lines in your `/etc/fstab` for you. If you don't need any special configuration on your system, all you need to do is to uncomment everything between the `BEGIN` and `END` lines (do NOT change these two lines, though):
|
||||
|
||||
# Chroot
|
||||
/bin /bkp/bin none bind 0 0
|
||||
/lib /bkp/lib none bind 0 0
|
||||
/usr/bin /bkp/usr/bin none bind 0 0
|
||||
/usr/lib /bkp/usr/lib none bind 0 0
|
||||
/usr/share/perl5 /bkp/usr/share/perl5 none bind 0 0
|
||||
/dev /bkp/dev none bind 0 0
|
||||
# BEGIN: rs-backup-suite
|
||||
#/bin /bkp/bin none bind 0 0
|
||||
#/bin /bkp/bin none remount,ro,bind 0 0
|
||||
#/lib /bkp/lib none bind 0 0
|
||||
#/lib /bkp/lib none remount,ro,bind 0 0
|
||||
#/dev /bkp/dev none bind 0 0
|
||||
#/dev /bkp/dev none remount,ro,bind 0 0
|
||||
#/usr/bin /bkp/usr/bin none bind 0 0
|
||||
#/usr/bin /bkp/usr/bin none remount,ro,bind 0 0
|
||||
#/usr/lib /bkp/usr/lib none bind 0 0
|
||||
#/usr/lib /bkp/usr/lib none remount,ro,bind 0 0
|
||||
#/usr/share/perl5 /bkp/usr/share/perl5 none bind 0 0
|
||||
#/usr/share/perl5 /bkp/usr/share/perl5 none remount,ro,bind 0 0
|
||||
# END: rs-backup-suite
|
||||
|
||||
**NOTE:** In Ubuntu the Perl modules are located at `/usr/share/perl` instead of `/usr/share/perl5`. Change that accordingly. Also note that if you are using Synology DSM, you also need to add a bind mount for /opt/bin to /bkp/opt/bin.
|
||||
The necessary mounts may differ from system to system. For instance, Ubuntu needs `/usr/share/perl` instead of `/usr/share/perl5`. Synology DSM doesn't need `/usr/share/*` at all, but requires `/opt/bin`, `/opt/lib` and `/opt/libexec`. But in most cases you don't need to worry about that since the install script tries to make the correct decisions for you.
|
||||
|
||||
If your 64-bit system doesn't have a `/lib` folder but only `/lib64` you may need to add this to your `/etc/fstab`:
|
||||
**NOTE:** If your 64-bit system doesn't have a `/lib` folder but only `/lib64` you may need to change the `/lib` line in your `/etc/fstab` as follows:
|
||||
|
||||
/lib64 /bkp/lib64 none bind 0 0
|
||||
/lib64 /bkp/lib64 none bind 0 0
|
||||
/lib64 /bkp/lib64 none remount,ro,bind 0 0
|
||||
|
||||
and rename `/bkp/lib` to `/bkp/lib64`. Usually `/lib` is symlinked to `/lib64` though.
|
||||
Don't forget to rename `/bkp/lib` to `/bkp/lib64`. The do the same with `/usr/lib` / `/usr/lib64`.
|
||||
|
||||
Finally add this to the end of your `/etc/ssh/sshd_config`:
|
||||
When you're done, add this to the end of your `/etc/ssh/sshd_config`:
|
||||
|
||||
Match Group backup
|
||||
ChrootDirectory /bkp/
|
||||
|
@ -72,22 +82,37 @@ and restart OpenSSH. Your backup users are now chrooted into `/bkp`.
|
|||
|
||||
**NOTE:** When using a chroot environment and you change anything in your user configuration (e.g. the username) you need to run `rs-update-passwd` or your user might not be able to log in anymore.
|
||||
|
||||
**NOTE about logging:** Be aware that logging of backup success or failure on the server side will not work in a chroot environment since we mounted all our binds read-only. Additionally, certain files and libraries needed by the syslog facility may not be available. So if you want server-side logging, you cannot use chroot. Client-side logging will still work, of course.
|
||||
|
||||
#### Changing the rotation options/backup levels
|
||||
To change how many increments of which level are kept, edit the file `/bkp/etc/rsnapshot.global.conf`. This is the global configuration file for rsnapshot which will be included in each user-specific configuration. There you can tweak the names and numbers for all backup levels.
|
||||
|
||||
If you add or remove any backup levels, make sure you also update the cron scripts. By default three cron scripts are installed: `/etc/cron.daily/rs-backup-rotate`, `/etc/cron.weekly/rs-backup-rotate` and `/etc/cron.monthly/rs-backup-rotate`.
|
||||
|
||||
#### Quota support
|
||||
rs-backup-suite directly supports Linux file system quota. To make use of it, you need to enable quota for your backup drive first (i.e install the necessary utility packages, mount the backup drive with needed mount options and initialize quota files). This is pretty much straight-forward and not in any way different to any other Linux system. If you need assistance with setting up quota, I recommend you read [this quota guide](http://www.linux.com/learn/tutorials/393886-enable-per-user-disk-quotas-in-linux).
|
||||
|
||||
Once disk quota are set up, you can change the value of `SET_QUOTA` in `/etc/rs-backup/server-config` to `true` and tweak the `QUOTA_*` directives to your liking. Any new user you create with `rs-add-user` will now be assigned these initial default quota.
|
||||
|
||||
Of course you can change these default quota at any time using `rs-setquota`. For instance:
|
||||
|
||||
sudo rs-setquota local-username 500G 505G 4M 5M
|
||||
|
||||
This sets soft quota for the user `local-username` to 500GiB, hard quota to 505GiB, inode soft limit to 4194304 and inode hard limit to 5242880. You can, of course, set quota like this even when `SET_QUOTA` is `false`.
|
||||
|
||||
Editing quota using native Linux quota tools (i.e. `setquota` or `edquota`) is also possible (in fact, `rs-setquota` only provides a more user-friendly frontend to `setquota`).
|
||||
|
||||
### Client
|
||||
To set up the client you simply need to run
|
||||
|
||||
sudo ./install.sh client
|
||||
|
||||
on your client machine. Then copy the file `/etc/rs-backup/client-config.example` to `/etc/rs-backup/client-config`, edit it as root and replace the value of `REMOTE_HOST` with the hostname or IP address of your NAS.
|
||||
on your client machine. Then open the file `/etc/rs-backup/client-config` as root and replace the value of `REMOTE_HOST` with the hostname or IP address of your NAS.
|
||||
|
||||
On the client machines the script `/usr/bin/rs-backup-run` is used for performing the backups. This script can either be run as root or as an unprivileged user. The behavior differs in both cases:
|
||||
|
||||
* If run as root, all files and folder specified in /etc/rs-backup/include-files` will be backed up. The backup user used for logging into the NAS is `hostname-root` by default (where `hostname` is the hostname of the current machine). Additionally the home directories of all users will be scanned. If a home directory contains a file called `.rs-backup-include` all files and folders specified inside that file will be backed up under this user's privileges. The username used for logging into the NAS is `hostname-username` (where `hostname` is again substituted for the hostname of the current machine and `username` for the user whose home directory is being backed up).
|
||||
* If run as a normal user, only the files that are specified in your own `.rs-backup-include` will be backed up.
|
||||
* If run as root, all files and folder specified in `/etc/rs-backup/include-files` will be backed up. The backup user used for logging into the NAS is `hostname-root` by default (where `hostname` is the hostname of the current machine). Additionally the home directories of all users will be scanned. If a home directory contains a file called `.rs-backup/include` all files and folders specified inside that file will be backed up under this user's privileges. The username used for logging into the NAS is `hostname-username` (where `hostname` is again substituted for the hostname of the current machine and `username` for the user whose home directory is being backed up).
|
||||
* If run as a normal user, only the files that are specified in your own `.rs-backup/include` will be backed up.
|
||||
|
||||
#### Changing the default configuration
|
||||
All the client configuration options are defined in `/etc/rs-backup/client-config`. You can edit the file as you wish. All parameters are documented clearly by comments. Most of these configuration options can also be overridden at runtime by passing command line arguments to `rs-backup-run`. For a list and a description of all possible command line arguments run
|
||||
|
@ -95,19 +120,38 @@ All the client configuration options are defined in `/etc/rs-backup/client-confi
|
|||
rs-backup-run --help
|
||||
|
||||
## Installing client and server on the same machine
|
||||
You can of course also install server and client on the same machine. This may be useful if you want, e.g. save your data to an external USB drive instead of a real NAS. A shortcut for running both `sudo make server-install` and `sudo make client-install` is simply running
|
||||
You can of course also install server and client on the same machine. This may be useful if you want, e.g. save your data to an external USB drive instead of a real NAS. A shortcut for running both `sudo ./install server` and `sudo ./install client` is simply running
|
||||
|
||||
sudo ./install all
|
||||
|
||||
## Uninstalling
|
||||
For uninstalling run ./uninstall.sh [all|server|client]. These remove all the scripts but preserve the data in `/bkp` (or whatever your backup folder is).
|
||||
For uninstalling run
|
||||
|
||||
sudo ./uninstall.sh [all|server|client]
|
||||
|
||||
This removes all the scripts but preserves the data in `/bkp` (or whatever your backup folder is).
|
||||
|
||||
## Backup strategies
|
||||
The intended use case for rs-backup-suite is as follows: you set up the server part on your NAS. Then you create a backup user for each user on each client machine.
|
||||
|
||||
### Cron
|
||||
In the next step you edit the crontab for root on each client and add a job for running `/usr/bin/rs-backup-run` at certain times. You can of course also create a shell script that calls `rs-backup-run` and put it in `/etc/cron.daily` to perform a global backup once a day.
|
||||
|
||||
After everything is set up that way you create the file `/etc/rs-backup/include-file` and write to it a list of files and folders you want to back up as root (e.g. you can specify `/etc/***` to backup the whole `/etc` directory and all its subdirectories). Furthermore each user creates a file called `.rs-backup-include` inside his home directory that serves the same purpose for his own home directory instead of the global system. Such a file could look like this:
|
||||
### Alternative: systemd
|
||||
Since version 0.2.5, rs-backup-run comes with systemd unit files which you can use for automatically running daily backups instead.
|
||||
To enable the timer, run
|
||||
|
||||
systemctl enable rs-backup-run.timer
|
||||
systemctl start rs-backup-run.timer
|
||||
|
||||
This will enable the timer when booting the system. By default, the timer is set to run once every day (or immediately if the system was down during the last timer tick).
|
||||
|
||||
You can also start a full system backup manually at any time by running
|
||||
|
||||
systemctl start rs-backup-run.service
|
||||
|
||||
### Inclusion patterns
|
||||
After everything is set up that way you create the file `/etc/rs-backup/include-file` and write to it a list of files and folders you want to back up as root (e.g. you can specify `/etc/***` to backup the whole `/etc` directory and all its subdirectories). Furthermore each user creates a file called `.rs-backup/include` inside his home directory that serves the same purpose for his own home directory instead of the global system. Such a file could look like this:
|
||||
|
||||
- /home/johndoe/.cache/***
|
||||
/home
|
||||
|
@ -133,6 +177,50 @@ Be aware that both access methods are strictly read-only! Write access is only g
|
|||
## Side note
|
||||
Because rs-backup-suite uses rsync for the client-server communication you don't necessarily need both parts. As long as you have a working rsync server on your NAS you can use the client script to push files to it. On the other hand you can use the rs-backup-suite server part with any other rsync client, as well.
|
||||
|
||||
## Special systems
|
||||
rs-backup-suite is designed to work on most generic Linux systems, but some embedded systems may require some extra love (especially those running on busybox):
|
||||
|
||||
### Synology DSM
|
||||
To run the server component on Synology DSM, you need to install the following packages via [Entware-ng / opkg](https://github.com/Entware-ng/Entware-ng/wiki/Install-on-Synology-NAS):
|
||||
|
||||
* `rsnapshot`
|
||||
* `openssh-sftp-server`
|
||||
* `util-linux-ng`
|
||||
* `logger`
|
||||
|
||||
In `/etc/ssh/sshd_config` make sure you replace whatever line contains the subsystem configuration for the sftp server with
|
||||
|
||||
Subsystem sftp /opt/libexec/sftp-server
|
||||
|
||||
and restart the SSH server using the configuration utility from the web interace. If you are using the `synoservicectl` utility from the command line instead, make sure you are actually starting the correct SSH server from `/usr/sbin` and not from `/opt/sbin` (although that works as well, but would have a different configuration file).
|
||||
|
||||
If you want to run your backups in a chroot environment please note that `/etc/fstab` will be reset to its defaults when rebooting the disk station. To avoid configuration loss, no mount directives are added to `/etc/fstab` by the install script. Instead the following entries are added to `/etc/rc` (which won't be overwritten upon reboot):
|
||||
|
||||
# BEGIN: rs-backup-suite
|
||||
#mount -o bind /bin /var/services/homes/bin
|
||||
#mount -o remount,ro,bind /var/services/homes/bin
|
||||
#mount -o bind /lib /var/services/homes/lib
|
||||
#mount -o remount,ro,bind /var/services/homes/lib
|
||||
#mount -o bind /dev /var/services/homes/dev
|
||||
#mount -o remount,ro,bind /var/services/homes/dev
|
||||
#mount -o bind /usr/bin /var/services/homes/usr/bin
|
||||
#mount -o remount,ro,bind /var/services/homes/usr/bin
|
||||
#mount -o bind /opt/bin /var/services/homes/opt/bin
|
||||
#mount -o remount,ro,bind /var/services/homes/opt/bin
|
||||
#mount -o bind /opt/lib /var/services/homes/opt/lib
|
||||
#mount -o remount,ro,bind /var/services/homes/opt/lib
|
||||
#mount -o bind /opt/libexec /var/services/homes/opt/libexec
|
||||
#mount -o remount,ro,bind /var/services/homes/opt/libexec
|
||||
# END: rs-backup-suite
|
||||
|
||||
To enable the mounts, uncomment everything between the `BEGIN` and `END` block. Afterwards either run these commands by hand once or reboot. Of course, don't forget to also set the correct chroot path in `/etc/ssh/sshd_config` and restart the SSH daemon:
|
||||
|
||||
Match Group backup
|
||||
ChrootDirectory /var/services/homes/
|
||||
|
||||
### Cygwin
|
||||
The server component is incompatible with Cygwin for several reasons, but the client component works just fine. At the moment, though, there is no root mode for backing up all home directories at once. Desktop notifications are also unsupported.
|
||||
|
||||
## Warning to users of older versions
|
||||
`rs-backup` used to reside in `/usr/local` instead of `/usr`. With the addition of a proper Makefile in version 0.2.0 this has changed. The consequence is that older setups won't work with the new version without modifications. In order to update your setup you need to update the path to `rs-run-ssh-cmd` (now at `/usr/bin/rs-run-ssh-cmd`) inside your users' `~/.ssh/authorized_keys` files as well as the path to `rs-rotate` (`/usr/bin/rs-rotate`) inside their `rsync.conf` files. Alternatively just create symlinks to the old locations.
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
##
|
||||
# Global config file for rs-backup-run
|
||||
# This is an example file. Copy it over without the .example extension
|
||||
# and modify it to your needs.
|
||||
# Most config options can also be passed directly as command line parameters.
|
||||
##
|
||||
|
||||
# Remote host to push the files to
|
||||
# The remote host must have a working rsync server running which allows
|
||||
# passwordless (public key) login over SSH
|
||||
REMOTE_HOST="host"
|
||||
|
||||
# The rsync module on the remote server
|
||||
PUSH_MODULE="push"
|
||||
|
||||
# Username to use for logging into the remote server.
|
||||
# You can use the variables %h which will be replaced with the hostname
|
||||
# of this machine and %u which will be replaced with your local username.
|
||||
# If a global system backup is performed, %u will be 'root' for the global
|
||||
# backup and the corresponding user for the individual home directories
|
||||
REMOTE_USER="%h-%u"
|
||||
|
||||
# Additional SSH options
|
||||
#SSH_OPTIONS="-C -i .ssh/id_rsa"
|
||||
|
||||
# Additional options for rsync
|
||||
#
|
||||
# For systems that don't support it (e.g. Synology DSM), you may
|
||||
# need to remove the --acls option
|
||||
#
|
||||
# The block size setting should avoid hangs when backing up larger
|
||||
# files. It's set to the default maximum value allowed by rsync.
|
||||
# If you need larger values, recompile rsync with MAX_BLOCK_SIZE
|
||||
# set to an appropriate value.
|
||||
RSYNC_OPTIONS="--acls --hard-links --xattrs --block-size=131072"
|
||||
#RSYNC_OPTIONS="--hard-links --xattrs"
|
||||
|
||||
# Name of the file inside the users' home directories
|
||||
# containing the patterns for matching files to include or exclude.
|
||||
# The format is the same as the global 'include-files' config file
|
||||
# and described in the FILTER RULES section of the rsync(1) man page.
|
||||
# If no such file is found inside a home directory, it won't be backup up
|
||||
INCLUSION_PATTERN_FILE=".rs-backup/include"
|
||||
|
||||
# Log verbosity
|
||||
# (0 = quiet, 1 = errors only, 2 = errors and warnings, 3 = info, 4 = debug)
|
||||
LOG_LEVEL=3
|
||||
|
||||
# Send error messages to STDERR
|
||||
PRINT_ERRORS=true
|
||||
|
||||
# Send warnings to STDERR (implies PRINT_ERRORS=true)
|
||||
PRINT_WARNINGS=true
|
||||
|
||||
# Show desktop notifications. Requires libnotify / notify-send.
|
||||
DESKTOP_NOTIFICATIONS=true
|
|
@ -0,0 +1,6 @@
|
|||
[Unit]
|
||||
Description=Start backup via rs-backup-suite
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/rs-backup-run
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Run rs-backup-run every day
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
Persistent=true
|
||||
Unit=rs-backup-run.service
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Script to push backups to a remote rsync backup server.
|
||||
|
@ -40,18 +40,32 @@
|
|||
# Additional internal config
|
||||
###############################################################################
|
||||
|
||||
_VERSION=0.2.1
|
||||
_VERSION=$(rs-version version)
|
||||
_GLOBAL_INCLUSION_PATTERN_FILE="/etc/rs-backup/include-files"
|
||||
_FORCED_INCLUSION_PATTERN_FILE=""
|
||||
_SKIP_HOME_DIRS=false
|
||||
_FALLBACK_LOG_FILE="/var/log/rs-backup.log"
|
||||
_FALLBACK_USER_LOG_FILE="rs-backup.user.log"
|
||||
_FORCED_LOG_FILE=""
|
||||
_QUIET_MODE=false
|
||||
_VERBOSE_MODE=false
|
||||
_SHOW_PROGRESS=false
|
||||
_DRY_RUN=false
|
||||
_FORCE_RUN=false
|
||||
_PRE_HOOK=""
|
||||
_PRE_HOOK_RUN=false
|
||||
_POST_HOOK=""
|
||||
_POST_HOOK_RUN=false
|
||||
_FORCED_POST_HOOK=""
|
||||
_FORCED_POST_HOOK_RUN=false
|
||||
_ERROR_COUNT=0
|
||||
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
_RUNFILE="/var/run/rs-backup/rs-backup-run.pid"
|
||||
else
|
||||
_RUNFILE="${HOME}/.rs-backup/rs-backup-run.pid"
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Function declarations
|
||||
|
@ -61,10 +75,9 @@ _ERROR_COUNT=0
|
|||
#
|
||||
# Usage: print_help
|
||||
print_help() {
|
||||
rs-version headline rs-backup-run
|
||||
rs-version copyright
|
||||
cat << HELP
|
||||
rs-backup-run version ${_VERSION}
|
||||
Copyright (C) 2013-2014 by Janek Bevendorff
|
||||
Web site: http://www.refining-linux.org/
|
||||
|
||||
Push backup to rsync backup server over SSH.
|
||||
|
||||
|
@ -78,31 +91,43 @@ user will be backed up.
|
|||
Usage: $(basename $0) [OPTION]...
|
||||
|
||||
Options:
|
||||
-r, --remote-host=HOST The remote host to connect to
|
||||
--remote-user=NAME The username to use for logging into the remote server
|
||||
(%h will be replaced with the host name of this
|
||||
machine and %u with your username)
|
||||
--push-module=NAME The remote rsync server module
|
||||
--ssh-options=OPTS Additional SSH options (will be merged with the default
|
||||
options set in the rs-backup client-config file)
|
||||
-o, --rsync-options=OPTS Additional options for rsync
|
||||
-n, --dry-run Perform a test run (same as the --dry-run option for
|
||||
rsync). Enable --verbose mode for useful control output
|
||||
-s, --no-home-dirs Don't back up home dirs, only perform global system
|
||||
backup (root only)
|
||||
-i, --include-from=FILE Specify an alternate inclusion pattern file
|
||||
This will override the default setting. If the script
|
||||
is run as root, only the system backup will be
|
||||
performed, no additional home directories will be
|
||||
backed up
|
||||
-l, --log-level=NUM Set log level to NUM (between 0 and 4)
|
||||
--log-file=FILE Set a different log file location
|
||||
-f, --force-run Force rs-backup to run, even if a lock file exists
|
||||
-q, --quiet Don't print any error messages or warnings to the
|
||||
screen (only write to log file)
|
||||
-v, --verbose Print all messages of the current debug level
|
||||
-p, --progress Print file transfer information to the terminal
|
||||
-h, --help Print this help and exit
|
||||
-r, --remote-host=HOST The remote host to connect to
|
||||
--remote-user=NAME The username to use for logging into the remote server
|
||||
(%h will be replaced with the host name of this
|
||||
machine and %u with your username)
|
||||
--push-module=NAME The remote rsync server module
|
||||
--ssh-options=OPTS Additional SSH options (will be merged with the default
|
||||
options set in the rs-backup client-config file)
|
||||
-o, --rsync-options=OPTS Additional options for rsync
|
||||
-n, --dry-run Perform a test run (same as the --dry-run option for
|
||||
rsync). Enable --verbose mode for useful control output
|
||||
-s, --no-home-dirs Don't back up home dirs, only perform global system
|
||||
backup (root only)
|
||||
-i, --include-from=FILE Specify an alternate inclusion pattern file
|
||||
This will override the default setting. If the script
|
||||
is run as root, only the system backup will be
|
||||
performed, no additional home directories will be
|
||||
backed up
|
||||
-l, --log-level=NUM Set log level to NUM (between 0 and 4)
|
||||
--log-file=FILE Log to this file instead of syslog
|
||||
-f, --force-run Force rs-backup to run, even if a lock file exists
|
||||
-q, --quiet Don't print any error messages or warnings to the
|
||||
screen (only write to log file)
|
||||
-v, --verbose Print all messages of the current debug level
|
||||
-p, --progress Print file transfer information to the terminal
|
||||
--pre-hook=CMD Command to be run before the backup. Will only be run
|
||||
once for multi-user / global system backup. The hook
|
||||
command will be executed as the user who started the
|
||||
backup command
|
||||
--post-hook=CMD Similar to --pre-hook, but run after the backup
|
||||
has successfully finished. If an error occurred
|
||||
during the backup, the post hook will not be run.
|
||||
--forced-post-hook=CMD Same as --post-hook, but will always be run, regardless
|
||||
of wether an error occurred or not. Will also be run
|
||||
if the backup was interrupted by SIGINT or SIGTERM.
|
||||
If both --post-hook and --forced-post-hook are specified,
|
||||
--post-hook is run first
|
||||
-h, --help Print this help and exit
|
||||
HELP
|
||||
}
|
||||
|
||||
|
@ -111,43 +136,62 @@ HELP
|
|||
# Usage: write_log <log level> <log message>
|
||||
#
|
||||
write_log() {
|
||||
local log_msg
|
||||
local log_date
|
||||
local log_msg="${2}"
|
||||
local log_date="[$(date)]"
|
||||
local log_dest
|
||||
local use_syslog=false
|
||||
local logger="logger -t $(basename $0)"
|
||||
|
||||
command -v logger > /dev/null 2>&1
|
||||
if [ $? -eq 0 ] && [ "${_FORCED_LOG_FILE}" == "" ]; then
|
||||
use_syslog=true
|
||||
fi
|
||||
|
||||
if [ $1 -gt 0 ] && [ $1 -le $LOG_LEVEL ]; then
|
||||
if $use_syslog; then
|
||||
case $1 in
|
||||
1) $logger -p err "${log_msg}" ;;
|
||||
2) $logger -p warning "${log_msg}" ;;
|
||||
3) $logger -p info "${log_msg}" ;;
|
||||
*) $logger -p debug "${log_msg}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# prepend priority prefixes to message for further logging output
|
||||
case $1 in
|
||||
1) log_msg="ERROR: ${2}" ;;
|
||||
2) log_msg="WARNING: ${2}" ;;
|
||||
3) log_msg="INFO: ${2}" ;;
|
||||
*) log_msg="DEBUG: ${2}" ;;
|
||||
1) log_msg="ERROR: ${log_msg}" ;;
|
||||
2) log_msg="WARNING: ${log_msg}" ;;
|
||||
3) log_msg="INFO: ${log_msg}" ;;
|
||||
*) log_msg="DEBUG: ${log_msg}" ;;
|
||||
esac
|
||||
|
||||
log_date="[$(date)]"
|
||||
full_log_msg="${log_date} ${log_msg}"
|
||||
|
||||
if [ "${_FORCED_LOG_FILE}" != "" ]; then
|
||||
log_dest=${_FORCED_LOG_FILE}
|
||||
elif [ $(id -u) -eq 0 ]; then
|
||||
log_dest=${LOG_FILE}
|
||||
elif [ "${HOME}" != "" ] && [ "${USER_LOG_FILE}" != "" ]; then
|
||||
log_dest=${HOME}/${USER_LOG_FILE}
|
||||
else
|
||||
echo "WARNING: Couldn't determine valid log file location, using '/var/tmp'..." >&2
|
||||
log_dest="/var/tmp/${LOG_FILE}"
|
||||
fi
|
||||
|
||||
if ! test_file_perms "w" "${log_dest}"; then
|
||||
echo "ERROR: Couldn't open log file for writing, redirecting to STDOUT!" >&2
|
||||
echo "${log_date} ${log_msg}" >&1
|
||||
else
|
||||
echo "${log_date} ${log_msg}" >> "${log_dest}"
|
||||
# if no syslog facility exists, go the cumbersome way...
|
||||
if ! $use_syslog || [ "${_FORCED_LOG_FILE}" != "" ]; then
|
||||
if [ "${_FORCED_LOG_FILE}" != "" ]; then
|
||||
log_dest=${_FORCED_LOG_FILE}
|
||||
elif [ $(id -u) -eq 0 ]; then
|
||||
log_dest=${_FALLBACK_LOG_FILE}
|
||||
elif [ "${HOME}" != "" ] && [ "${_FALLBACK_USER_LOG_FILE}" != "" ]; then
|
||||
log_dest=${HOME}/${_FALLBACK_USER_LOG_FILE}
|
||||
else
|
||||
echo -e "\e[1mWARNING: Couldn't determine valid log file location, using '/var/tmp'...\e[0m" >&2
|
||||
log_dest="/var/tmp/$(basename ${LOG_FILE})"
|
||||
fi
|
||||
|
||||
touch "${log_dest}" 2> /dev/null
|
||||
if ! test_file_perms "w" "${log_dest}"; then
|
||||
echo -e "\e[1m\e[91mERROR: Couldn't open log file for writing, redirecting to STDOUT!\e[0m" >&2
|
||||
echo "${log_date} ${log_msg}" >&1
|
||||
else
|
||||
echo "${log_date} ${log_msg}" >> "${log_dest}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# after logging stuff, print it to the screen if we're not in quiet mode
|
||||
if ! $_QUIET_MODE && [ $1 -eq 1 ]; then
|
||||
$_VERBOSE_MODE || $PRINT_ERRORS && echo "${log_msg}" >&2
|
||||
$_VERBOSE_MODE || $PRINT_ERRORS && echo -e "\e[1m\e[91m${log_msg}\e[0m" >&2
|
||||
elif ! $_QUIET_MODE && [ $1 -le 2 ]; then
|
||||
$_VERBOSE_MODE || $PRINT_WARNINGS && echo "${log_msg}" >&2
|
||||
$_VERBOSE_MODE || $PRINT_WARNINGS && echo -e "\e[1m${log_msg}\e[0m" >&2
|
||||
elif ! $_QUIET_MODE && [ $1 -gt 2 ]; then
|
||||
$_VERBOSE_MODE && echo "${log_msg}" >&1
|
||||
fi
|
||||
|
@ -161,6 +205,140 @@ write_log() {
|
|||
}
|
||||
|
||||
|
||||
# Create runfile containing current PID
|
||||
#
|
||||
# Usage: create_runfile
|
||||
#
|
||||
create_runfile() {
|
||||
write_log 4 "Creating runfile (PID=${$}) at '${_RUNFILE}'..."
|
||||
if [ ! -d "$(dirname $_RUNFILE)" ]; then
|
||||
mkdir -p "$(dirname $_RUNFILE)"
|
||||
fi
|
||||
echo $$ > "$_RUNFILE"
|
||||
}
|
||||
|
||||
# Remove created runfile
|
||||
#
|
||||
# Usage: remove_runfile
|
||||
#
|
||||
remove_runfile() {
|
||||
write_log 4 "Removing runfile at '${_RUNFILE}'..."
|
||||
rm -f "$_RUNFILE"
|
||||
# also remove parent directory, but only if empty
|
||||
# redirect error output since --ignore-fail-on-non-empty is not POSIX
|
||||
rmdir "$(dirname $_RUNFILE)" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Run the user-specified pre hook
|
||||
#
|
||||
# Usage: run_pre_hook
|
||||
#
|
||||
run_pre_hook() {
|
||||
if ! $_PRE_HOOK_RUN && [ "" != "$_PRE_HOOK" ]; then
|
||||
$SHELL -c "$_PRE_HOOK"
|
||||
_PRE_HOOK_RUN=true
|
||||
fi
|
||||
}
|
||||
|
||||
# Run the user-specified post hook
|
||||
#
|
||||
# Usage: run_post_hook
|
||||
#
|
||||
run_post_hook() {
|
||||
if ! $_POST_HOOK_RUN && [ "" != "$_POST_HOOK" ]; then
|
||||
$SHELL -c "$_POST_HOOK"
|
||||
_POST_HOOK_RUN=true
|
||||
fi
|
||||
}
|
||||
|
||||
# Run the user-specified forced post hook
|
||||
#
|
||||
# Usage: run_forced_post_hook
|
||||
#
|
||||
run_forced_post_hook() {
|
||||
if ! $_FORCED_POST_HOOK_RUN && [ "" != "$_FORCED_POST_HOOK" ]; then
|
||||
$SHELL -c "$_FORCED_POST_HOOK"
|
||||
_FORCED_POST_HOOK_RUN=true
|
||||
fi
|
||||
}
|
||||
|
||||
# Exit cleanly with given exit code.
|
||||
# Removes any run files and runs the forced post hook.
|
||||
#
|
||||
# Usage clean_exit <exit_code>
|
||||
#
|
||||
clean_exit() {
|
||||
remove_runfile
|
||||
run_forced_post_hook
|
||||
exit $@
|
||||
}
|
||||
|
||||
# Handle script termination by external signals.
|
||||
#
|
||||
# Usage: handle_signals
|
||||
#
|
||||
handle_exit_signal() {
|
||||
write_log 1 "Program terminated upon user request."
|
||||
clean_exit 1
|
||||
}
|
||||
|
||||
# Show a desktop notification using notify-send
|
||||
#
|
||||
# Usage: desktop_notify <type: INFO|WARNING|ERROR> <title> <message>
|
||||
#
|
||||
desktop_notify() {
|
||||
local icon
|
||||
local urgency
|
||||
local user
|
||||
|
||||
if [[ "$(uname -o)" == "Cygwin" ]]; then
|
||||
# not implemented
|
||||
return
|
||||
fi
|
||||
|
||||
command -v notify-send > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
# notify-send not available
|
||||
return
|
||||
fi
|
||||
|
||||
if $_QUIET_MODE || $_DRY_RUN; then
|
||||
return
|
||||
fi
|
||||
|
||||
user=$(who | awk '/:0/ { print $1; exit; }')
|
||||
if [ $(id -u) -ne 0 ] && [[ "$user" != "" ]] && [ $(id -u "$user") -ne $(id -u) ]; then
|
||||
# we're neither root nor the current user on display :0.0,
|
||||
# so don't show any notification
|
||||
return
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
"ERROR")
|
||||
icon="dialog-error.png"
|
||||
urgency="critical"
|
||||
;;
|
||||
"WARNING")
|
||||
icon="dialog-warning.png"
|
||||
urgency="normal"
|
||||
;;
|
||||
"SUCCESS")
|
||||
icon="dialog-ok.png"
|
||||
urgency="low"
|
||||
;;
|
||||
*)
|
||||
icon="dialog-information.png"
|
||||
urgency="low"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$user" != "" ]]; then
|
||||
dbus_pid=$(pgrep -u "$user" dbus-daemon | head -n1)
|
||||
environment=$(xargs --null < /proc/$dbus_pid/environ)
|
||||
sudo -u "$user" $environment notify-send -i "$icon" -u "$urgency" "rs-backup: $2" "$3"
|
||||
fi
|
||||
}
|
||||
|
||||
# Test if a file is readable and/or writeable
|
||||
#
|
||||
# Usage: test_file_perms <mode: r|w|rw> <filename>
|
||||
|
@ -249,7 +427,7 @@ perform_backup() {
|
|||
local msg
|
||||
local backup_cmd
|
||||
local ssh_cmd
|
||||
local rsync_opts="${RSNC_OPTIONS}"
|
||||
local rsync_opts="${RSYNC_OPTIONS}"
|
||||
local exit_code
|
||||
local tee_device="/dev/tty"
|
||||
|
||||
|
@ -288,11 +466,12 @@ perform_backup() {
|
|||
backup_cmd="rsync \
|
||||
--rsh=\"${ssh_cmd}\" \
|
||||
--archive \
|
||||
--acls \
|
||||
--delete \
|
||||
--delete-excluded \
|
||||
--exclude=\"${_RUNFILE}\" \
|
||||
--exclude=\"${LOG_FILE}\" \
|
||||
--exclude=\"${USER_LOG_FILE}\" \
|
||||
--include-from=\"${inclusion_pattern_file}\" \
|
||||
--exclude=\"*\" \
|
||||
${rsync_opts} \
|
||||
/ \
|
||||
\"${destination}\""
|
||||
|
@ -303,18 +482,19 @@ perform_backup() {
|
|||
|
||||
if [ $(id -u) -eq 0 ] && [ "${username}" != "$(id -un)" ]; then
|
||||
write_log 4 "Running backup with privileges of user '${username}' (UID: $(id -u ${username}))..."
|
||||
msg=$(su - "${username}" -c "${backup_cmd}" 2>&1 | tee "${tee_device}")
|
||||
msg=$(su - "${username}" -c "${backup_cmd}" 3>&1 1>&2 2>&3- | tee "${tee_device}")
|
||||
elif [ $(id -u) -ne 0 ] && [ "${username}" != "$(id -un)" ]; then
|
||||
write_log 1 "Cannot run run backup as user '${username}' (UID: $(id -u ${username}), missing root privileges!"
|
||||
return 1
|
||||
else
|
||||
msg=$(sh -c "${backup_cmd}" 2>&1 | tee "${tee_device}")
|
||||
msg=$(sh -c "${backup_cmd}" 3>&1 1>&2 2>&3- | tee "${tee_device}")
|
||||
fi
|
||||
|
||||
exit_code=$?
|
||||
|
||||
if [ ${exit_code} -ne 0 ]; then
|
||||
write_log 1 "Backup failed! Error message: ${msg}"
|
||||
desktop_notify "ERROR" "Backup failed!" "Backup for user '${username}' failed!<br>Please refer to your log files for further information."
|
||||
return ${exit_code}
|
||||
else
|
||||
write_log 3 "Backup finished."
|
||||
|
@ -340,6 +520,7 @@ back_up_system() {
|
|||
write_log 3 "Starting global system backup..."
|
||||
fi
|
||||
perform_backup "${_GLOBAL_INCLUSION_PATTERN_FILE}" "$(get_remote_username root)@${REMOTE_HOST}::${PUSH_MODULE}"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Back up single home directory
|
||||
|
@ -371,6 +552,7 @@ back_up_single_home_dir() {
|
|||
write_log 3 "Starting backup of '${home_dir}'..."
|
||||
fi
|
||||
perform_backup "${home_dir}/${INCLUSION_PATTERN_FILE}" "$(get_remote_username ${username})@${REMOTE_HOST}::${PUSH_MODULE}" "${username}"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Back up all home dirs
|
||||
|
@ -378,14 +560,18 @@ back_up_single_home_dir() {
|
|||
# Usage: back_up_home_dirs
|
||||
#
|
||||
back_up_home_dirs() {
|
||||
local exit_code=0
|
||||
write_log 3 "Starting backup of all home directories..."
|
||||
|
||||
get_processed_passwd_file | while read line; do
|
||||
back_up_single_home_dir "$(echo -n ${line} | cut -d ':' -f 6)" "$(echo -n ${line} | cut -d ':' -f 1)"
|
||||
exit_code=$(($exit_code | $?))
|
||||
done
|
||||
|
||||
return $exit_code
|
||||
}
|
||||
|
||||
# Prase command line args
|
||||
# Parse command line args
|
||||
#
|
||||
# Usage: parse_cmd_args <cmd arg line>
|
||||
#
|
||||
|
@ -400,16 +586,15 @@ parse_cmd_args() {
|
|||
getopt -T > /dev/null
|
||||
if [ $? -ne 4 ]; then
|
||||
write_log 1 "Need GNU getopt for command line parameter parsing!"
|
||||
exit 1;
|
||||
exit 1
|
||||
fi
|
||||
|
||||
args=$(getopt \
|
||||
-s sh \
|
||||
-o "r:o:nsi:l:fqvph" \
|
||||
-l "remote-host:,remote-user:,push-module:,ssh-options:,rsync-options:,dry-run,no-home-dirs,include-from:,log-level:,log-file:,force-run,quiet,verbose,progress,help" \
|
||||
-n "${name}" \
|
||||
-- "${@}")
|
||||
short_opts="r:o:nsi:l:fqvph"
|
||||
long_opts="remote-host:,remote-user:,push-module:,ssh-options:,rsync-options:,"
|
||||
long_opts+="dry-run,no-home-dirs,include-from:,log-level:,log-file:,force-run"
|
||||
long_opts+="quiet,verbose,progress,pre-hook:,post-hook:,forced-post-hook:,help"
|
||||
|
||||
args=$(getopt -s sh -o "$short_opts" -l "$long_opts" -n "${name}" -- "${@}")
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
@ -441,17 +626,17 @@ parse_cmd_args() {
|
|||
shift ;;
|
||||
"-i"|"--include-from")
|
||||
# File must exist and be readable
|
||||
! test_file_perms "r" "${2}" && echo "$name: '${2}' does not exist or is not readable!" >&2 && exit 1
|
||||
! test_file_perms "r" "${2}" && echo "$name: '${2}' does not exist or is not readable!" >&2 && exit 1
|
||||
_FORCED_INCLUSION_PATTERN_FILE=$2
|
||||
_SKIP_HOME_DIRS=true
|
||||
shift 2 ;;
|
||||
"-l"|"--log-level")
|
||||
LOG_LEVEL=$2;
|
||||
LOG_LEVEL="$2"
|
||||
shift 2 ;;
|
||||
"--log-file")
|
||||
# Test if file is writeable
|
||||
! test_file_perms "w" "${2}" && echo "$name: '${2}' is not writeable!" >&2 && exit 1
|
||||
_FORCED_LOG_FILE=$2
|
||||
_FORCED_LOG_FILE="$2"
|
||||
shift 2 ;;
|
||||
"-f"|"--force-run")
|
||||
_FORCE_RUN=true
|
||||
|
@ -465,6 +650,15 @@ parse_cmd_args() {
|
|||
"-p"|"--progress")
|
||||
! $_QUIET_MODE && _SHOW_PROGRESS=true
|
||||
shift ;;
|
||||
"--pre-hook")
|
||||
_PRE_HOOK="$2"
|
||||
shift 2 ;;
|
||||
"--post-hook")
|
||||
_POST_HOOK="$2"
|
||||
shift 2 ;;
|
||||
"--forced-post-hook")
|
||||
_FORCED_POST_HOOK="$2"
|
||||
shift 2 ;;
|
||||
"-h"|"--help")
|
||||
print_help
|
||||
exit ;;
|
||||
|
@ -478,44 +672,68 @@ parse_cmd_args() {
|
|||
###############################################################################
|
||||
# Initialize the actual backup
|
||||
###############################################################################
|
||||
|
||||
# Register exit trap to catch signals and cleanly shut down the script
|
||||
trap handle_exit_signal SIGHUP SIGINT SIGTERM
|
||||
|
||||
parse_cmd_args "$@"
|
||||
|
||||
# Check if a backup is already running
|
||||
if [ -f /tmp/rs-backup.lock ] && ! $_FORCE_RUN; then
|
||||
write_log 1 "Backup lock file exists. Either a backup is already running or it didn't shut down properly last time."
|
||||
write_log 1 "If you're sure no backup is running right now, remove the lock file '/tmp/rs-backup.lock' or use the '--force-run' parameter."
|
||||
if [ -f "$_RUNFILE" ] && ! $_FORCE_RUN; then
|
||||
write_log 1 "rs-backup is already running as PID $(<$_RUNFILE)."
|
||||
write_log 1 "Please finish any running backups before starting a new one."
|
||||
write_log 1 "If you're sure you want to run another backup, either remove the runfile at " \
|
||||
"'$_RUNFILE' or use the '--force-run' parameter."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
write_log 4 "No other backup running, ready to start."
|
||||
if [ ! -f "$_RUNFILE" ]; then
|
||||
write_log 4 "No other backup running, ready to start."
|
||||
elif $_FORCE_RUN; then
|
||||
write_log 4 "Backup already running as PID $(<$_RUNFILE), forcing parallel backup..."
|
||||
fi
|
||||
|
||||
# Create lock file
|
||||
write_log 4 "Creating lock file..."
|
||||
touch /tmp/rs-backup.lock
|
||||
run_pre_hook
|
||||
create_runfile
|
||||
|
||||
# Backup exit code (0 if all backups have finished successfully)
|
||||
_exit_code=$?
|
||||
|
||||
# Check if script has been invoked as root
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
write_log 4 "Running as root, performing global system backup..."
|
||||
desktop_notify "INFO" "Full system backup" "rs-backup is starting a full system backup..."
|
||||
back_up_system
|
||||
_exit_code=$(($_exit_code | $?))
|
||||
|
||||
if ! $_SKIP_HOME_DIRS; then
|
||||
back_up_home_dirs
|
||||
_exit_code=$(($_exit_code | $?))
|
||||
else
|
||||
write_log 3 "Skipping home directory backup as requested."
|
||||
fi
|
||||
else
|
||||
write_log 3 "Running without root privileges, only backing up user home directory..."
|
||||
if [ "${HOME}" != "" ]; then
|
||||
desktop_notify "INFO" "Home directory backup" "rs-backup is starting a home directory backup (unprivileged)..."
|
||||
back_up_single_home_dir "$(realpath ${HOME})" "$(id -nu)"
|
||||
_exit_code=$(($_exit_code | $?))
|
||||
else
|
||||
write_log 2 "Current user has no home directory, skipping."
|
||||
fi
|
||||
fi
|
||||
|
||||
write_log 4 "Removing lock file..."
|
||||
rm /tmp/rs-backup.lock
|
||||
if [ $_exit_code -eq 0 ]; then
|
||||
desktop_notify "SUCCESS" "Backup finished" "Your backup has successfully finished"
|
||||
fi
|
||||
|
||||
remove_runfile
|
||||
|
||||
write_log 4 "Done."
|
||||
|
||||
if [ $_ERROR_COUNT -gt 0 ]; then
|
||||
exit 1
|
||||
clean_exit 1
|
||||
fi
|
||||
|
||||
run_post_hook
|
||||
run_forced_post_hook
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#!/bin/sh
|
||||
##
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Install script for installing server and client script files
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
##
|
||||
|
||||
if [[ "$1" != "all" ]] && [[ "$1" != "client" ]] && [[ "$1" != "server" ]]; then
|
||||
./server/usr/bin/rs-version headline "rs-backup-suite installer"
|
||||
./server/usr/bin/rs-version copyright
|
||||
echo
|
||||
echo "Usage: $(basename $0) [all|server|client]"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ $(id -u) -ne 0 ] && [[ "$(uname -o)" != "Cygwin" ]]; then
|
||||
echo "ERROR: This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Global variables
|
||||
###############################################################################
|
||||
DISTRIBUTION="$(./server/usr/bin/rs-detect-distribution)"
|
||||
COMPONENT="$1"
|
||||
MODE="install"
|
||||
if [[ "$(basename $0)" == "uninstall.sh" ]]; then
|
||||
MODE="uninstall"
|
||||
fi
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Command aliases
|
||||
###############################################################################
|
||||
CP="cp -vr --preserve=mode,timestamps,links"
|
||||
RM="rm -Rvf"
|
||||
MKDIR="mkdir -pv"
|
||||
|
||||
|
||||
# Client component
|
||||
echo "Installing client component..."
|
||||
|
||||
$CP ./client/usr/bin/* /usr/bin/
|
||||
$CP ./server/usr/bin/rs-version /usr/bin/
|
||||
|
||||
if [ -d /etc/systemd/system ]; then
|
||||
echo 'Detected systemd. Run `systemctl enable rs-backup-run.timer` to enable daily backups.'
|
||||
$CP ./client/etc/systemd/system/* /etc/systemd/system
|
||||
fi
|
||||
|
||||
# Do not overwrite existing config
|
||||
if [ ! -e /etc/rs-backup/client-config ]; then
|
||||
$CP ./client/etc/rs-backup /etc/
|
||||
elif ! $(cmp --silent ./client/etc/rs-backup/client-config /etc/rs-backup/client-config); then
|
||||
$CP ./client/etc/rs-backup/client-config /etc/rs-backup/client-config.new
|
||||
fi
|
||||
|
||||
echo "Done."
|
106
install.sh
106
install.sh
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Install script for installing server and client script files
|
||||
|
@ -27,12 +27,14 @@
|
|||
##
|
||||
|
||||
if [[ "$1" != "all" ]] && [[ "$1" != "client" ]] && [[ "$1" != "server" ]]; then
|
||||
./server/usr/bin/rs-version
|
||||
./server/usr/bin/rs-version headline "rs-backup-suite installer"
|
||||
./server/usr/bin/rs-version copyright
|
||||
echo
|
||||
echo "Usage: $(basename $0) [all|server|client]"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ $UID -ne 0 ]; then
|
||||
if [ $(id -u) -ne 0 ] && [[ "$(uname -o)" != "Cygwin" ]]; then
|
||||
echo "ERROR: This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
@ -52,7 +54,7 @@ fi
|
|||
###############################################################################
|
||||
# Command aliases
|
||||
###############################################################################
|
||||
CP="cp -vr --preserve=mode,timestamps,links,xattr"
|
||||
CP="cp -vr --preserve=mode,timestamps,links"
|
||||
RM="rm -Rvf"
|
||||
MKDIR="mkdir -pv"
|
||||
|
||||
|
@ -73,10 +75,6 @@ if [[ $MODE == "install" ]]; then
|
|||
# Do not overwrite existing config
|
||||
if [ ! -e /etc/rs-backup/server-config ]; then
|
||||
$CP ./server/etc/rs-backup /etc/
|
||||
# Correct command paths in rsnapshot config for Synology DSM
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
sed -i "s#/usr/bin/\(cp\|rm\|rsync\)\$#/opt/bin/\1#" /etc/rs-backup/rsnapshot.global.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
|
@ -89,6 +87,7 @@ if [[ $MODE == "install" ]]; then
|
|||
if ! grep -q "/usr/sbin/rs-rotate-cron" /etc/crontab; then
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
cat ./server/etc/crontab_synology >> /etc/crontab
|
||||
synoservicectl --reload crond
|
||||
else
|
||||
cat ./server/etc/crontab >> /etc/crontab
|
||||
fi
|
||||
|
@ -97,8 +96,13 @@ if [[ $MODE == "install" ]]; then
|
|||
echo "ERROR: Could not install cron scripts, please add rotation jobs manually." >&2
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Installing backup directory..."
|
||||
BKP_DIR="$(grep -o '^BACKUP_ROOT=".*"$' /etc/rs-backup/server-config | sed 's#BACKUP_ROOT=\"\(.*\)\"$#\1#')"
|
||||
if [ -e /etc/rs-backup/server-config ]; then
|
||||
BKP_DIR="$(grep -o '^BACKUP_ROOT=".*"$' /etc/rs-backup/server-config | sed 's#BACKUP_ROOT=\"\(.*\)\"$#\1#')"
|
||||
else
|
||||
BKP_DIR="/bkp"
|
||||
fi
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]] && [[ "$BKP_DIR" == "/bkp" ]]; then
|
||||
if readlink -q /var/services/homes > /dev/null; then
|
||||
BKP_DIR="/var/services/homes"
|
||||
|
@ -107,6 +111,7 @@ if [[ $MODE == "install" ]]; then
|
|||
BKP_DIR="/volume1/homes"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Backup directory path will be '$BKP_DIR'."
|
||||
echo -n "Do you want to use this directory? [Y/n] "
|
||||
read answer
|
||||
|
@ -126,20 +131,63 @@ if [[ $MODE == "install" ]]; then
|
|||
$MKDIR "$BKP_DIR"/etc
|
||||
$MKDIR "$BKP_DIR"/lib
|
||||
$MKDIR "$BKP_DIR"/usr/bin
|
||||
$MKDIR "$BKP_DIR"/usr/lib
|
||||
$MKDIR "$BKP_DIR"/usr/share
|
||||
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
$MKDIR "$BKP_DIR"/opt/bin
|
||||
fi
|
||||
[[ "$DISTRIBUTION" != "Synology" ]] && $MKDIR "$BKP_DIR"/usr/lib
|
||||
|
||||
if [[ "$DISTRIBUTION" == "Ubuntu" ]]; then
|
||||
$MKDIR "$BKP_DIR"/usr/share/perl
|
||||
elif [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
$MKDIR "$BKP_DIR"/opt/bin
|
||||
$MKDIR "$BKP_DIR"/opt/lib
|
||||
$MKDIR "$BKP_DIR"/opt/libexec
|
||||
else
|
||||
$MKDIR "$BKP_DIR"/usr/share/perl5
|
||||
fi
|
||||
|
||||
$CP ./server/bkp/etc/* "$BKP_DIR"/etc/
|
||||
# Apply distro-specific configurations
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
# Synology DSM restores default /etc/fstab upon reboot,
|
||||
# so we better put mount commands in /etc/rc
|
||||
if ! grep -q "^# BEGIN: rs-backup-suite" /etc/rc; then
|
||||
tmp_name="/tmp/rs-backup_etc-rc.$RANDOM"
|
||||
fstab_contents="$(cat ./server/etc/fstab_synology | sed "s#::BACKUP_ROOT::#$BKP_DIR#")"
|
||||
tac /etc/rc | sed -e '1!b' -e '/^exit 0$/d' | tac > $tmp_name
|
||||
echo "$fstab_contents" >> $tmp_name
|
||||
echo "exit 0" >> $tmp_name
|
||||
cat $tmp_name > /etc/rc
|
||||
rm $tmp_name
|
||||
fi
|
||||
|
||||
# Add our own syslog template
|
||||
if ! grep -q "^# rs-backup-suite$" /usr/syno/synosdk/texts/enu/events; then
|
||||
cat ./server/etc/events_synology >> /usr/syno/synosdk/texts/enu/events
|
||||
fi
|
||||
else
|
||||
if ! grep -q "^# BEGIN: rs-backup-suite" /etc/fstab; then
|
||||
if [[ "$DISTRIBUTION" == "Ubuntu" ]]; then
|
||||
fstab_local_name="fstab_ubuntu"
|
||||
elif [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
fstab_local_name="fstab_synology"
|
||||
else
|
||||
fstab_local_name="fstab"
|
||||
fi
|
||||
fstab_contents="$(cat ./server/etc/$fstab_local_name | sed "s#::BACKUP_ROOT::#$BKP_DIR#")"
|
||||
echo "$fstab_contents" >> /etc/fstab
|
||||
fi
|
||||
fi
|
||||
|
||||
# Do not overwrite existing config
|
||||
if [ ! -e "$BKP_DIR"/etc/rsnapshot.global.conf ]; then
|
||||
$CP ./server/bkp/etc/* "$BKP_DIR"/etc/
|
||||
# Correct command paths in rsnapshot config for Synology DSM
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
sed -i "s#/usr/bin/\(rsync\|logger\)\$#/opt/bin/\1#" "$BKP_DIR"/etc/rsnapshot.global.conf
|
||||
fi
|
||||
else
|
||||
# Update command paths if upgrading from earlier version
|
||||
echo "Updating cp and rm command paths..."
|
||||
sed -i "s#/opt/bin/cp\$#/usr/bin/cp#" "$BKP_DIR"/etc/rsnapshot.global.conf
|
||||
sed -i "s#/opt/bin/rm\$#/usr/bin/rs-rm#" "$BKP_DIR"/etc/rsnapshot.global.conf
|
||||
fi
|
||||
|
||||
# Create symlink for chroot
|
||||
dir="$(dirname ${BKP_DIR}${BKP_DIR})"
|
||||
|
@ -167,10 +215,18 @@ if [[ $MODE == "install" ]]; then
|
|||
echo "Installing client component..."
|
||||
|
||||
$CP ./client/usr/bin/* /usr/bin/
|
||||
$CP ./server/usr/bin/rs-version /usr/bin/
|
||||
|
||||
if [ -d /etc/systemd/system ]; then
|
||||
echo 'Detected systemd. Run `systemctl enable rs-backup-run.timer` to enable daily backups.'
|
||||
$CP ./client/etc/systemd/system/* /etc/systemd/system
|
||||
fi
|
||||
|
||||
# Do not overwrite existing config
|
||||
if [ ! -e /etc/rs-backup/client-config ]; then
|
||||
$CP ./client/etc/rs-backup /etc/
|
||||
elif ! $(cmp --silent ./client/etc/rs-backup/client-config /etc/rs-backup/client-config); then
|
||||
$CP ./client/etc/rs-backup/client-config /etc/rs-backup/client-config.new
|
||||
fi
|
||||
|
||||
echo "Done."
|
||||
|
@ -204,6 +260,24 @@ elif [[ "$MODE" == "uninstall" ]]; then
|
|||
$RM /usr/sbin/"$(basename $i)"
|
||||
done
|
||||
|
||||
$RM /etc/rs-skel
|
||||
|
||||
[ -e /etc/cron.daily/rs-backup-rotate ] && $RM /etc/cron.daily/rs-backup-rotate
|
||||
[ -e /etc/cron.weekly/rs-backup-rotate ] && $RM /etc/cron.weekly/rs-backup-rotate
|
||||
[ -e /etc/cron.monthly/rs-backup-rotate ] && $RM /etc/cron.monthly/rs-backup-rotate
|
||||
|
||||
if [ -e /etc/crontab ]; then
|
||||
echo "Removing crontab entries..."
|
||||
sed -i '/^@[a-z]\+ \+\/usr\/sbin\/rs-rotate-cron [a-z]\+$/d' /etc/crontab
|
||||
fi
|
||||
|
||||
# Remove fstab entries
|
||||
fstab_name="/etc/fstab"
|
||||
if [[ "$DISTRIBUTION" == "Synology" ]]; then
|
||||
fstab_name="/etc/rc"
|
||||
fi
|
||||
sed -i '/^# BEGIN: rs-backup-suite$/,/^# END: rs-backup-suite$/d' $fstab_name
|
||||
|
||||
echo "Done."
|
||||
|
||||
# Client component
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
config_version 1.2
|
||||
|
||||
cmd_cp /usr/bin/cp
|
||||
cmd_rm /usr/bin/rm
|
||||
cmd_rm /usr/bin/rs-rm
|
||||
cmd_rsync /usr/bin/rsync
|
||||
cmd_logger /usr/bin/logger
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@daily /usr/sbin/rs-rotate-cron daily
|
||||
@weekly /usr/sbin/rs-rotate-cron weekly
|
||||
@monthly /usr/sbin/rs-rotate-cron monthly
|
||||
@daily /usr/sbin/rs-rotate-cron daily
|
||||
@weekly /usr/sbin/rs-rotate-cron weekly
|
||||
@monthly /usr/sbin/rs-rotate-cron monthly
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@daily root /usr/sbin/rs-rotate-cron daily
|
||||
@weekly root /usr/sbin/rs-rotate-cron weekly
|
||||
@monthly root /usr/sbin/rs-rotate-cron monthly
|
||||
0 0 * * * root /usr/sbin/rs-rotate-cron daily
|
||||
0 0 * * 0 root /usr/sbin/rs-rotate-cron weekly
|
||||
0 0 1 * * root /usr/sbin/rs-rotate-cron monthly
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
[99000000]
|
||||
# rs-backup-suite
|
||||
99000001 = "@1"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# BEGIN: rs-backup-suite
|
||||
#/bin ::BACKUP_ROOT::/bin none bind 0 0
|
||||
#/bin ::BACKUP_ROOT::/bin none remount,ro,bind 0 0
|
||||
#/lib ::BACKUP_ROOT::/lib none bind 0 0
|
||||
#/lib ::BACKUP_ROOT::/lib none remount,ro,bind 0 0
|
||||
#/dev ::BACKUP_ROOT::/dev none bind 0 0
|
||||
#/dev ::BACKUP_ROOT::/dev none remount,ro,bind 0 0
|
||||
#/usr/bin ::BACKUP_ROOT::/usr/bin none bind 0 0
|
||||
#/usr/bin ::BACKUP_ROOT::/usr/bin none remount,ro,bind 0 0
|
||||
#/usr/lib ::BACKUP_ROOT::/usr/lib none bind 0 0
|
||||
#/usr/lib ::BACKUP_ROOT::/usr/lib none remount,ro,bind 0 0
|
||||
#/usr/share/perl5 ::BACKUP_ROOT::/usr/share/perl5 none bind 0 0
|
||||
#/usr/share/perl5 ::BACKUP_ROOT::/usr/share/perl5 none remount,ro,bind 0 0
|
||||
# END: rs-backup-suite
|
|
@ -0,0 +1,16 @@
|
|||
# BEGIN: rs-backup-suite
|
||||
#mount -o bind /bin ::BACKUP_ROOT::/bin
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/bin
|
||||
#mount -o bind /lib ::BACKUP_ROOT::/lib
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/lib
|
||||
#mount -o bind /dev ::BACKUP_ROOT::/dev
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/dev
|
||||
#mount -o bind /usr/bin ::BACKUP_ROOT::/usr/bin
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/usr/bin
|
||||
#mount -o bind /opt/bin ::BACKUP_ROOT::/opt/bin
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/opt/bin
|
||||
#mount -o bind /opt/lib ::BACKUP_ROOT::/opt/lib
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/opt/lib
|
||||
#mount -o bind /opt/libexec ::BACKUP_ROOT::/opt/libexec
|
||||
#mount -o remount,ro,bind ::BACKUP_ROOT::/opt/libexec
|
||||
# END: rs-backup-suite
|
|
@ -0,0 +1,14 @@
|
|||
# BEGIN: rs-backup-suite
|
||||
#/bin ::BACKUP_ROOT::/bin none bind 0 0
|
||||
#/bin ::BACKUP_ROOT::/bin none remount,ro,bind 0 0
|
||||
#/lib ::BACKUP_ROOT::/lib none bind 0 0
|
||||
#/lib ::BACKUP_ROOT::/lib none remount,ro,bind 0 0
|
||||
#/dev ::BACKUP_ROOT::/dev none bind 0 0
|
||||
#/dev ::BACKUP_ROOT::/dev none remount,ro,bind 0 0
|
||||
#/usr/bin ::BACKUP_ROOT::/usr/bin none bind 0 0
|
||||
#/usr/bin ::BACKUP_ROOT::/usr/bin none remount,ro,bind 0 0
|
||||
#/usr/lib ::BACKUP_ROOT::/usr/lib none bind 0 0
|
||||
#/usr/lib ::BACKUP_ROOT::/usr/lib none remount,ro,bind 0 0
|
||||
#/usr/share/perl ::BACKUP_ROOT::/usr/share/perl none bind 0 0
|
||||
#/usr/share/perl ::BACKUP_ROOT::/usr/share/perl none remount,ro,bind 0 0
|
||||
# END: rs-backup-suite
|
|
@ -1,4 +1,4 @@
|
|||
include_conf ${BACKUP_ROOT}/etc/rs-backup/rsnapshot.global.conf
|
||||
include_conf ${BACKUP_ROOT}/etc/rsnapshot.global.conf
|
||||
|
||||
snapshot_root ${HOME_DIR}/${FILES_DIR}
|
||||
logfile ${HOME_DIR}/rsnapshot.log
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Base directory for all backups
|
||||
BACKUP_ROOT="/bkp"
|
||||
|
||||
# Backup user group
|
||||
USER_GROUP="backup"
|
||||
|
||||
# Directory containing the actual backup files (relative to BACKUP_ROOT/<user>)
|
||||
FILES_DIR="files"
|
||||
|
||||
# Set default quota for new users
|
||||
SET_QUOTA=false
|
||||
|
||||
# Mount point for backup device that has quota enabled
|
||||
# If nothing is set, quota will be set for all available quota-enabled devices
|
||||
QUOTA_MOUNT_POINT=""
|
||||
|
||||
# Default quota limits. Hard and soft size limit are in bytes (min. 1024)
|
||||
# Numbers may also end with k, M, G or T for magnitudes of 1024
|
||||
#
|
||||
# These numbers are only the defaults. If you want to change them later for
|
||||
# individual users, you can do that with rs-setquota or directly using
|
||||
# the native Linux quota tools (i.e. setquota / edquota)
|
||||
QUOTA_SOFT_LIMIT="350G"
|
||||
QUOTA_HARD_LIMIT="355G"
|
||||
QUOTA_INODE_SOFT_LIMIT="3900k"
|
||||
QUOTA_INODE_HARD_LIMIT="4000k"
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Print out Linux distribution identification.
|
||||
|
@ -31,7 +31,7 @@ command -v lsb_release > /dev/null 2>&1
|
|||
|
||||
if [ $? -eq 0 ]; then
|
||||
lsb_release -is
|
||||
elif [ -e /etc/synoinfo.conf ]; then
|
||||
elif [ -e /etc/synoinfo.conf ] || [ -e /lib/$(ls /lib | grep libsynosdk | head -n1) ]; then
|
||||
echo "Synology"
|
||||
else
|
||||
echo "unknown"
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Log to appropriate syslog facility.
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
##
|
||||
|
||||
if [ "$2" == "" ] ; then
|
||||
echo "Usage: $(basename $0) <info|warn|err> <message>"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$1" != "info" ] && [ "$1" != "warn" ] && [ "$1" != "err" ]; then
|
||||
echo "Invalid log priority '$1'. Choose from <info|warn|err>."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
distribution=$(rs-detect-distribution)
|
||||
if [[ "Synology" == "${distribution}" ]]; then
|
||||
# Use Synology's crappy synologd if we're on DSM
|
||||
/usr/syno/bin/synologset1 sys $1 0x99000001 "[rs-backup-server] $2"
|
||||
else
|
||||
# Any other distribution
|
||||
command -v logger > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
logger -p $1 -t rs-backup-server "$2"
|
||||
else
|
||||
# Log to STDOUT/STDERR if we have no syslog facility
|
||||
prefix="$(date) [rs-backup-server]"
|
||||
if [ "$1" == "err" ]; then
|
||||
echo "$prefix ERROR: $2" >&2
|
||||
elif [ "$1" == "warn" ]; then
|
||||
echo "$prefix WARNING: $2" >&2
|
||||
else
|
||||
echo "$prefix INFO: $2"
|
||||
fi
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Recursively adjust permissions of given file or directory and remove it.
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
##
|
||||
|
||||
if [ "$1" == "" ]; then
|
||||
. rs-version
|
||||
echo "Usage: $(basename $0) [flags] <file>"
|
||||
exit
|
||||
fi
|
||||
|
||||
chmod -R +w "${@: -1}"
|
||||
rm ${@}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Rotate backup revisions. Intended for use with cron.
|
||||
|
@ -36,6 +36,50 @@ if [ "$RSYNC_EXIT_STATUS" == "" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# rsync exit code descriptions found at
|
||||
# <https://lxadm.com/Rsync_exit_codes>
|
||||
msg="unknown code"
|
||||
case $RSYNC_EXIT_STATUS in
|
||||
0) msg="Success" ;;
|
||||
1) msg="Syntax or usage error" ;;
|
||||
2) msg="Protocol incompatibility" ;;
|
||||
3) msg="Errors selecting input/output files, dirs" ;;
|
||||
4) msg="Requested action not supported: an attempt was made to manipulate 64-bit files on a platformi " \
|
||||
"that cannot support them; or an option was specified that is supported by the client and not by the server" ;;
|
||||
5) msg="Error starting client-server protocol" ;;
|
||||
6) msg="Daemon unable to append to log-file" ;;
|
||||
10) msg="Error in socket I/O" ;;
|
||||
11) msg="Error in file I/O" ;;
|
||||
12) msg="Error in rsync protocol data stream" ;;
|
||||
13) msg="Errors with program diagnostics" ;;
|
||||
14) msg="Error in IPC code" ;;
|
||||
20) msg="Received SIGUSR1 or SIGINT" ;;
|
||||
21) msg="Some error returned by waitpid()" ;;
|
||||
22) msg="Error allocating core memory buffers" ;;
|
||||
23) msg="Partial transfer due to error" ;;
|
||||
24) msg="Partial transfer due to vanished source files" ;;
|
||||
25) msg="The --max-delete limit stopped deletions" ;;
|
||||
30) msg="Timeout in data send/receive" ;;
|
||||
35) msg="Timeout waiting for daemon connection" ;;
|
||||
esac
|
||||
|
||||
if [ $RSYNC_EXIT_STATUS -eq 0 ] || [ $RSYNC_EXIT_STATUS -eq 24 ]; then
|
||||
rsnapshot -c "$1" push
|
||||
rs-logger info "Backup for user '$(id -un)' finished with exit code ${RSYNC_EXIT_STATUS} (${msg})"
|
||||
RSNAPSHOT="rsnapshot"
|
||||
if [ -x /usr/bin/rsnapshot ]; then
|
||||
RSNAPSHOT="/usr/bin/rsnapshot"
|
||||
elif [ -x /opt/bin/rsnapshot ]; then
|
||||
RSNAPSHOT="/opt/bin/rsnapshot"
|
||||
fi
|
||||
$RSNAPSHOT -c "$1" push
|
||||
rsnapshot_exit_code=$?
|
||||
if [ $rsnapshot_exit_code -eq 1 ]; then
|
||||
rs-logger err "Backup rotation for level 'push' of user '$(id -un)' failed."
|
||||
elif [ $rsnapshot_exit_code -eq 2 ]; then
|
||||
rs-logger warn "Backup rotation for level 'push' of user '$(id -un)' finished with warnings."
|
||||
else
|
||||
rs-logger info "Backup rotation for level 'push' of user '$(id -un)' finished."
|
||||
fi
|
||||
else
|
||||
rs-logger err "Backup for user '$(id -un)' failed with exit code ${RSYNC_EXIT_STATUS} (${msg})"
|
||||
fi
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Run a restricted command in an SSH session.
|
||||
|
@ -27,13 +27,19 @@
|
|||
##
|
||||
|
||||
home_dir=$1
|
||||
export HOME="${home_dir}/files"
|
||||
cd $HOME
|
||||
|
||||
if [ "${SSH_ORIGINAL_COMMAND}" == "internal-sftp" ] || [ "${SSH_ORIGINAL_COMMAND}" == "/usr/lib/ssh/sftp-server" ]; then
|
||||
cd "${home_dir}/files"
|
||||
exec /usr/lib/ssh/sftp-server -R
|
||||
if $(echo "${SSH_ORIGINAL_COMMAND}" | grep -q "^\(internal-sftp\|.*/sftp-server\)"); then
|
||||
[ -x /usr/lib/openssh/sftp-server ] && exec /usr/lib/openssh/sftp-server -R
|
||||
[ -x /usr/lib/ssh/sftp-server ] && exec /usr/lib/ssh/sftp-server -R
|
||||
[ -x /usr/libexec/sftp-server ] && exec /usr/libexec/sftp-server -R
|
||||
[ -x /opt/libexec/sftp-server ] && exec /opt/libexec/sftp-server -R
|
||||
else
|
||||
source /etc/profile
|
||||
exec `which rsync` --server --daemon --config="${home_dir}/rsync.conf" .
|
||||
rs-logger info "Starting backup for user '$(id -un)'."
|
||||
RSYNC_OPTS="--server --daemon --config='$home_dir/rsync.conf' ."
|
||||
[ -x /usr/bin/rsync ] && exec /usr/bin/rsync $(eval echo $RSYNC_OPTS)
|
||||
[ -x /opt/bin/rsync ] && exec /opt/bin/rsync $(eval echo $RSYNC_OPTS)
|
||||
fi
|
||||
|
||||
echo "Session failed." >&2
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Print out version and copyright information for rs-backup.
|
||||
|
@ -26,7 +26,29 @@
|
|||
# THE SOFTWARE.
|
||||
##
|
||||
|
||||
VERSION="0.2.1"
|
||||
_VERSION="0.3.0"
|
||||
|
||||
echo -e "\e[1mrs-backup-suite\e[0m version ${VERSION}"
|
||||
echo "Copyright (C) 2013-2014 Janek Bevendorff"
|
||||
headline() {
|
||||
if [ "$1" != "" ]; then
|
||||
component="$1"
|
||||
else
|
||||
component="rs-backup-suite"
|
||||
fi
|
||||
echo -e "\e[1m${component}\e[0m version ${_VERSION}"
|
||||
}
|
||||
|
||||
copyright() {
|
||||
echo "Copyright (C) 2013-2016 Janek Bevendorff"
|
||||
echo "Website: https://github.com/Manko10/rs-backup-suite"
|
||||
}
|
||||
|
||||
if [ "$1" == "version" ]; then
|
||||
echo -n "${_VERSION}"
|
||||
elif [ "$1" == "headline" ]; then
|
||||
headline "$2"
|
||||
elif [ "$1" == "copyright" ]; then
|
||||
copyright
|
||||
else
|
||||
headline
|
||||
copyright
|
||||
fi
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Add SSH key to a backup user for passwordless login
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Set up a backup user.
|
||||
|
@ -88,6 +88,10 @@ fi
|
|||
|
||||
rs-update-passwd
|
||||
|
||||
if $SET_QUOTA; then
|
||||
rs-setquota "${local_username}"
|
||||
fi
|
||||
|
||||
# Generate config files from templates
|
||||
rsync_conf="$(cat /etc/rs-backup/rsync.conf.template)"
|
||||
rsnapshot_conf="$(cat /etc/rs-backup/rsnapshot.conf.template)"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Create daily, weekly or monthly snapshots from manual push backups
|
||||
|
@ -43,21 +43,33 @@ for home_dir in "${BACKUP_ROOT}"/*; do
|
|||
config=$(cat "${BACKUP_ROOT}/etc/rsnapshot.global.conf")
|
||||
|
||||
# Get number of preceding increments
|
||||
config=$(echo "${config}" | grep -P '^retain\t')
|
||||
config=$(echo "${config}" | grep -oPz "retain\t+(\w+)\t+(\d+)\nretain\s+${1}\t+" | sed -n 1p)
|
||||
config=$(echo "${config}" | awk '$1 == "retain" && $2 == "'${1}'" { print lastline } { lastline = $0 }')
|
||||
preceding_name=$(echo "${config}" | awk '{ print $2 }')
|
||||
preceding_number=$(($(echo "${config}" | awk ' { print $3 }') - 1))
|
||||
|
||||
# Continue if no proper preceding increment could be found
|
||||
if [ "${preceding_name}" == "" ] ||
|
||||
[ ! -d "${home_dir}/${FILES_DIR}/${preceding_name}.${preceding_number}" ]; then
|
||||
echo "Not rotating ${1}"
|
||||
echo "Not enough preceding increments found, not rotating ${1}"
|
||||
continue
|
||||
fi
|
||||
|
||||
cd "${home_dir}/${FILES_DIR}"
|
||||
owner=$(ls -ld "${home_dir}/${FILES_DIR}" | awk '{ print $3 }')
|
||||
stat_cmd="stat"
|
||||
# avoid using BusyBox stat on Synology
|
||||
if [ -x /opt/bin/stat ]; then
|
||||
stat_cmd="/opt/bin/stat"
|
||||
fi
|
||||
owner=$(${stat_cmd} -c '%U' .)
|
||||
|
||||
su - "${owner}" -c "rsnapshot -c '${home_dir}/rsnapshot.conf' '$1'"
|
||||
rsnapshot_exit_code=$?
|
||||
if [ $rsnapshot_exit_code -eq 1 ]; then
|
||||
rs-logger err "Backup rotation for level '$1' of user '$(id -un)' failed."
|
||||
elif [ $rsnapshot_exit_code -eq 2 ]; then
|
||||
rs-logger warn "Backup rotation for level '$1' of user '$(id -un)' finished with warnings."
|
||||
else
|
||||
rs-logger info "Backup rotation for level '$1' of user '$(id -un)' finished."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Set quota for user
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
##
|
||||
|
||||
if [[ "$1" == "" ]]; then
|
||||
. rs-version
|
||||
echo "Usage: $(basename $0) <username> [<soft limit> <hard limit> <inode soft limit> <inode hard limit>]"
|
||||
echo " Limits are in bytes and can contain the postfixes k, M, G, T."
|
||||
echo " If no limits are specified the default values from the config file will be used."
|
||||
exit
|
||||
fi
|
||||
|
||||
. /etc/rs-backup/server-config
|
||||
|
||||
if ! $QUOTA_MOUNT_POINT; then
|
||||
echo "ERROR: No mount point specified in config files." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$2" == "" ]] && [[ "$QUOTA_HARD_LIMIT" == "" ]]; then
|
||||
echo "ERROR: No limits have been specified. You need to set at least default values in your config file." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Expand postfixes (kilobytes, megabytes, gigabytes, terabytes)
|
||||
# and calculate number
|
||||
expand_postfixes() {
|
||||
local number=$1
|
||||
|
||||
number=$(echo "$number" | sed 's/k$/ * 1024/I')
|
||||
number=$(echo "$number" | sed 's/M$/ * 1024 * 1024/I')
|
||||
number=$(echo "$number" | sed 's/G$/ * 1024 * 1024 * 1024/I')
|
||||
number=$(echo "$number" | sed 's/T$/ * 1024 * 1024 * 1024 * 1024/I')
|
||||
number=$(echo "$number" | sed 's/[^0-9\*]//g')
|
||||
|
||||
number=$(eval "echo $(($number))")
|
||||
echo "$number"
|
||||
}
|
||||
|
||||
block_size=1024
|
||||
quota_file_system="$QUOTA_MOUNT_POINT"
|
||||
if [[ "$quota_file_system" == "" ]]; then
|
||||
quota_file_system="-a"
|
||||
fi
|
||||
|
||||
soft_limit=$(expand_postfixes "$QUOTA_SOFT_LIMIT")
|
||||
hard_limit=$(expand_postfixes "$QUOTA_HARD_LIMIT")
|
||||
inode_soft_limit=$(expand_postfixes "$QUOTA_INODE_SOFT_LIMIT")
|
||||
inode_hard_limit=$(expand_postfixes "$QUOTA_INODE_HARD_LIMIT")
|
||||
|
||||
[[ "$2" != "" ]] && soft_limit=$(expand_postfixes "$2")
|
||||
[[ "$3" != "" ]] && hard_limit=$(expand_postfixes "$3")
|
||||
[[ "$4" != "" ]] && inode_soft_limit=$(expand_postfixes "$4")
|
||||
[[ "$5" != "" ]] && inode_hard_limit=$(expand_postfixes "$5")
|
||||
|
||||
soft_limit=$(($soft_limit / $block_size))
|
||||
hard_limit=$(($hard_limit / $block_size))
|
||||
|
||||
setquota "$1" "$soft_limit" "$hard_limit" "$inode_soft_limit" "$inode_hard_limit" "$quota_file_system"
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Update passwd file in chroot folder based on the contents of /etc/passwd.
|
||||
|
@ -34,5 +34,4 @@ if [ "${BACKUP_ROOT}" == "" ] || [ "$(realpath ${BACKUP_ROOT})" == "/" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
touch "${BACKUP_ROOT}/etc/passwd"
|
||||
cat /etc/passwd | grep "::${BACKUP_ROOT}/[^/:]\+:/bin/[^:]\+$" > "${BACKUP_ROOT}/etc/passwd"
|
||||
grep ":rs-backup user:${BACKUP_ROOT}/[^:]\+:[^:]\+$" /etc/passwd > "${BACKUP_ROOT}/etc/passwd"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
# Copyright (C) 2013-2014 Janek Bevendorff
|
||||
# Copyright (C) 2013-2016 Janek Bevendorff
|
||||
# Website: http://www.refining-linux.org/
|
||||
#
|
||||
# Utility program. Check if disk has been used since last check and spin it down if not.
|
||||
|
|
Loading…
Reference in New Issue