blob: 556e7a460be2994043b67e60271a38e649b9a1df [file] [log] [blame] [raw]
/*
* Copyright (C) 2000-2011, Parallels, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <mntent.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/param.h>
#include "fs.h"
#include "util.h"
#include "logger.h"
#include "vzerror.h"
#include "script.h"
#include "quota.h"
int vps_is_run(vps_handler *h, envid_t veid);
/** Get CT mount status.
*
* @param root CT root.
* @return 1 - CT mounted
* 0 - CT unmounted.
* -1 - error
*/
int vps_is_mounted(const char *root)
{
return vz_fs_is_mounted(root);
}
/** Mount CT.
*
* @param veid CT ID.
* @param fs file system parameters.
* @param dq disk quota parameters.
* @return 0 on success.
*/
int fsmount(envid_t veid, fs_param *fs, dq_param *dq)
{
int ret;
/* Create VE_ROOT mount point if not exist */
if (make_dir(fs->root, 1)) {
logger(-1, 0, "Can't create mount point %s", fs->root);
return VZ_FS_MPOINTCREATE;
}
if ((ret = vps_quotaon(veid, fs->private, dq)))
return ret;
if ((ret = vz_mount(fs, 0)))
vps_quotaoff(veid, dq);
return ret;
}
/** Unmount CT.
*
* @param veid CT ID.
* @param root CT root.
* @return 0 on success.
*/
int fsumount(envid_t veid, const char *root)
{
if (umount(root) != 0) {
logger(-1, errno, "Can't umount %s", root);
return VZ_FS_CANTUMOUNT;
}
if (!quota_ctl(veid, QUOTA_STAT))
return quota_off(veid, 0);
return 0;
}
/** Mount CT and run mount action script if exists.
*
* @param h CT handler.
* @param veid CT ID.
* @param fs file system parameters.
* @param dq disk quota parameters.
* @param skip skip mount action scrips
* @return 0 on success.
*/
int vps_mount(vps_handler *h, envid_t veid, fs_param *fs, dq_param *dq,
skipFlags skip)
{
char buf[PATH_LEN];
int ret, i;
if (check_var(fs->root, "VE_ROOT is not set"))
return VZ_VE_ROOT_NOTSET;
if (check_var(fs->private, "VE_PRIVATE is not set"))
return VZ_VE_PRIVATE_NOTSET;
if (!stat_file(fs->private)) {
logger(-1, 0, "Container private area %s does not exist",
fs->private);
return VZ_FS_NOPRVT;
}
if (vps_is_mounted(fs->root)) {
logger(-1, 0, "Container is already mounted");
return 0;
}
/* Execute pre mount scripts */
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
PRE_MOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing mount script %s",
buf);
fsumount(veid, fs->root);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, PRE_MOUNT_PREFIX);
}
}
if ((ret = fsmount(veid, fs, dq)))
return ret;
/* Execute per-CT & global mount scripts */
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
MOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing mount script %s",
buf);
fsumount(veid, fs->root);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, MOUNT_PREFIX);
}
}
logger(0, 0, "Container is mounted");
return 0;
}
static int umount_submounts(const char *root)
{
FILE *fp;
struct mntent *mnt;
int len;
char path[MAXPATHLEN + 1];
if (realpath(root, path) == NULL) {
logger(-1, errno, "realpath(%s) failed", root);
return -1;
}
if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
logger(-1, errno, "Unable to open /proc/mounts");
return -1;
}
strcat(path, "/"); /* skip base mountpoint */
len = strlen(path);
while ((mnt = getmntent(fp)) != NULL) {
if (strncmp(path, mnt->mnt_dir, len) == 0) {
if (umount(mnt->mnt_dir))
logger(-1, errno, "Cannot umount %s",
mnt->mnt_dir);
}
}
endmntent(fp);
return 0;
}
/** Unmount CT and run unmount action script if exists.
*
* @param h CT handler.
* @param veid CT ID.
* @param root CT root.
* @param skip skip unmount action scrips
* @return 0 on success.
*/
int vps_umount(vps_handler *h, envid_t veid, const char *root, skipFlags skip)
{
char buf[PATH_LEN];
int ret, i;
if (!vps_is_mounted(root)) {
logger(-1, 0, "CT is not mounted");
return VZ_FS_NOT_MOUNTED;
}
if (vps_is_run(h, veid)) {
logger(-1, 0, "Container is running -- stop it first");
return 0;
}
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, UMOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing umount script %s",
buf);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
UMOUNT_PREFIX);
}
}
umount_submounts(root);
if (!(ret = fsumount(veid, root)))
logger(0, 0, "Container is unmounted");
if (!(skip & SKIP_ACTION_SCRIPT)) {
snprintf(buf, sizeof(buf), "%s%d.%s", VPS_CONF_DIR,
veid, POST_UMOUNT_PREFIX);
for (i = 0; i < 2; i++) {
if (run_pre_script(veid, buf)) {
logger(-1, 0, "Error executing umount script %s",
buf);
return VZ_ACTIONSCRIPT_ERROR;
}
snprintf(buf, sizeof(buf), "%svps.%s", VPS_CONF_DIR,
POST_UMOUNT_PREFIX);
}
}
return ret;
}
int vps_set_fs(fs_param *g_fs, fs_param *fs)
{
if (fs->noatime != YES)
return 0;
if (check_var(g_fs->root, "VE_ROOT is not set"))
return VZ_VE_ROOT_NOTSET;
if (check_var(g_fs->private, "VE_PRIVATE is not set"))
return VZ_VE_PRIVATE_NOTSET;
if (!vps_is_mounted(g_fs->root)) {
logger(-1, 0, "Container is not mounted");
return VZ_FS_NOT_MOUNTED;
}
g_fs->noatime = fs->noatime;
return vz_mount(g_fs, 1);
}