Files
xen/tools/libxc/xc_suspend.c
T
Ian Jackson fe1a6bc754 libxc: Fix buffer length for get_suspend_file
Declaring a formal parameter to have an array type doesn't result in
the parameter actually having an array type.  The type is "adjusted"
to a pointer.  (C99 6.9.1(7), 6.7.5.3.)

So the use of sizeof in xc_suspend.c:get_suspend_file was wrong.
Instead, use the #define.  Also get rid of the array size, as it is
misleading.

Newer versions of gcc warn about the erroneous code:
  xc_suspend.c:39:25: error: argument to 'sizeof' in 'snprintf' call
    is the same expression as the destination; did you mean to provide
    an explicit length? [-Werror=sizeof-pointer-memaccess]

Reported-By: Julien Grall <julien.grall@linaro.org>
Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Julien Grall <julien.grall@linaro.org>

--
v2: Actually change the declaration of buf.
2014-03-18 13:56:47 +00:00

202 lines
5.0 KiB
C

/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <unistd.h>
#include <fcntl.h>
#include "xc_private.h"
#include "xenguest.h"
#define SUSPEND_LOCK_FILE "/var/run/xen/suspend-evtchn-%d.lock"
/*
* locking
*/
#define ERR(x) do{ \
ERROR("Can't " #x " lock file for suspend event channel %s: %s\n", \
suspend_file, strerror(errno)); \
goto err; \
}while(0)
#define SUSPEND_FILE_BUFLEN (sizeof(SUSPEND_LOCK_FILE) + 10)
static void get_suspend_file(char buf[], int domid)
{
snprintf(buf, SUSPEND_FILE_BUFLEN, SUSPEND_LOCK_FILE, domid);
}
static int lock_suspend_event(xc_interface *xch, int domid, int *lockfd)
{
int fd = -1, r;
char suspend_file[SUSPEND_FILE_BUFLEN];
struct stat ours, theirs;
struct flock fl;
get_suspend_file(suspend_file, domid);
*lockfd = -1;
for (;;) {
if (fd >= 0)
close (fd);
fd = open(suspend_file, O_CREAT | O_RDWR, 0600);
if (fd < 0)
ERR("create");
r = fcntl(fd, F_SETFD, FD_CLOEXEC);
if (r)
ERR("fcntl F_SETFD FD_CLOEXEC");
memset(&fl, 0, sizeof(fl));
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_len = 1;
r = fcntl(fd, F_SETLK, &fl);
if (r)
ERR("fcntl F_SETLK");
r = fstat(fd, &ours);
if (r)
ERR("fstat");
r = stat(suspend_file, &theirs);
if (r) {
if (errno == ENOENT)
/* try again */
continue;
ERR("stat");
}
if (ours.st_ino != theirs.st_ino)
/* someone else must have removed it while we were locking it */
continue;
break;
}
*lockfd = fd;
return 0;
err:
if (fd >= 0)
close(fd);
return -1;
}
static int unlock_suspend_event(xc_interface *xch, int domid, int *lockfd)
{
int r;
char suspend_file[SUSPEND_FILE_BUFLEN];
if (*lockfd < 0)
return 0;
get_suspend_file(suspend_file, domid);
r = unlink(suspend_file);
if (r)
ERR("unlink");
r = close(*lockfd);
*lockfd = -1;
if (r)
ERR("close");
err:
if (*lockfd >= 0)
close(*lockfd);
return -1;
}
int xc_await_suspend(xc_interface *xch, xc_evtchn *xce, int suspend_evtchn)
{
int rc;
do {
rc = xc_evtchn_pending(xce);
if (rc < 0) {
ERROR("error polling suspend notification channel: %d", rc);
return -1;
}
} while (rc != suspend_evtchn);
/* harmless for one-off suspend */
if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
ERROR("failed to unmask suspend notification channel: %d", rc);
return 0;
}
/* Internal callers are allowed to call this with suspend_evtchn<0
* but *lockfd>0. */
int xc_suspend_evtchn_release(xc_interface *xch, xc_evtchn *xce,
int domid, int suspend_evtchn, int *lockfd)
{
if (suspend_evtchn >= 0)
xc_evtchn_unbind(xce, suspend_evtchn);
return unlock_suspend_event(xch, domid, lockfd);
}
int xc_suspend_evtchn_init_sane(xc_interface *xch, xc_evtchn *xce,
int domid, int port, int *lockfd)
{
int rc, suspend_evtchn = -1;
if (lock_suspend_event(xch, domid, lockfd)) {
errno = EINVAL;
goto cleanup;
}
suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
if (suspend_evtchn < 0) {
ERROR("failed to bind suspend event channel: %d", suspend_evtchn);
goto cleanup;
}
rc = xc_domain_subscribe_for_suspend(xch, domid, port);
if (rc < 0) {
ERROR("failed to subscribe to domain: %d", rc);
goto cleanup;
}
return suspend_evtchn;
cleanup:
xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn, lockfd);
return -1;
}
int xc_suspend_evtchn_init_exclusive(xc_interface *xch, xc_evtchn *xce,
int domid, int port, int *lockfd)
{
int suspend_evtchn;
suspend_evtchn = xc_suspend_evtchn_init_sane(xch, xce, domid, port, lockfd);
if (suspend_evtchn < 0)
return suspend_evtchn;
/* event channel is pending immediately after binding */
xc_await_suspend(xch, xce, suspend_evtchn);
return suspend_evtchn;
}