diff --git a/setup/start/sudoers b/setup/start/sudoers index 8d6a47ba5..4c3d1d953 100644 --- a/setup/start/sudoers +++ b/setup/start/sudoers @@ -1,8 +1,8 @@ # sudo logging breaks journalctl output with very long urls (systemd bug) Defaults !syslog -Defaults!/home/yellowtent/box/src/scripts/rmvolume.sh env_keep="HOME BOX_ENV" -yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/rmvolume.sh +Defaults!/home/yellowtent/box/src/scripts/clearvolume.sh env_keep="HOME BOX_ENV" +yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/clearvolume.sh Defaults!/home/yellowtent/box/src/scripts/mvvolume.sh env_keep="HOME BOX_ENV" yellowtent ALL=(root) NOPASSWD: /home/yellowtent/box/src/scripts/mvvolume.sh diff --git a/src/addons.js b/src/addons.js index 8c119c16d..809da343c 100644 --- a/src/addons.js +++ b/src/addons.js @@ -110,7 +110,7 @@ var KNOWN_ADDONS = { clear: NOOP, }, localstorage: { - setup: setupLocalStorage, // docker creates the directory for us + setup: setupLocalStorage, teardown: teardownLocalStorage, backup: NOOP, // no backup because it's already inside app data restore: NOOP, @@ -745,7 +745,7 @@ function clearLocalStorage(app, options, callback) { debugApp(app, 'clearLocalStorage'); - docker.clearVolume(app, `${app.id}-localstorage`, callback); + docker.clearVolume(app, `${app.id}-localstorage`, { removeDirectory: false }, callback); } function teardownLocalStorage(app, options, callback) { @@ -756,7 +756,7 @@ function teardownLocalStorage(app, options, callback) { debugApp(app, 'teardownLocalStorage'); async.series([ - docker.clearVolume.bind(null, app, `${app.id}-localstorage`), + docker.clearVolume.bind(null, app, `${app.id}-localstorage`, { removeDirectory: true }), docker.removeVolume.bind(null, app, `${app.id}-localstorage`) ], callback); } diff --git a/src/apps.js b/src/apps.js index 3e9b90fa4..6a1285049 100644 --- a/src/apps.js +++ b/src/apps.js @@ -303,7 +303,7 @@ function validateEnv(env) { } function validateDataDir(dataDir) { - if (!dataDir) return new AppsError(AppsError.BAD_FIELD, 'dataDir cannot be empty'); + if (dataDir === '') return null; // revert back to default dataDir if (path.resolve(dataDir) !== dataDir) return new AppsError(AppsError.BAD_FIELD, 'dataDir must be an absolute path'); @@ -773,7 +773,7 @@ function configure(appId, data, user, auditSource, callback) { if (error) return callback(error); } - if ('dataDir' in data) { + if ('dataDir' in data && data.dataDir !== app.dataDir) { error = validateDataDir(data.dataDir); if (error) return callback(error); values.dataDir = data.dataDir; diff --git a/src/apptask.js b/src/apptask.js index abceacd9e..de2377bec 100644 --- a/src/apptask.js +++ b/src/apptask.js @@ -175,6 +175,7 @@ function deleteAppDir(app, options, callback) { if (!entries) return callback(`Error listing ${resolvedAppDataDir}: ${safe.error.message}`); // remove only files. directories inside app dir are currently volumes managed by the addons + // we cannot delete those dirs anyway because of perms entries.forEach(function (entry) { let stat = safe.fs.statSync(path.join(resolvedAppDataDir, entry)); if (stat && !stat.isDirectory()) safe.fs.unlinkSync(path.join(resolvedAppDataDir, entry)); diff --git a/src/docker.js b/src/docker.js index 12f9781c0..6f32a3e6c 100644 --- a/src/docker.js +++ b/src/docker.js @@ -61,7 +61,7 @@ var addons = require('./addons.js'), util = require('util'), _ = require('underscore'); -const RMVOLUME_CMD = path.join(__dirname, 'scripts/rmvolume.sh'), +const CLEARVOLUME_CMD = path.join(__dirname, 'scripts/clearvolume.sh'), MKDIRVOLUME_CMD = path.join(__dirname, 'scripts/mkdirvolume.sh'); function DockerError(reason, errorOrMessage) { @@ -553,9 +553,10 @@ function createVolume(app, name, volumeDataDir, callback) { }); } -function clearVolume(app, name, callback) { +function clearVolume(app, name, options, callback) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof name, 'string'); + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); let docker = exports.connection; @@ -565,7 +566,7 @@ function clearVolume(app, name, callback) { if (error) return callback(error); const volumeDataDir = v.Options.device; - shell.sudo('removeVolume', [ RMVOLUME_CMD, volumeDataDir ], {}, callback); + shell.sudo('clearVolume', [ CLEARVOLUME_CMD, options.removeDirectory ? 'rmdir' : 'clear', volumeDataDir ], {}, callback); }); } diff --git a/src/scripts/rmvolume.sh b/src/scripts/clearvolume.sh similarity index 50% rename from src/scripts/rmvolume.sh rename to src/scripts/clearvolume.sh index f83aebeda..085fb408f 100755 --- a/src/scripts/rmvolume.sh +++ b/src/scripts/clearvolume.sh @@ -17,15 +17,24 @@ if [[ "$1" == "--check" ]]; then exit 0 fi -volume_dir="$1" +cmd="$1" +volume_dir="$2" if [[ "${BOX_ENV}" == "test" ]]; then # be careful not to nuke some random directory when testing [[ "${volume_dir}" != *"./cloudron_test/"* ]] && exit 1 fi -# this removes hidden files -find "${volume_dir}" -maxdepth 1 -mindepth 1 -exec rm -rf '{}' \; -# volume could be a mount point that cannot be deleted -rmdir "${volume_dir}" || true +if [[ -d "${volume_dir}" ]]; then + # this removes hidden files + find "${volume_dir}" -maxdepth 1 -mindepth 1 -exec rm -rf '{}' \; +fi +if [[ "${cmd}" == "clear" ]]; then + mkdir -p "${volume_dir}" + # set it up so that we can restore here as normal user + chown $SUDO_USER:$SUDO_USER "${volume_dir}" +else + # this make not succeed if volume is a mount point + rmdir "${volume_dir}" || true +fi \ No newline at end of file diff --git a/src/scripts/mvvolume.sh b/src/scripts/mvvolume.sh index 9152a91d6..a484303da 100755 --- a/src/scripts/mvvolume.sh +++ b/src/scripts/mvvolume.sh @@ -30,6 +30,6 @@ fi # the find logic is so that move to a subdir works (and we also move hidden files) find "${source_dir}" -maxdepth 1 -mindepth 1 -not -wholename "${target_dir}" -exec cp -ar '{}' "${target_dir}" \; find "${source_dir}" -maxdepth 1 -mindepth 1 -not -wholename "${target_dir}" -exec rm -rf '{}' \; -# this will fail if target is a subdir +# this will fail if target is a subdir or if source is a mountpoint rmdir "${source_dir}" || true diff --git a/src/test/checkInstall b/src/test/checkInstall index 4f7e548e4..3bb199ea4 100755 --- a/src/test/checkInstall +++ b/src/test/checkInstall @@ -9,7 +9,7 @@ readonly TEST_IMAGE="cloudron/test:25.2.0" sudo -k || sudo --reset-timestamp # checks if all scripts are sudo access -scripts=("${SOURCE_DIR}/src/scripts/rmvolume.sh" \ +scripts=("${SOURCE_DIR}/src/scripts/clearvolume.sh" \ "${SOURCE_DIR}/src/scripts/mvvolume.sh" \ "${SOURCE_DIR}/src/scripts/mkdirvolume.sh" \ "${SOURCE_DIR}/src/scripts/rmaddondir.sh" \