util.c 74.6 KB
Newer Older
1 2 3
/*
 * utils.c: common, generic utility functions
 *
4
 * Copyright (C) 2006-2012 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * Copyright (C) 2006 Daniel P. Berrange
 * Copyright (C) 2006, 2007 Binary Karma
 * Copyright (C) 2006 Shuveb Hussain
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
 */

27
#include <config.h>
28

29 30
#include <stdio.h>
#include <stdarg.h>
31
#include <stdlib.h>
32 33 34
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
C
Cole Robinson 已提交
35
#include <poll.h>
36
#include <sys/stat.h>
37
#include <sys/types.h>
38
#include <sys/ioctl.h>
E
Eric Blake 已提交
39
#include <sys/wait.h>
40
#if HAVE_MMAP
41
# include <sys/mman.h>
42
#endif
43
#include <string.h>
44
#include <signal.h>
E
Eric Blake 已提交
45
#include <termios.h>
46 47
#include <pty.h>

48 49 50
#if HAVE_LIBDEVMAPPER_H
# include <libdevmapper.h>
#endif
51

52
#ifdef HAVE_PATHS_H
53
# include <paths.h>
54
#endif
55
#include <netdb.h>
56
#ifdef HAVE_GETPWUID_R
57 58
# include <pwd.h>
# include <grp.h>
59
#endif
60
#if HAVE_CAPNG
61
# include <cap-ng.h>
62
#endif
63
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
64
# include <mntent.h>
65
#endif
66

67
#ifdef WIN32
68 69 70
# ifdef HAVE_WINSOCK2_H
#  include <winsock2.h>
# endif
71 72 73 74
# include <windows.h>
# include <shlobj.h>
#endif

75
#include "c-ctype.h"
76
#include "dirname.h"
77
#include "virterror_internal.h"
78
#include "logging.h"
79
#include "buf.h"
D
Daniel Veillard 已提交
80
#include "util.h"
L
Laine Stump 已提交
81
#include "storage_file.h"
82
#include "memory.h"
83
#include "threads.h"
E
Eric Blake 已提交
84
#include "verify.h"
E
Eric Blake 已提交
85
#include "virfile.h"
86
#include "command.h"
87
#include "nonblocking.h"
88
#include "passfd.h"
89

90 91 92 93
#ifndef NSIG
# define NSIG 32
#endif

94 95
verify(sizeof(gid_t) <= sizeof(unsigned int) &&
       sizeof(uid_t) <= sizeof(unsigned int));
E
Eric Blake 已提交
96

97
#define VIR_FROM_THIS VIR_FROM_NONE
98

99
#define virUtilError(code, ...)                                            \
100
        virReportErrorHelper(VIR_FROM_NONE, code, __FILE__,                \
101
                             __FUNCTION__, __LINE__, __VA_ARGS__)
102

D
Daniel P. Berrange 已提交
103
/* Like read(), but restarts after EINTR */
E
Eric Blake 已提交
104 105
ssize_t
saferead(int fd, void *buf, size_t count)
D
Daniel P. Berrange 已提交
106
{
E
Eric Blake 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119 120
    size_t nread = 0;
    while (count > 0) {
        ssize_t r = read(fd, buf, count);
        if (r < 0 && errno == EINTR)
            continue;
        if (r < 0)
            return r;
        if (r == 0)
            return nread;
        buf = (char *)buf + r;
        count -= r;
        nread += r;
    }
    return nread;
D
Daniel P. Berrange 已提交
121 122 123
}

/* Like write(), but restarts after EINTR */
E
Eric Blake 已提交
124 125
ssize_t
safewrite(int fd, const void *buf, size_t count)
D
Daniel P. Berrange 已提交
126
{
E
Eric Blake 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    size_t nwritten = 0;
    while (count > 0) {
        ssize_t r = write(fd, buf, count);

        if (r < 0 && errno == EINTR)
            continue;
        if (r < 0)
            return r;
        if (r == 0)
            return nwritten;
        buf = (const char *)buf + r;
        count -= r;
        nwritten += r;
    }
    return nwritten;
D
Daniel P. Berrange 已提交
142 143
}

144
#ifdef HAVE_POSIX_FALLOCATE
E
Eric Blake 已提交
145
int safezero(int fd, off_t offset, off_t len)
146
{
147 148 149 150 151
    int ret = posix_fallocate(fd, offset, len);
    if (ret == 0)
        return 0;
    errno = ret;
    return -1;
152 153 154
}
#else

155
# ifdef HAVE_MMAP
E
Eric Blake 已提交
156
int safezero(int fd, off_t offset, off_t len)
157 158 159 160 161 162 163
{
    int r;
    char *buf;

    /* memset wants the mmap'ed file to be present on disk so create a
     * sparse file
     */
D
Daniel P. Berrange 已提交
164
    r = ftruncate(fd, offset + len);
165
    if (r < 0)
J
Jiri Denemark 已提交
166
        return -1;
167 168 169

    buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
    if (buf == MAP_FAILED)
J
Jiri Denemark 已提交
170
        return -1;
171 172 173 174 175 176 177

    memset(buf, 0, len);
    munmap(buf, len);

    return 0;
}

178
# else /* HAVE_MMAP */
179

E
Eric Blake 已提交
180
int safezero(int fd, off_t offset, off_t len)
181 182 183 184 185
{
    int r;
    char *buf;
    unsigned long long remain, bytes;

D
Daniel P. Berrange 已提交
186
    if (lseek(fd, offset, SEEK_SET) < 0)
J
Jiri Denemark 已提交
187
        return -1;
D
Daniel P. Berrange 已提交
188

189 190 191 192 193
    /* Split up the write in small chunks so as not to allocate lots of RAM */
    remain = len;
    bytes = 1024 * 1024;

    r = VIR_ALLOC_N(buf, bytes);
J
Jiri Denemark 已提交
194 195 196 197
    if (r < 0) {
        errno = ENOMEM;
        return -1;
    }
198 199 200 201 202

    while (remain) {
        if (bytes > remain)
            bytes = remain;

J
Jiri Denemark 已提交
203
        r = safewrite(fd, buf, bytes);
204 205
        if (r < 0) {
            VIR_FREE(buf);
J
Jiri Denemark 已提交
206
            return -1;
207 208 209 210 211 212 213 214
        }

        /* safewrite() guarantees all data will be written */
        remain -= bytes;
    }
    VIR_FREE(buf);
    return 0;
}
215
# endif /* HAVE_MMAP */
216 217
#endif /* HAVE_POSIX_FALLOCATE */

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
int virFileStripSuffix(char *str,
                       const char *suffix)
{
    int len = strlen(str);
    int suffixlen = strlen(suffix);

    if (len < suffixlen)
        return 0;

    if (!STREQ(str + len - suffixlen, suffix))
        return 0;

    str[len-suffixlen] = '\0';

    return 1;
}

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
char *
virArgvToString(const char *const *argv)
{
    int len, i;
    char *ret, *p;

    for (len = 1, i = 0; argv[i]; i++)
        len += strlen(argv[i]) + 1;

    if (VIR_ALLOC_N(ret, len) < 0)
        return NULL;
    p = ret;

    for (i = 0; argv[i]; i++) {
        if (i != 0)
            *(p++) = ' ';

        strcpy(p, argv[i]);
        p += strlen(argv[i]);
    }

    *p = '\0';

    return ret;
}

261
#ifndef WIN32
262

E
Eric Blake 已提交
263
int virSetInherit(int fd, bool inherit) {
264 265
    int fflags;
    if ((fflags = fcntl(fd, F_GETFD)) < 0)
266
        return -1;
E
Eric Blake 已提交
267
    if (inherit)
268
        fflags &= ~FD_CLOEXEC;
E
Eric Blake 已提交
269
    else
270 271
        fflags |= FD_CLOEXEC;
    if ((fcntl(fd, F_SETFD, fflags)) < 0)
272 273 274 275
        return -1;
    return 0;
}

276
#else /* WIN32 */
277

E
Eric Blake 已提交
278
int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED)
279 280 281
{
    return -1;
}
282

283 284 285 286
#endif /* WIN32 */

int virSetBlocking(int fd, bool blocking) {
    return set_nonblocking_flag (fd, !blocking);
J
Jim Meyering 已提交
287 288
}

289 290
int virSetNonBlock(int fd) {
    return virSetBlocking(fd, false);
291 292
}

293
int virSetCloseExec(int fd)
294
{
295
    return virSetInherit(fd, false);
296 297
}

298 299 300 301 302 303 304 305 306 307
int
virPipeReadUntilEOF(int outfd, int errfd,
                    char **outbuf, char **errbuf) {

    struct pollfd fds[2];
    int i;
    int finished[2];

    fds[0].fd = outfd;
    fds[0].events = POLLIN;
308
    fds[0].revents = 0;
309 310 311
    finished[0] = 0;
    fds[1].fd = errfd;
    fds[1].events = POLLIN;
312
    fds[1].revents = 0;
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    finished[1] = 0;

    while(!(finished[0] && finished[1])) {

        if (poll(fds, ARRAY_CARDINALITY(fds), -1) < 0) {
            if ((errno == EAGAIN) || (errno == EINTR))
                continue;
            goto pollerr;
        }

        for (i = 0; i < ARRAY_CARDINALITY(fds); ++i) {
            char data[1024], **buf;
            int got, size;

            if (!(fds[i].revents))
                continue;
            else if (fds[i].revents & POLLHUP)
                finished[i] = 1;

            if (!(fds[i].revents & POLLIN)) {
                if (fds[i].revents & POLLHUP)
                    continue;

                virUtilError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("Unknown poll response."));
                goto error;
            }

            got = read(fds[i].fd, data, sizeof(data));

343 344 345
            if (got == sizeof(data))
                finished[i] = 0;

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
            if (got == 0) {
                finished[i] = 1;
                continue;
            }
            if (got < 0) {
                if (errno == EINTR)
                    continue;
                if (errno == EAGAIN)
                    break;
                goto pollerr;
            }

            buf = ((fds[i].fd == outfd) ? outbuf : errbuf);
            size = (*buf ? strlen(*buf) : 0);
            if (VIR_REALLOC_N(*buf, size+got+1) < 0) {
                virReportOOMError();
                goto error;
            }
            memmove(*buf+size, data, got);
            (*buf)[size+got] = '\0';
        }
        continue;

    pollerr:
        virReportSystemError(errno,
                             "%s", _("poll error"));
        goto error;
    }

    return 0;

error:
    VIR_FREE(*outbuf);
    VIR_FREE(*errbuf);
    return -1;
}

383 384 385 386
/* Like gnulib's fread_file, but read no more than the specified maximum
   number of bytes.  If the length of the input is <= max_len, and
   upon error while reading that data, it works just like fread_file.  */
static char *
387
saferead_lim (int fd, size_t max_len, size_t *length)
388 389 390 391 392 393 394
{
    char *buf = NULL;
    size_t alloc = 0;
    size_t size = 0;
    int save_errno;

    for (;;) {
395 396
        int count;
        int requested;
397 398 399 400 401 402

        if (size + BUFSIZ + 1 > alloc) {
            alloc += alloc / 2;
            if (alloc < size + BUFSIZ + 1)
                alloc = size + BUFSIZ + 1;

403
            if (VIR_REALLOC_N(buf, alloc) < 0) {
404 405 406 407 408 409 410 411
                save_errno = errno;
                break;
            }
        }

        /* Ensure that (size + requested <= max_len); */
        requested = MIN (size < max_len ? max_len - size : 0,
                         alloc - size - 1);
412
        count = saferead (fd, buf + size, requested);
413 414 415 416
        size += count;

        if (count != requested || requested == 0) {
            save_errno = errno;
417
            if (count < 0)
418 419 420 421 422 423 424
                break;
            buf[size] = '\0';
            *length = size;
            return buf;
        }
    }

425
    VIR_FREE(buf);
426 427 428
    errno = save_errno;
    return NULL;
}
429

430
/* A wrapper around saferead_lim that maps a failure due to
431
   exceeding the maximum size limitation to EOVERFLOW.  */
432 433
int
virFileReadLimFD(int fd, int maxlen, char **buf)
434
{
435
    size_t len;
436 437 438 439 440 441 442
    char *s;

    if (maxlen <= 0) {
        errno = EINVAL;
        return -1;
    }
    s = saferead_lim (fd, maxlen+1, &len);
443 444 445 446 447 448 449 450 451 452 453 454 455
    if (s == NULL)
        return -1;
    if (len > maxlen || (int)len != len) {
        VIR_FREE(s);
        /* There was at least one byte more than MAXLEN.
           Set errno accordingly. */
        errno = EOVERFLOW;
        return -1;
    }
    *buf = s;
    return len;
}

D
Daniel P. Berrange 已提交
456
int virFileReadAll(const char *path, int maxlen, char **buf)
457
{
458 459
    int fd = open(path, O_RDONLY);
    if (fd < 0) {
460
        virReportSystemError(errno, _("Failed to open file '%s'"), path);
461
        return -1;
462 463
    }

464
    int len = virFileReadLimFD(fd, maxlen, buf);
465
    VIR_FORCE_CLOSE(fd);
466
    if (len < 0) {
467
        virReportSystemError(errno, _("Failed to read file '%s'"), path);
468
        return -1;
469 470
    }

471
    return len;
472 473
}

474 475
/* Truncate @path and write @str to it.  If @mode is 0, ensure that
   @path exists; otherwise, use @mode if @path must be created.
M
Mark McLoughlin 已提交
476 477
   Return 0 for success, nonzero for failure.
   Be careful to preserve any errno value upon failure. */
478
int virFileWriteStr(const char *path, const char *str, mode_t mode)
M
Mark McLoughlin 已提交
479 480 481
{
    int fd;

482 483 484 485 486
    if (mode)
        fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode);
    else
        fd = open(path, O_WRONLY|O_TRUNC);
    if (fd == -1)
M
Mark McLoughlin 已提交
487 488 489
        return -1;

    if (safewrite(fd, str, strlen(str)) < 0) {
490
        VIR_FORCE_CLOSE(fd);
M
Mark McLoughlin 已提交
491 492 493 494
        return -1;
    }

    /* Use errno from failed close only if there was no write error.  */
495
    if (VIR_CLOSE(fd) != 0)
M
Mark McLoughlin 已提交
496 497 498 499 500
        return -1;

    return 0;
}

501 502 503 504 505 506 507 508 509
int virFileMatchesNameSuffix(const char *file,
                             const char *name,
                             const char *suffix)
{
    int filelen = strlen(file);
    int namelen = strlen(name);
    int suffixlen = strlen(suffix);

    if (filelen == (namelen + suffixlen) &&
510 511
        STREQLEN(file, name, namelen) &&
        STREQLEN(file + namelen, suffix, suffixlen))
512 513 514 515 516 517 518 519 520 521 522 523 524 525
        return 1;
    else
        return 0;
}

int virFileHasSuffix(const char *str,
                     const char *suffix)
{
    int len = strlen(str);
    int suffixlen = strlen(suffix);

    if (len < suffixlen)
        return 0;

526
    return STRCASEEQ(str + len - suffixlen, suffix);
527 528
}

529
#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
J
Jim Meyering 已提交
530 531
  ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
   && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
532

J
Jim Meyering 已提交
533 534
/* Return nonzero if checkLink and checkDest
   refer to the same file.  Otherwise, return 0.  */
535 536 537
int virFileLinkPointsTo(const char *checkLink,
                        const char *checkDest)
{
J
Jim Meyering 已提交
538 539
    struct stat src_sb;
    struct stat dest_sb;
540

J
Jim Meyering 已提交
541 542 543
    return (stat (checkLink, &src_sb) == 0
            && stat (checkDest, &dest_sb) == 0
            && SAME_INODE (src_sb, dest_sb));
544 545
}

D
Daniel P. Berrange 已提交
546 547


548 549 550 551
static int
virFileResolveLinkHelper(const char *linkpath,
                         bool intermediatePaths,
                         char **resultpath)
D
Daniel P. Berrange 已提交
552 553 554 555 556
{
    struct stat st;

    *resultpath = NULL;

557 558 559
    /* We don't need the full canonicalization of intermediate
     * directories, if linkpath is absolute and the basename is
     * already a non-symlink.  */
560
    if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) {
561
        if (lstat(linkpath, &st) < 0)
562
            return -1;
563 564 565 566 567 568

        if (!S_ISLNK(st.st_mode)) {
            if (!(*resultpath = strdup(linkpath)))
                return -1;
            return 0;
        }
D
Daniel P. Berrange 已提交
569 570
    }

571
    *resultpath = canonicalize_file_name(linkpath);
D
Daniel P. Berrange 已提交
572

573
    return *resultpath == NULL ? -1 : 0;
D
Daniel P. Berrange 已提交
574 575
}

576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
/*
 * Attempt to resolve a symbolic link, returning an
 * absolute path where only the last component is guaranteed
 * not to be a symlink.
 *
 * Return 0 if path was not a symbolic, or the link was
 * resolved. Return -1 with errno set upon error
 */
int virFileResolveLink(const char *linkpath,
                       char **resultpath)
{
    return virFileResolveLinkHelper(linkpath, false, resultpath);
}

/*
 * Attempt to resolve a symbolic link, returning an
 * absolute path where every component is guaranteed
 * not to be a symlink.
 *
 * Return 0 if path was not a symbolic, or the link was
 * resolved. Return -1 with errno set upon error
 */
int virFileResolveAllLinks(const char *linkpath,
                           char **resultpath)
{
    return virFileResolveLinkHelper(linkpath, true, resultpath);
}
603 604 605 606 607 608 609 610 611 612 613 614 615

/*
 * Check whether the given file is a link.
 * Returns 1 in case of the file being a link, 0 in case it is not
 * a link and the negative errno in all other cases.
 */
int virFileIsLink(const char *linkpath)
{
    struct stat st;

    if (lstat(linkpath, &st) < 0)
        return -errno;

616
    return S_ISLNK(st.st_mode) != 0;
617 618 619
}


620
/*
621
 * Finds a requested executable file in the PATH env. e.g.:
622 623 624 625 626 627
 * "kvm-img" will return "/usr/bin/kvm-img"
 *
 * You must free the result
 */
char *virFindFileInPath(const char *file)
{
628
    char *path = NULL;
629
    char *pathiter;
630
    char *pathseg;
631
    char *fullpath = NULL;
632

633 634 635 636
    if (file == NULL)
        return NULL;

    /* if we are passed an absolute path (starting with /), return a
637
     * copy of that path, after validating that it is executable
638
     */
639 640
    if (IS_ABSOLUTE_FILE_NAME(file)) {
        if (virFileIsExecutable(file))
641 642 643 644 645
            return strdup(file);
        else
            return NULL;
    }

646 647 648 649 650 651 652 653 654
    /* If we are passed an anchored path (containing a /), then there
     * is no path search - it must exist in the current directory
     */
    if (strchr(file, '/')) {
        if (virFileIsExecutable(file))
            ignore_value(virFileAbsPath(file, &path));
        return path;
    }

655
    /* copy PATH env so we can tweak it */
656 657
    path = getenv("PATH");

658
    if (path == NULL || (path = strdup(path)) == NULL)
C
Chris Lalancette 已提交
659
        return NULL;
D
Daniel P. Berrange 已提交
660

661 662 663
    /* for each path segment, append the file to search for and test for
     * it. return it if found.
     */
664 665 666 667 668 669
    pathiter = path;
    while ((pathseg = strsep(&pathiter, ":")) != NULL) {
        if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 ||
            virFileIsExecutable(fullpath))
            break;
        VIR_FREE(fullpath);
670 671
    }

672 673
    VIR_FREE(path);
    return fullpath;
674
}
675

676 677 678 679 680 681
bool virFileIsDir(const char *path)
{
    struct stat s;
    return (stat (path, &s) == 0) && S_ISDIR (s.st_mode);
}

682
bool virFileExists(const char *path)
683
{
684 685 686
    return access(path, F_OK) == 0;
}

687 688
/* Check that a file is regular and has executable bits.  If false is
 * returned, errno is valid.
689 690 691 692 693 694 695 696 697
 *
 * Note: In the presence of ACLs, this may return true for a file that
 * would actually fail with EACCES for a given user, or false for a
 * file that the user could actually execute, but setups with ACLs
 * that weird are unusual. */
bool
virFileIsExecutable(const char *file)
{
    struct stat sb;
698

699 700
    /* We would also want to check faccessat if we cared about ACLs,
     * but we don't.  */
701 702 703 704 705 706
    if (stat(file, &sb) < 0)
        return false;
    if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0)
        return true;
    errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES;
    return false;
707 708
}

709
#ifndef WIN32
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/* Check that a file is accessible under certain
 * user & gid.
 * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK.
 * see 'man access' for more details.
 * Returns 0 on success, -1 on fail with errno set.
 */
int
virFileAccessibleAs(const char *path, int mode,
                    uid_t uid, gid_t gid)
{
    pid_t pid = 0;
    int status, ret = 0;
    int forkRet = 0;

    if (uid == getuid() &&
        gid == getgid())
        return access(path, mode);

    forkRet = virFork(&pid);

    if (pid < 0) {
        return -1;
    }

    if (pid) { /* parent */
        if (virPidWait(pid, &status) < 0) {
            /* virPidWait() already
             * reported error */
                return -1;
        }

741 742 743 744 745
        if (!WIFEXITED(status)) {
            errno = EINTR;
            return -1;
        }

746
        if (status) {
747
            errno = WEXITSTATUS(status);
748 749 750 751
            return -1;
        }

        return 0;
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
    }

    /* child.
     * Return positive value here. Parent
     * will change it to negative one. */

    if (forkRet < 0) {
        ret = errno;
        goto childerror;
    }

    if (virSetUIDGID(uid, gid) < 0) {
        ret = errno;
        goto childerror;
    }

    if (access(path, mode) < 0)
        ret = errno;

childerror:
    if ((ret & 0xFF) != ret) {
        VIR_WARN("unable to pass desired return value %d", ret);
        ret = 0xFF;
    }

    _exit(ret);
}

L
Laine Stump 已提交
780 781 782 783
/* virFileOpenForceOwnerMode() - an internal utility function called
 * only by virFileOpenAs().  Sets the owner and mode of the file
 * opened as "fd" if it's not correct AND the flags say it should be
 * forced. */
784
static int
L
Laine Stump 已提交
785 786
virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode,
                          uid_t uid, gid_t gid, unsigned int flags)
787
{
788 789 790
    int ret = 0;
    struct stat st;

L
Laine Stump 已提交
791 792
    if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE)))
        return 0;
793

L
Laine Stump 已提交
794
    if (fstat(fd, &st) == -1) {
795
        ret = -errno;
796
        virReportSystemError(errno, _("stat of '%s' failed"), path);
L
Laine Stump 已提交
797
        return ret;
798
    }
L
Laine Stump 已提交
799 800 801 802 803 804
    /* NB: uid:gid are never "-1" (default) at this point - the caller
     * has always changed -1 to the value of get[gu]id().
    */
    if ((flags & VIR_FILE_OPEN_FORCE_OWNER) &&
        ((st.st_uid != uid) || (st.st_gid != gid)) &&
        (fchown(fd, uid, gid) < 0)) {
805
        ret = -errno;
L
Laine Stump 已提交
806 807 808 809 810
        virReportSystemError(errno,
                             _("cannot chown '%s' to (%u, %u)"),
                             path, (unsigned int) uid,
                             (unsigned int) gid);
        return ret;
811
    }
L
Laine Stump 已提交
812 813 814 815
    if ((flags & VIR_FILE_OPEN_FORCE_MODE) &&
        ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
         (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) &&
        (fchmod(fd, mode) < 0)) {
816
        ret = -errno;
817
        virReportSystemError(errno,
818 819
                             _("cannot set mode of '%s' to %04o"),
                             path, mode);
L
Laine Stump 已提交
820
        return ret;
821 822 823 824
    }
    return ret;
}

L
Laine Stump 已提交
825 826 827 828 829 830 831 832
/* virFileOpenForked() - an internal utility function called only by
 * virFileOpenAs(). It forks, then the child does setuid+setgid to
 * given uid:gid and attempts to open the file, while the parent just
 * calls recvfd to get the open fd back from the child. returns the
 * fd, or -errno if there is an error. */
static int
virFileOpenForked(const char *path, int openflags, mode_t mode,
                  uid_t uid, gid_t gid, unsigned int flags)
833
{
834 835
    pid_t pid;
    int waitret, status, ret = 0;
836 837 838
    int fd = -1;
    int pair[2] = { -1, -1 };
    int forkRet;
839 840

    /* parent is running as root, but caller requested that the
L
Laine Stump 已提交
841
     * file be opened as some other user and/or group). The
842 843 844
     * following dance avoids problems caused by root-squashing
     * NFS servers. */

845 846 847 848 849 850
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
        ret = -errno;
        virReportSystemError(errno,
                             _("failed to create socket needed for '%s'"),
                             path);
        return ret;
851 852 853
    }

    forkRet = virFork(&pid);
L
Laine Stump 已提交
854 855
    if (pid < 0)
        return -errno;
856

L
Laine Stump 已提交
857
    if (pid == 0) {
858

L
Laine Stump 已提交
859
        /* child */
860

L
Laine Stump 已提交
861 862 863 864 865 866 867 868
        VIR_FORCE_CLOSE(pair[0]); /* preserves errno */
        if (forkRet < 0) {
            /* error encountered and logged in virFork() after the fork. */
            ret = -errno;
            goto childerror;
        }

        /* set desired uid/gid, then attempt to create the file */
869

L
Laine Stump 已提交
870
        if (virSetUIDGID(uid, gid) < 0) {
871
            ret = -errno;
L
Laine Stump 已提交
872
            goto childerror;
873
        }
874

L
Laine Stump 已提交
875
        if ((fd = open(path, openflags, mode)) < 0) {
876
            ret = -errno;
877
            virReportSystemError(errno,
L
Laine Stump 已提交
878
                                 _("child process failed to create file '%s'"),
879
                                 path);
L
Laine Stump 已提交
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
            goto childerror;
        }

        /* File is successfully open. Set permissions if requested. */
        ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
        if (ret < 0)
            goto childerror;

        do {
            ret = sendfd(pair[1], fd);
        } while (ret < 0 && errno == EINTR);

        if (ret < 0) {
            ret = -errno;
            virReportSystemError(errno, "%s",
                                 _("child process failed to send fd to parent"));
            goto childerror;
897
        }
L
Laine Stump 已提交
898 899 900 901 902 903 904 905

    childerror:
        /* ret tracks -errno on failure, but exit value must be positive.
         * If the child exits with EACCES, then the parent tries again.  */
        /* XXX This makes assumptions about errno being < 255, which is
         * not true on Hurd.  */
        VIR_FORCE_CLOSE(pair[1]);
        if (ret < 0) {
906
            VIR_FORCE_CLOSE(fd);
907
        }
L
Laine Stump 已提交
908 909 910 911 912 913
        ret = -ret;
        if ((ret & 0xff) != ret) {
            VIR_WARN("unable to pass desired return value %d", ret);
            ret = 0xff;
        }
        _exit(ret);
914 915
    }

L
Laine Stump 已提交
916
    /* parent */
917

L
Laine Stump 已提交
918
    VIR_FORCE_CLOSE(pair[1]);
919

L
Laine Stump 已提交
920 921 922 923 924 925
    do {
        fd = recvfd(pair[0], 0);
    } while (fd < 0 && errno == EINTR);
    VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */

    if (fd < 0 && errno != EACCES) {
926
        ret = -errno;
L
Laine Stump 已提交
927 928
        while (waitpid(pid, NULL, 0) == -1 && errno == EINTR);
        return ret;
929
    }
930

L
Laine Stump 已提交
931 932 933 934
    /* wait for child to complete, and retrieve its exit code */
    while ((waitret = waitpid(pid, &status, 0) == -1)
           && (errno == EINTR));
    if (waitret == -1) {
935
        ret = -errno;
L
Laine Stump 已提交
936 937 938 939 940
        virReportSystemError(errno,
                             _("failed to wait for child creating '%s'"),
                             path);
        VIR_FORCE_CLOSE(fd);
        return ret;
941
    }
L
Laine Stump 已提交
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
    if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES ||
        fd == -1) {
        /* fall back to the simpler method, which works better in
         * some cases */
        VIR_FORCE_CLOSE(fd);
        if (flags & VIR_FILE_OPEN_NOFORK) {
            /* If we had already tried opening w/o fork+setuid and
             * failed, no sense trying again. Just set return the
             * original errno that we got at that time (by
             * definition, always either EACCES or EPERM - EACCES
             * is close enough).
             */
            return -EACCES;
        }
        if ((fd = open(path, openflags, mode)) < 0)
            return -errno;
        ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
        if (ret < 0) {
            VIR_FORCE_CLOSE(fd);
            return ret;
        }
    }
    return fd;
}
966

L
Laine Stump 已提交
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
/**
 * virFileOpenAs:
 * @path: file to open or create
 * @openflags: flags to pass to open
 * @mode: mode to use on creation or when forcing permissions
 * @uid: uid that should own file on creation
 * @gid: gid that should own file
 * @flags: bit-wise or of VIR_FILE_OPEN_* flags
 *
 * Open @path, and return an fd to the open file. @openflags contains
 * the flags normally passed to open(2), while those in @flags are
 * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try
 * opening the file while executing with the current uid:gid
 * (i.e. don't fork+setuid+setgid before the call to open()).  If
 * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while
 * the effective user id is @uid (by forking a child process); this
 * allows one to bypass root-squashing NFS issues; NOFORK is always
 * tried before FORK (the absence of both flags is treated identically
 * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes
 * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by
 * uid:gid before returning (even if it already existed with a
 * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE,
 * ensure it has those permissions before returning (again, even if
 * the file already existed with different permissions).  The return
 * value (if non-negative) is the file descriptor, left open.  Returns
 * -errno on failure.  */
int
virFileOpenAs(const char *path, int openflags, mode_t mode,
              uid_t uid, gid_t gid, unsigned int flags)
{
    int ret = 0, fd = -1;
998

L
Laine Stump 已提交
999 1000
    /* allow using -1 to mean "current value" */
    if (uid == (uid_t) -1)
O
Osier Yang 已提交
1001
        uid = getuid();
L
Laine Stump 已提交
1002
    if (gid == (gid_t) -1)
O
Osier Yang 已提交
1003
        gid = getgid();
1004

L
Laine Stump 已提交
1005 1006 1007
    /* treat absence of both flags as presence of both for simpler
     * calling. */
    if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK)))
O
Osier Yang 已提交
1008
        flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK;
L
Laine Stump 已提交
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020

    if ((flags & VIR_FILE_OPEN_NOFORK)
        || (getuid() != 0)
        || ((uid == 0) && (gid == 0))) {

        if ((fd = open(path, openflags, mode)) < 0) {
            ret = -errno;
        } else {
            ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags);
            if (ret < 0)
                goto error;
        }
1021
    }
1022

L
Laine Stump 已提交
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    /* If we either 1) didn't try opening as current user at all, or
     * 2) failed, and errno/virStorageFileIsSharedFS indicate we might
     * be successful if we try as a different uid, then try doing
     * fork+setuid+setgid before opening.
     */
    if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) {

        if (ret < 0) {
            /* An open(2) that failed due to insufficient permissions
             * could return one or the other of these depending on OS
             * version and circumstances. Any other errno indicates a
             * problem that couldn't be remedied by fork+setuid
             * anyway. */
            if (ret != -EACCES && ret != -EPERM)
                goto error;

            /* On Linux we can also verify the FS-type of the
             * directory.  (this is a NOP on other platforms). */
            switch (virStorageFileIsSharedFS(path)) {
            case 1:
                /* it was on a network share, so we'll re-try */
                break;
            case -1:
                /* failure detecting fstype */
1047
                virReportSystemError(errno, _("couldn't determine fs type "
L
Laine Stump 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
                                              "of mount containing '%s'"), path);
                goto error;
            case 0:
            default:
                /* file isn't on a recognized network FS */
                goto error;
            }
        }

        /* passed all prerequisites - retry the open w/fork+setuid */
        if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) {
            ret = fd;
            fd = -1;
            goto error;
        }
    }

    /* File is successfully opened */

    return fd;

error:
    if (fd < 0) {
        /* whoever failed the open last has already set ret = -errno */
        virReportSystemError(-ret, openflags & O_CREAT
                             ? _("failed to create file '%s'")
                             : _("failed to open file '%s'"),
                             path);
    } else {
        /* some other failure after the open succeeded */
        VIR_FORCE_CLOSE(fd);
    }
    return ret;
}

/* return -errno on failure, or 0 on success */
static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid,
                              unsigned int flags) {
    int ret = 0;
    struct stat st;

    if ((mkdir(path, mode) < 0)
        && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) {
        ret = -errno;
        virReportSystemError(errno, _("failed to create directory '%s'"),
                             path);
        goto error;
1095
    }
1096

L
Laine Stump 已提交
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
    if (stat(path, &st) == -1) {
        ret = -errno;
        virReportSystemError(errno, _("stat of '%s' failed"), path);
        goto error;
    }
    if (((st.st_uid != uid) || (st.st_gid != gid))
        && (chown(path, uid, gid) < 0)) {
        ret = -errno;
        virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"),
                             path, (unsigned int) uid, (unsigned int) gid);
        goto error;
    }
    if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
        && (chmod(path, mode) < 0)) {
        ret = -errno;
        virReportSystemError(errno,
                             _("cannot set mode of '%s' to %04o"),
                             path, mode);
        goto error;
    }
error:
    return ret;
1119 1120
}

1121
/* return -errno on failure, or 0 on success */
1122 1123 1124 1125 1126 1127 1128
int virDirCreate(const char *path, mode_t mode,
                 uid_t uid, gid_t gid, unsigned int flags) {
    struct stat st;
    pid_t pid;
    int waitret;
    int status, ret = 0;

1129
    if ((!(flags & VIR_DIR_CREATE_AS_UID))
1130 1131
        || (getuid() != 0)
        || ((uid == 0) && (gid == 0))
1132 1133
        || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) {
        return virDirCreateNoFork(path, mode, uid, gid, flags);
1134 1135
    }

1136
    int forkRet = virFork(&pid);
1137 1138

    if (pid < 0) {
1139
        ret = -errno;
1140 1141 1142 1143 1144 1145 1146
        return ret;
    }

    if (pid) { /* parent */
        /* wait for child to complete, and retrieve its exit code */
        while ((waitret = waitpid(pid, &status, 0) == -1)  && (errno == EINTR));
        if (waitret == -1) {
1147
            ret = -errno;
1148
            virReportSystemError(errno,
1149 1150 1151 1152
                                 _("failed to wait for child creating '%s'"),
                                 path);
            goto parenterror;
        }
1153
        if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) {
1154 1155
            /* fall back to the simpler method, which works better in
             * some cases */
1156
            return virDirCreateNoFork(path, mode, uid, gid, flags);
1157 1158 1159 1160 1161
        }
parenterror:
        return ret;
    }

1162 1163 1164 1165 1166 1167 1168 1169
    /* child */

    if (forkRet < 0) {
        /* error encountered and logged in virFork() after the fork. */
        goto childerror;
    }

    /* set desired uid/gid, then attempt to create the directory */
1170

1171
    if (virSetUIDGID(uid, gid) < 0) {
1172
        ret = -errno;
1173 1174 1175
        goto childerror;
    }
    if (mkdir(path, mode) < 0) {
1176 1177
        ret = -errno;
        if (ret != -EACCES) {
1178
            /* in case of EACCES, the parent will retry */
1179
            virReportSystemError(errno, _("child failed to create directory '%s'"),
1180 1181 1182 1183
                                 path);
        }
        goto childerror;
    }
1184 1185 1186
    /* check if group was set properly by creating after
     * setgid. If not, try doing it with chown */
    if (stat(path, &st) == -1) {
1187
        ret = -errno;
1188 1189 1190 1191 1192
        virReportSystemError(errno,
                             _("stat of '%s' failed"), path);
        goto childerror;
    }
    if ((st.st_gid != gid) && (chown(path, -1, gid) < 0)) {
1193
        ret = -errno;
1194 1195
        virReportSystemError(errno,
                             _("cannot chown '%s' to group %u"),
E
Eric Blake 已提交
1196
                             path, (unsigned int) gid);
1197 1198 1199 1200 1201 1202 1203 1204 1205
        goto childerror;
    }
    if ((flags & VIR_DIR_CREATE_FORCE_PERMS)
        && chmod(path, mode) < 0) {
        virReportSystemError(errno,
                             _("cannot set mode of '%s' to %04o"),
                             path, mode);
        goto childerror;
    }
1206 1207 1208 1209
childerror:
    _exit(ret);
}

1210
#else /* WIN32 */
1211

1212 1213 1214 1215
int
virFileAccessibleAs(const char *path,
                    int mode,
                    uid_t uid ATTRIBUTE_UNUSED,
1216
                    gid_t gid ATTRIBUTE_UNUSED)
1217 1218 1219 1220 1221 1222 1223
{

    VIR_WARN("Ignoring uid/gid due to WIN32");

    return access(path, mode);
}

1224
/* return -errno on failure, or 0 on success */
1225 1226 1227 1228 1229
int virFileOpenAs(const char *path ATTRIBUTE_UNUSED,
                  int openflags ATTRIBUTE_UNUSED,
                  mode_t mode ATTRIBUTE_UNUSED,
                  uid_t uid ATTRIBUTE_UNUSED,
                  gid_t gid ATTRIBUTE_UNUSED,
1230
                  unsigned int flags_unused ATTRIBUTE_UNUSED)
1231 1232
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
1233
                 "%s", _("virFileOpenAs is not implemented for WIN32"));
1234

1235
    return -ENOSYS;
1236 1237
}

1238 1239 1240 1241
int virDirCreate(const char *path ATTRIBUTE_UNUSED,
                 mode_t mode ATTRIBUTE_UNUSED,
                 uid_t uid ATTRIBUTE_UNUSED,
                 gid_t gid ATTRIBUTE_UNUSED,
1242
                 unsigned int flags_unused ATTRIBUTE_UNUSED)
1243 1244 1245 1246
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virDirCreate is not implemented for WIN32"));

1247
    return -ENOSYS;
1248
}
1249
#endif /* WIN32 */
1250

1251 1252
static int virFileMakePathHelper(char *path)
{
1253
    struct stat st;
1254
    char *p;
1255

1256 1257 1258 1259 1260 1261 1262 1263 1264
    if (stat(path, &st) >= 0) {
        if (S_ISDIR(st.st_mode))
            return 0;

        errno = ENOTDIR;
        return -1;
    }

    if (errno != ENOENT)
1265
        return -1;
1266

1267 1268 1269 1270
    if ((p = strrchr(path, '/')) == NULL) {
        errno = EINVAL;
        return -1;
    }
1271

1272
    if (p != path) {
1273
        *p = '\0';
1274 1275 1276 1277

        if (virFileMakePathHelper(path) < 0)
            return -1;

1278
        *p = '/';
1279
    }
1280

1281 1282 1283
    if (mkdir(path, 0777) < 0 && errno != EEXIST)
        return -1;

1284 1285 1286
    return 0;
}

1287 1288 1289 1290 1291 1292
/**
 * Creates the given directory with mode 0777 if it's not already existing.
 *
 * Returns 0 on success, or -1 if an error occurred (in which case, errno
 * is set appropriately).
 */
1293 1294
int virFileMakePath(const char *path)
{
1295
    int ret = -1;
1296
    char *tmp;
1297

1298
    if ((tmp = strdup(path)) == NULL)
1299
        goto cleanup;
1300

1301
    ret = virFileMakePathHelper(tmp);
1302 1303

cleanup:
1304
    VIR_FREE(tmp);
1305
    return ret;
1306 1307
}

1308
/* Build up a fully qualified path for a config file to be
1309
 * associated with a persistent guest or network */
1310 1311
char *
virFileBuildPath(const char *dir, const char *name, const char *ext)
1312
{
1313
    char *path;
1314

1315 1316
    if (ext == NULL) {
        if (virAsprintf(&path, "%s/%s", dir, name) < 0) {
1317
            virReportOOMError();
1318 1319 1320 1321
            return NULL;
        }
    } else {
        if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) {
1322
            virReportOOMError();
1323 1324 1325 1326 1327
            return NULL;
        }
    }

    return path;
1328 1329
}

1330 1331 1332
/* Open a non-blocking master side of a pty.  If ttyName is not NULL,
 * then populate it with the name of the slave.  If rawmode is set,
 * also put the master side into raw mode before returning.  */
1333
#ifndef WIN32
1334 1335 1336 1337
int virFileOpenTty(int *ttymaster,
                   char **ttyName,
                   int rawmode)
{
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
    /* XXX A word of caution - on some platforms (Solaris and HP-UX),
     * additional ioctl() calls are needs after opening the slave
     * before it will cause isatty() to return true.  Should we make
     * virFileOpenTty also return the opened slave fd, so the caller
     * doesn't have to worry about that mess?  */
    int ret = -1;
    int slave = -1;
    char *name = NULL;

    /* Unfortunately, we can't use the name argument of openpty, since
     * there is no guarantee on how large the buffer has to be.
     * Likewise, we can't use the termios argument: we have to use
     * read-modify-write since there is no portable way to initialize
     * a struct termios without use of tcgetattr.  */
    if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0)
        return -1;
1354

1355 1356 1357 1358 1359
    /* What a shame that openpty cannot atomically set FD_CLOEXEC, but
     * that using posix_openpt/grantpt/unlockpt/ptsname is not
     * thread-safe, and that ptsname_r is not portable.  */
    if (virSetNonBlock(*ttymaster) < 0 ||
        virSetCloseExec(*ttymaster) < 0)
1360 1361
        goto cleanup;

1362 1363
    /* While Linux supports tcgetattr on either the master or the
     * slave, Solaris requires it to be on the slave.  */
1364 1365
    if (rawmode) {
        struct termios ttyAttr;
1366
        if (tcgetattr(slave, &ttyAttr) < 0)
1367 1368 1369 1370
            goto cleanup;

        cfmakeraw(&ttyAttr);

1371
        if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0)
1372 1373 1374
            goto cleanup;
    }

1375 1376 1377 1378
    /* ttyname_r on the slave is required by POSIX, while ptsname_r on
     * the master is a glibc extension, and the POSIX ptsname is not
     * thread-safe.  Since openpty gave us both descriptors, guess
     * which way we will determine the name?  :)  */
1379
    if (ttyName) {
1380 1381 1382 1383 1384 1385
        /* Initial guess of 64 is generally sufficient; rely on ERANGE
         * to tell us if we need to grow.  */
        size_t len = 64;
        int rc;

        if (VIR_ALLOC_N(name, len) < 0)
1386
            goto cleanup;
1387

1388 1389 1390 1391 1392 1393
        while ((rc = ttyname_r(slave, name, len)) == ERANGE) {
            if (VIR_RESIZE_N(name, len, len, len) < 0)
                goto cleanup;
        }
        if (rc != 0) {
            errno = rc;
1394
            goto cleanup;
E
Eric Blake 已提交
1395
        }
1396 1397
        *ttyName = name;
        name = NULL;
1398 1399
    }

1400
    ret = 0;
1401 1402

cleanup:
1403
    if (ret != 0)
1404
        VIR_FORCE_CLOSE(*ttymaster);
1405 1406
    VIR_FORCE_CLOSE(slave);
    VIR_FREE(name);
1407

1408
    return ret;
1409
}
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
#else /* WIN32 */
int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,
                   char **ttyName ATTRIBUTE_UNUSED,
                   int rawmode ATTRIBUTE_UNUSED)
{
    /* mingw completely lacks pseudo-terminals, and the gnulib
     * replacements are not (yet) license compatible.  */
    errno = ENOSYS;
    return -1;
}
#endif /* WIN32 */
1421

1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
bool virFileIsAbsPath(const char *path)
{
    if (!path)
        return false;

    if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
        return true;

#ifdef WIN32
    if (c_isalpha(path[0]) &&
        path[1] == ':' &&
        VIR_FILE_IS_DIR_SEPARATOR(path[2]))
        return true;
#endif

    return false;
}


const char *virFileSkipRoot(const char *path)
{
#ifdef WIN32
    /* Skip \\server\share or //server/share */
    if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) &&
        VIR_FILE_IS_DIR_SEPARATOR(path[1]) &&
        path[2] &&
        !VIR_FILE_IS_DIR_SEPARATOR(path[2]))
    {
        const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR);
        const char *q = strchr(path + 2, '/');

        if (p == NULL || (q != NULL && q < p))
            p = q;

        if (p && p > path + 2 && p[1]) {
            path = p + 1;

            while (path[0] &&
                   !VIR_FILE_IS_DIR_SEPARATOR(path[0]))
                path++;

            /* Possibly skip a backslash after the share name */
            if (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
                path++;

            return path;
        }
    }
#endif

    /* Skip initial slashes */
    if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) {
        while (VIR_FILE_IS_DIR_SEPARATOR(path[0]))
            path++;

        return path;
    }

#ifdef WIN32
    /* Skip X:\ */
    if (c_isalpha(path[0]) &&
        path[1] == ':' &&
        VIR_FILE_IS_DIR_SEPARATOR(path[2]))
        return path + 3;
#endif

    return path;
}



A
Amy Griffis 已提交
1493
/*
E
Eric Blake 已提交
1494
 * Creates an absolute path for a potentially relative path.
A
Amy Griffis 已提交
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
 * Return 0 if the path was not relative, or on success.
 * Return -1 on error.
 *
 * You must free the result.
 */
int virFileAbsPath(const char *path, char **abspath)
{
    char *buf;

    if (path[0] == '/') {
1505 1506
        if (!(*abspath = strdup(path)))
            return -1;
A
Amy Griffis 已提交
1507 1508 1509
    } else {
        buf = getcwd(NULL, 0);
        if (buf == NULL)
1510
            return -1;
A
Amy Griffis 已提交
1511

1512
        if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
A
Amy Griffis 已提交
1513
            VIR_FREE(buf);
1514
            return -1;
A
Amy Griffis 已提交
1515
        }
1516
        VIR_FREE(buf);
A
Amy Griffis 已提交
1517 1518 1519 1520
    }

    return 0;
}
1521

1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
/* Remove spurious / characters from a path. The result must be freed */
char *
virFileSanitizePath(const char *path)
{
    const char *cur = path;
    char *cleanpath;
    int idx = 0;

    cleanpath = strdup(path);
    if (!cleanpath) {
        virReportOOMError();
        return NULL;
    }

    /* Need to sanitize:
     * //           -> //
     * ///          -> /
     * /../foo      -> /../foo
     * /foo///bar/  -> /foo/bar
     */

    /* Starting with // is valid posix, but ///foo == /foo */
    if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') {
        idx = 2;
        cur += 2;
    }

    /* Sanitize path in place */
    while (*cur != '\0') {
        if (*cur != '/') {
            cleanpath[idx++] = *cur++;
            continue;
        }

        /* Skip all extra / */
        while (*++cur == '/')
            continue;

        /* Don't add a trailing / */
        if (idx != 0 && *cur == '\0')
            break;

        cleanpath[idx++] = '/';
    }
    cleanpath[idx] = '\0';

    return cleanpath;
}

1571 1572 1573 1574 1575 1576 1577
/* Like strtol, but produce an "int" result, and check more carefully.
   Return 0 upon success;  return -1 to indicate failure.
   When END_PTR is NULL, the byte after the final valid digit must be NUL.
   Otherwise, it's like strtol and lets the caller check any suffix for
   validity.  This function is careful to return -1 when the string S
   represents a number that is not representable as an "int". */
int
D
Daniel P. Berrange 已提交
1578
virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
1579 1580 1581 1582 1583 1584
{
    long int val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1585
    val = strtol(s, &p, base); /* exempt from syntax-check */
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
    err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

/* Just like virStrToLong_i, above, but produce an "unsigned int" value.  */
int
virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
{
    unsigned long int val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1604
    val = strtoul(s, &p, base); /* exempt from syntax-check */
1605 1606 1607 1608 1609 1610 1611 1612 1613
    err = (errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

1614 1615 1616 1617 1618 1619 1620 1621 1622
/* Just like virStrToLong_i, above, but produce a "long" value.  */
int
virStrToLong_l(char const *s, char **end_ptr, int base, long *result)
{
    long int val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1623
    val = strtol(s, &p, base); /* exempt from syntax-check */
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
    err = (errno || (!end_ptr && *p) || p == s);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

/* Just like virStrToLong_i, above, but produce an "unsigned long" value.  */
int
virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result)
{
    unsigned long int val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1642
    val = strtoul(s, &p, base); /* exempt from syntax-check */
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
    err = (errno || (!end_ptr && *p) || p == s);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

/* Just like virStrToLong_i, above, but produce a "long long" value.  */
1653 1654 1655 1656 1657 1658 1659 1660
int
virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
{
    long long val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1661
    val = strtoll(s, &p, base); /* exempt from syntax-check */
E
Eric Blake 已提交
1662
    err = (errno || (!end_ptr && *p) || p == s);
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

/* Just like virStrToLong_i, above, but produce an "unsigned long long" value.  */
int
D
Daniel P. Berrange 已提交
1673
virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result)
1674 1675 1676 1677 1678 1679
{
    unsigned long long val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1680
    val = strtoull(s, &p, base); /* exempt from syntax-check */
E
Eric Blake 已提交
1681
    err = (errno || (!end_ptr && *p) || p == s);
1682 1683 1684 1685 1686 1687 1688
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}
1689

1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
int
virStrToDouble(char const *s,
               char **end_ptr,
               double *result)
{
    double val;
    char *p;
    int err;

    errno = 0;
E
Eric Blake 已提交
1700
    val = strtod(s, &p); /* exempt from syntax-check */
1701 1702 1703 1704 1705 1706 1707 1708 1709
    err = (errno || (!end_ptr && *p) || p == s);
    if (end_ptr)
        *end_ptr = p;
    if (err)
        return -1;
    *result = val;
    return 0;
}

1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
/* Convert C from hexadecimal character to integer.  */
int
virHexToBin(unsigned char c)
{
    switch (c) {
    default: return c - '0';
    case 'a': case 'A': return 10;
    case 'b': case 'B': return 11;
    case 'c': case 'C': return 12;
    case 'd': case 'D': return 13;
    case 'e': case 'E': return 14;
    case 'f': case 'F': return 15;
    }
}

1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
/* Scale an integer VALUE in-place by an optional case-insensitive
 * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is
 * typically 1 or 1024).  Recognized suffixes include 'b' or 'bytes',
 * as well as power-of-two scaling via binary abbreviations ('KiB',
 * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and
 * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...).
 * Ensure that the result does not exceed LIMIT.  Return 0 on success,
 * -1 with error message raised on failure.  */
int
virScaleInteger(unsigned long long *value, const char *suffix,
                unsigned long long scale, unsigned long long limit)
{
    if (!suffix || !*suffix) {
        if (!scale) {
            virUtilError(VIR_ERR_INTERNAL_ERROR,
                         _("invalid scale %llu"), scale);
            return -1;
        }
        suffix = "";
    } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte") ||
               STRCASEEQ(suffix, "bytes")) {
        scale = 1;
    } else {
        int base;

        if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) {
            base = 1024;
        } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) {
            base = 1000;
        } else {
            virUtilError(VIR_ERR_INVALID_ARG,
                         _("unknown suffix '%s'"), suffix);
            return -1;
        }
        scale = 1;
        switch (c_tolower(*suffix)) {
        case 'e':
            scale *= base;
            /* fallthrough */
        case 'p':
            scale *= base;
            /* fallthrough */
        case 't':
            scale *= base;
            /* fallthrough */
        case 'g':
            scale *= base;
            /* fallthrough */
        case 'm':
            scale *= base;
            /* fallthrough */
        case 'k':
            scale *= base;
            break;
        default:
            virUtilError(VIR_ERR_INVALID_ARG,
                         _("unknown suffix '%s'"), suffix);
            return -1;
        }
    }

    if (*value && *value >= (limit / scale)) {
        virUtilError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"),
                     *value, suffix);
        return -1;
    }
    *value *= scale;
    return 0;
}

1795 1796 1797 1798 1799
/**
 * virSkipSpaces:
 * @str: pointer to the char pointer used
 *
 * Skip potential blanks, this includes space tabs, line feed,
E
Eric Blake 已提交
1800
 * carriage returns.
1801 1802 1803 1804 1805 1806
 */
void
virSkipSpaces(const char **str)
{
    const char *cur = *str;

E
Eric Blake 已提交
1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
    while (c_isspace(*cur))
        cur++;
    *str = cur;
}

/**
 * virSkipSpacesAndBackslash:
 * @str: pointer to the char pointer used
 *
 * Like virSkipSpaces, but also skip backslashes erroneously emitted
 * by xend
 */
void
virSkipSpacesAndBackslash(const char **str)
{
    const char *cur = *str;

    while (c_isspace(*cur) || *cur == '\\')
1825 1826 1827 1828
        cur++;
    *str = cur;
}

E
Eric Blake 已提交
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
/**
 * virTrimSpaces:
 * @str: string to modify to remove all trailing spaces
 * @endp: track the end of the string
 *
 * If @endp is NULL on entry, then all spaces prior to the trailing
 * NUL in @str are removed, by writing NUL into the appropriate
 * location.  If @endp is non-NULL but points to a NULL pointer,
 * then all spaces prior to the trailing NUL in @str are removed,
 * NUL is written to the new string end, and endp is set to the
 * location of the (new) string end.  If @endp is non-NULL and
 * points to a non-NULL pointer, then that pointer is used as
 * the end of the string, endp is set to the (new) location, but
 * no NUL pointer is written into the string.
 */
void
virTrimSpaces(char *str, char **endp)
{
    char *end;

    if (!endp || !*endp)
        end = str + strlen(str);
    else
        end = *endp;
    while (end > str && c_isspace(end[-1]))
        end--;
    if (endp) {
        if (!*endp)
            *end = '\0';
        *endp = end;
    } else {
        *end = '\0';
    }
}

/**
 * virSkipSpacesBackwards:
 * @str: start of string
 * @endp: on entry, *endp must be NULL or a location within @str, on exit,
 * will be adjusted to skip trailing spaces, or to NULL if @str had nothing
 * but spaces.
 */
void
virSkipSpacesBackwards(const char *str, char **endp)
{
    /* Casting away const is safe, since virTrimSpaces does not
     * modify string with this particular usage.  */
    char *s = (char*) str;

    if (!*endp)
        *endp = s + strlen(s);
    virTrimSpaces(s, endp);
    if (s == *endp)
        *endp = NULL;
}

1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
/**
 * virParseNumber:
 * @str: pointer to the char pointer used
 *
 * Parse an unsigned number
 *
 * Returns the unsigned number or -1 in case of error. @str will be
 *         updated to skip the number.
 */
int
virParseNumber(const char **str)
{
    int ret = 0;
    const char *cur = *str;

    if ((*cur < '0') || (*cur > '9'))
1901
        return -1;
1902

J
Jim Meyering 已提交
1903
    while (c_isdigit(*cur)) {
1904 1905 1906 1907
        unsigned int c = *cur - '0';

        if ((ret > INT_MAX / 10) ||
            ((ret == INT_MAX / 10) && (c > INT_MAX % 10)))
1908
            return -1;
1909 1910 1911 1912
        ret = ret * 10 + c;
        cur++;
    }
    *str = cur;
1913
    return ret;
1914
}
1915

1916 1917 1918 1919 1920

/**
 * virParseVersionString:
 * @str: const char pointer to the version string
 * @version: unsigned long pointer to output the version number
1921 1922
 * @allowMissing: true to treat 3 like 3.0.0, false to error out on
 * missing minor or micro
1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
 *
 * Parse an unsigned version number from a version string. Expecting
 * 'major.minor.micro' format, ignoring an optional suffix.
 *
 * The major, minor and micro numbers are encoded into a single version number:
 *
 *   1000000 * major + 1000 * minor + micro
 *
 * Returns the 0 for success, -1 for error.
 */
int
1934 1935
virParseVersionString(const char *str, unsigned long *version,
                      bool allowMissing)
1936
{
1937
    unsigned int major, minor = 0, micro = 0;
1938 1939
    char *tmp;

1940
    if (virStrToLong_ui(str, &tmp, 10, &major) < 0)
1941 1942
        return -1;

1943 1944 1945
    if (!allowMissing && *tmp != '.')
        return -1;

1946
    if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0)
1947 1948
        return -1;

1949 1950 1951
    if (!allowMissing && *tmp != '.')
        return -1;

1952
    if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &micro) < 0)
1953 1954
        return -1;

1955 1956 1957
    if (major > UINT_MAX / 1000000 || minor > 999 || micro > 999)
        return -1;

1958 1959 1960 1961 1962
    *version = 1000000 * major + 1000 * minor + micro;

    return 0;
}

E
Eric Blake 已提交
1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
/**
 * virVasprintf
 *
 * like glibc's vasprintf but makes sure *strp == NULL on failure
 */
int
virVasprintf(char **strp, const char *fmt, va_list list)
{
    int ret;

    if ((ret = vasprintf(strp, fmt, list)) == -1)
        *strp = NULL;

    return ret;
}

G
Guido Günther 已提交
1979 1980 1981
/**
 * virAsprintf
 *
1982
 * like glibc's_asprintf but makes sure *strp == NULL on failure
G
Guido Günther 已提交
1983
 */
1984
int
G
Guido Günther 已提交
1985 1986 1987 1988 1989 1990
virAsprintf(char **strp, const char *fmt, ...)
{
    va_list ap;
    int ret;

    va_start(ap, fmt);
E
Eric Blake 已提交
1991
    ret = virVasprintf(strp, fmt, ap);
G
Guido Günther 已提交
1992 1993 1994 1995
    va_end(ap);
    return ret;
}

C
Chris Lalancette 已提交
1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038
/**
 * virStrncpy
 *
 * A safe version of strncpy.  The last parameter is the number of bytes
 * available in the destination string, *not* the number of bytes you want
 * to copy.  If the destination is not large enough to hold all n of the
 * src string bytes plus a \0, NULL is returned and no data is copied.
 * If the destination is large enough to hold the n bytes plus \0, then the
 * string is copied and a pointer to the destination string is returned.
 */
char *
virStrncpy(char *dest, const char *src, size_t n, size_t destbytes)
{
    char *ret;

    if (n > (destbytes - 1))
        return NULL;

    ret = strncpy(dest, src, n);
    /* strncpy NULL terminates iff the last character is \0.  Therefore
     * force the last byte to be \0
     */
    dest[n] = '\0';

    return ret;
}

/**
 * virStrcpy
 *
 * A safe version of strcpy.  The last parameter is the number of bytes
 * available in the destination string, *not* the number of bytes you want
 * to copy.  If the destination is not large enough to hold all n of the
 * src string bytes plus a \0, NULL is returned and no data is copied.
 * If the destination is large enough to hold the source plus \0, then the
 * string is copied and a pointer to the destination string is returned.
 */
char *
virStrcpy(char *dest, const char *src, size_t destbytes)
{
    return virStrncpy(dest, src, strlen(src), destbytes);
}

2039 2040 2041 2042 2043
int virEnumFromString(const char *const*types,
                      unsigned int ntypes,
                      const char *type)
{
    unsigned int i;
2044 2045 2046
    if (!type)
        return -1;

2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063
    for (i = 0 ; i < ntypes ; i++)
        if (STREQ(types[i], type))
            return i;

    return -1;
}

const char *virEnumToString(const char *const*types,
                            unsigned int ntypes,
                            int type)
{
    if (type < 0 || type >= ntypes)
        return NULL;

    return types[type];
}

2064 2065 2066
/* Translates a device name of the form (regex) /^[fhv]d[a-z]+[0-9]*$/
 * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
 * Note that any trailing string of digits is simply ignored.
2067 2068 2069 2070 2071 2072
 * @param name The name of the device
 * @return name's index, or -1 on failure
 */
int virDiskNameToIndex(const char *name) {
    const char *ptr = NULL;
    int idx = 0;
2073
    static char const* const drive_prefix[] = {"fd", "hd", "vd", "sd", "xvd", "ubd"};
2074
    unsigned int i;
2075

2076 2077 2078
    for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
        if (STRPREFIX(name, drive_prefix[i])) {
            ptr = name + strlen(drive_prefix[i]);
2079
            break;
2080
        }
2081 2082
    }

2083
    if (!ptr)
2084 2085
        return -1;

D
Daniel Veillard 已提交
2086
    for (i = 0; *ptr; i++) {
2087
        idx = (idx + (i < 1 ? 0 : 1)) * 26;
2088

J
Jim Meyering 已提交
2089
        if (!c_islower(*ptr))
2090
            break;
2091 2092 2093 2094 2095

        idx += *ptr - 'a';
        ptr++;
    }

2096 2097 2098 2099 2100
    /* Count the trailing digits.  */
    size_t n_digits = strspn(ptr, "0123456789");
    if (ptr[n_digits] != '\0')
        return -1;

2101 2102
    return idx;
}
G
Guido Günther 已提交
2103

2104 2105 2106 2107 2108 2109
char *virIndexToDiskName(int idx, const char *prefix)
{
    char *name = NULL;
    int i, k, offset;

    if (idx < 0) {
2110 2111
        virUtilError(VIR_ERR_INTERNAL_ERROR,
                     _("Disk index %d is negative"), idx);
2112 2113 2114 2115 2116 2117 2118 2119
        return NULL;
    }

    for (i = 0, k = idx; k >= 0; ++i, k = k / 26 - 1) { }

    offset = strlen(prefix);

    if (VIR_ALLOC_N(name, offset + i + 1)) {
2120
        virReportOOMError();
2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133
        return NULL;
    }

    strcpy(name, prefix);
    name[offset + i] = '\0';

    for (i = i - 1, k = idx; k >= 0; --i, k = k / 26 - 1) {
        name[offset + i] = 'a' + (k % 26);
    }

    return name;
}

2134
#ifndef AI_CANONIDN
2135
# define AI_CANONIDN 0
2136 2137
#endif

C
Chris Lalancette 已提交
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
/* Who knew getting a hostname could be so delicate.  In Linux (and Unices
 * in general), many things depend on "hostname" returning a value that will
 * resolve one way or another.  In the modern world where networks frequently
 * come and go this is often being hard-coded to resolve to "localhost".  If
 * it *doesn't* resolve to localhost, then we would prefer to have the FQDN.
 * That leads us to 3 possibilities:
 *
 * 1)  gethostname() returns an FQDN (not localhost) - we return the string
 *     as-is, it's all of the information we want
 * 2)  gethostname() returns "localhost" - we return localhost; doing further
 *     work to try to resolve it is pointless
 * 3)  gethostname() returns a shortened hostname - in this case, we want to
 *     try to resolve this to a fully-qualified name.  Therefore we pass it
 *     to getaddrinfo().  There are two possible responses:
 *     a)  getaddrinfo() resolves to a FQDN - return the FQDN
2153
 *     b)  getaddrinfo() fails or resolves to localhost - in this case, the
2154 2155 2156
 *         data we got from gethostname() is actually more useful than what
 *         we got from getaddrinfo().  Return the value from gethostname()
 *         and hope for the best.
C
Chris Lalancette 已提交
2157 2158
 */
char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
2159 2160 2161
{
    int r;
    char hostname[HOST_NAME_MAX+1], *result;
C
Chris Lalancette 已提交
2162
    struct addrinfo hints, *info;
2163 2164

    r = gethostname (hostname, sizeof(hostname));
2165
    if (r == -1) {
2166 2167
        virReportSystemError(errno,
                             "%s", _("failed to determine host name"));
2168
        return NULL;
2169
    }
2170 2171
    NUL_TERMINATE(hostname);

C
Chris Lalancette 已提交
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
    if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) {
        /* in this case, gethostname returned localhost (meaning we can't
         * do any further canonicalization), or it returned an FQDN (and
         * we don't need to do any further canonicalization).  Return the
         * string as-is; it's up to callers to check whether "localhost"
         * is allowed.
         */
        result = strdup(hostname);
        goto check_and_return;
    }

    /* otherwise, it's a shortened, non-localhost, hostname.  Attempt to
     * canonicalize the hostname by running it through getaddrinfo
     */

2187 2188 2189 2190
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
    hints.ai_family = AF_UNSPEC;
    r = getaddrinfo(hostname, NULL, &hints, &info);
2191
    if (r != 0) {
2192 2193 2194 2195
        VIR_WARN("getaddrinfo failed for '%s': %s",
                 hostname, gai_strerror(r));
        result = strdup(hostname);
        goto check_and_return;
2196
    }
2197

2198 2199 2200
    /* Tell static analyzers about getaddrinfo semantics.  */
    sa_assert (info);

C
Chris Lalancette 已提交
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
    if (info->ai_canonname == NULL ||
        STRPREFIX(info->ai_canonname, "localhost"))
        /* in this case, we tried to canonicalize and we ended up back with
         * localhost.  Ignore the canonicalized name and just return the
         * original hostname
         */
        result = strdup(hostname);
    else
        /* Caller frees this string. */
        result = strdup (info->ai_canonname);
2211

C
Chris Lalancette 已提交
2212
    freeaddrinfo(info);
2213

C
Chris Lalancette 已提交
2214 2215
check_and_return:
    if (result == NULL)
2216
        virReportOOMError();
2217 2218 2219
    return result;
}

G
Guido Günther 已提交
2220 2221 2222
/* send signal to a single process */
int virKillProcess(pid_t pid, int sig)
{
2223
    if (pid <= 1) {
G
Guido Günther 已提交
2224 2225 2226 2227
        errno = ESRCH;
        return -1;
    }

2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
#ifdef WIN32
    /* Mingw / Windows don't have many signals (AFAIK) */
    switch (sig) {
    case SIGINT:
        /* This does a Ctrl+C equiv */
        if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) {
            errno = ESRCH;
            return -1;
        }
        break;

    case SIGTERM:
        /* Since TerminateProcess is closer to SIG_KILL, we do
         * a Ctrl+Break equiv which is more pleasant like the
         * good old unix SIGTERM/HUP
         */
        if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) {
            errno = ESRCH;
            return -1;
        }
        break;

    default:
    {
        HANDLE proc;
        proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
        if (!proc) {
            errno = ESRCH; /* Not entirely accurate, but close enough */
            return -1;
        }

        /*
         * TerminateProcess is more or less equiv to SIG_KILL, in that
         * a process can't trap / block it
         */
2263
        if (sig != 0 && !TerminateProcess(proc, sig)) {
2264 2265 2266 2267 2268 2269 2270 2271
            errno = ESRCH;
            return -1;
        }
        CloseHandle(proc);
    }
    }
    return 0;
#else
G
Guido Günther 已提交
2272
    return kill(pid, sig);
2273
#endif
G
Guido Günther 已提交
2274
}
2275 2276 2277


#ifdef HAVE_GETPWUID_R
2278 2279 2280 2281 2282
enum {
    VIR_USER_ENT_DIRECTORY,
    VIR_USER_ENT_NAME,
};

2283
static char *virGetUserEnt(uid_t uid,
2284
                           int field)
2285 2286 2287 2288
{
    char *strbuf;
    char *ret;
    struct passwd pwbuf;
2289
    struct passwd *pw = NULL;
2290 2291
    long val = sysconf(_SC_GETPW_R_SIZE_MAX);
    size_t strbuflen = val;
2292
    int rc;
2293

2294 2295 2296
    /* sysconf is a hint; if it fails, fall back to a reasonable size */
    if (val < 0)
        strbuflen = 1024;
2297 2298

    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
2299
        virReportOOMError();
2300 2301 2302
        return NULL;
    }

2303 2304 2305 2306 2307 2308 2309
    /*
     * From the manpage (terrifying but true):
     *
     * ERRORS
     *  0 or ENOENT or ESRCH or EBADF or EPERM or ...
     *        The given name or uid was not found.
     */
2310 2311 2312 2313 2314 2315 2316 2317 2318
    while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) {
        if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) {
            virReportOOMError();
            VIR_FREE(strbuf);
            return NULL;
        }
    }
    if (rc != 0 || pw == NULL) {
        virReportSystemError(rc,
E
Eric Blake 已提交
2319 2320
                             _("Failed to find user record for uid '%u'"),
                             (unsigned int) uid);
2321 2322 2323 2324
        VIR_FREE(strbuf);
        return NULL;
    }

2325 2326 2327 2328
    if (field == VIR_USER_ENT_DIRECTORY)
        ret = strdup(pw->pw_dir);
    else
        ret = strdup(pw->pw_name);
2329 2330 2331

    VIR_FREE(strbuf);
    if (!ret)
2332
        virReportOOMError();
2333 2334 2335

    return ret;
}
2336

2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
static char *virGetGroupEnt(gid_t gid)
{
    char *strbuf;
    char *ret;
    struct group grbuf;
    struct group *gr = NULL;
    long val = sysconf(_SC_GETGR_R_SIZE_MAX);
    size_t strbuflen = val;
    int rc;

    /* sysconf is a hint; if it fails, fall back to a reasonable size */
    if (val < 0)
        strbuflen = 1024;

    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
        virReportOOMError();
        return NULL;
    }

    /*
     * From the manpage (terrifying but true):
     *
     * ERRORS
     *  0 or ENOENT or ESRCH or EBADF or EPERM or ...
     *        The given name or gid was not found.
     */
    while ((rc = getgrgid_r(gid, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) {
        if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) {
            virReportOOMError();
            VIR_FREE(strbuf);
            return NULL;
        }
    }
    if (rc != 0 || gr == NULL) {
        virReportSystemError(rc,
                             _("Failed to find group record for gid '%u'"),
                             (unsigned int) gid);
        VIR_FREE(strbuf);
        return NULL;
    }

    ret = strdup(gr->gr_name);

    VIR_FREE(strbuf);
    if (!ret)
        virReportOOMError();

    return ret;
}

2387
char *virGetUserDirectory(void)
2388
{
2389
    return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY);
2390 2391
}

2392
static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir)
2393
{
2394
    const char *path = getenv(xdgenvname);
2395
    char *ret = NULL;
2396
    char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY);
2397 2398

    if (path && path[0]) {
2399
        if (virAsprintf(&ret, "%s/libvirt", path) < 0)
2400 2401
            goto no_memory;
    } else {
2402
        if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0)
2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
            goto no_memory;
    }

 cleanup:
    VIR_FREE(home);
    return ret;
 no_memory:
    virReportOOMError();
    goto cleanup;
}

2414
char *virGetUserConfigDirectory(void)
2415
{
2416
    return virGetXDGDirectory("XDG_CONFIG_HOME", ".config");
2417 2418
}

2419
char *virGetUserCacheDirectory(void)
2420
{
2421
     return virGetXDGDirectory("XDG_CACHE_HOME", ".cache");
2422 2423
}

2424
char *virGetUserRuntimeDirectory(void)
2425
{
2426
    const char *path = getenv("XDG_RUNTIME_DIR");
2427 2428

    if (!path || !path[0]) {
2429
        return virGetUserCacheDirectory();
2430 2431 2432
    } else {
        char *ret;

2433
        if (virAsprintf(&ret, "%s/libvirt", path) < 0) {
2434 2435 2436 2437 2438 2439 2440 2441
            virReportOOMError();
            return NULL;
        }

        return ret;
    }
}

2442
char *virGetUserName(uid_t uid)
2443
{
2444
    return virGetUserEnt(uid, VIR_USER_ENT_NAME);
2445 2446
}

2447 2448 2449 2450 2451
char *virGetGroupName(gid_t gid)
{
    return virGetGroupEnt(gid);
}

2452

2453
int virGetUserID(const char *name,
2454 2455 2456 2457 2458
                 uid_t *uid)
{
    char *strbuf;
    struct passwd pwbuf;
    struct passwd *pw = NULL;
2459 2460
    long val = sysconf(_SC_GETPW_R_SIZE_MAX);
    size_t strbuflen = val;
2461
    int rc;
2462

2463 2464 2465
    /* sysconf is a hint; if it fails, fall back to a reasonable size */
    if (val < 0)
        strbuflen = 1024;
2466 2467

    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
2468
        virReportOOMError();
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
        return -1;
    }

    /*
     * From the manpage (terrifying but true):
     *
     * ERRORS
     *  0 or ENOENT or ESRCH or EBADF or EPERM or ...
     *        The given name or uid was not found.
     */
2479 2480 2481 2482 2483 2484 2485 2486 2487
    while ((rc = getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) {
        if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) {
            virReportOOMError();
            VIR_FREE(strbuf);
            return -1;
        }
    }
    if (rc != 0 || pw == NULL) {
        virReportSystemError(rc,
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
                             _("Failed to find user record for name '%s'"),
                             name);
        VIR_FREE(strbuf);
        return -1;
    }

    *uid = pw->pw_uid;

    VIR_FREE(strbuf);

    return 0;
}


2502
int virGetGroupID(const char *name,
2503 2504 2505 2506 2507
                  gid_t *gid)
{
    char *strbuf;
    struct group grbuf;
    struct group *gr = NULL;
2508 2509
    long val = sysconf(_SC_GETGR_R_SIZE_MAX);
    size_t strbuflen = val;
2510
    int rc;
2511

2512 2513 2514
    /* sysconf is a hint; if it fails, fall back to a reasonable size */
    if (val < 0)
        strbuflen = 1024;
2515 2516

    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
2517
        virReportOOMError();
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527
        return -1;
    }

    /*
     * From the manpage (terrifying but true):
     *
     * ERRORS
     *  0 or ENOENT or ESRCH or EBADF or EPERM or ...
     *        The given name or uid was not found.
     */
2528 2529 2530 2531 2532 2533 2534 2535 2536
    while ((rc = getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) {
        if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) {
            virReportOOMError();
            VIR_FREE(strbuf);
            return -1;
        }
    }
    if (rc != 0 || gr == NULL) {
        virReportSystemError(rc,
2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548
                             _("Failed to find group record for name '%s'"),
                             name);
        VIR_FREE(strbuf);
        return -1;
    }

    *gid = gr->gr_gid;

    VIR_FREE(strbuf);

    return 0;
}
2549

L
Laine Stump 已提交
2550 2551 2552

/* Set the real and effective uid and gid to the given values, and call
 * initgroups so that the process has all the assumed group membership of
2553 2554
 * that uid. return 0 on success, -1 on failure (the original system error
 * remains in errno).
L
Laine Stump 已提交
2555 2556 2557 2558
 */
int
virSetUIDGID(uid_t uid, gid_t gid)
{
2559 2560
    int err;

L
Laine Stump 已提交
2561 2562
    if (gid > 0) {
        if (setregid(gid, gid) < 0) {
2563
            virReportSystemError(err = errno,
E
Eric Blake 已提交
2564 2565
                                 _("cannot change to '%d' group"),
                                 (unsigned int) gid);
2566
            goto error;
L
Laine Stump 已提交
2567 2568 2569 2570 2571 2572 2573 2574
        }
    }

    if (uid > 0) {
# ifdef HAVE_INITGROUPS
        struct passwd pwd, *pwd_result;
        char *buf = NULL;
        size_t bufsize;
2575
        int rc;
L
Laine Stump 已提交
2576 2577 2578 2579 2580 2581 2582

        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
        if (bufsize == -1)
            bufsize = 16384;

        if (VIR_ALLOC_N(buf, bufsize) < 0) {
            virReportOOMError();
2583 2584
            err = ENOMEM;
            goto error;
L
Laine Stump 已提交
2585
        }
2586 2587 2588 2589 2590
        while ((rc = getpwuid_r(uid, &pwd, buf, bufsize,
                                &pwd_result)) == ERANGE) {
            if (VIR_RESIZE_N(buf, bufsize, bufsize, bufsize) < 0) {
                virReportOOMError();
                VIR_FREE(buf);
2591 2592
                err = ENOMEM;
                goto error;
2593 2594 2595
            }
        }
        if (rc || !pwd_result) {
2596
            virReportSystemError(err = rc, _("cannot getpwuid_r(%d)"),
E
Eric Blake 已提交
2597
                                 (unsigned int) uid);
L
Laine Stump 已提交
2598
            VIR_FREE(buf);
2599
            goto error;
L
Laine Stump 已提交
2600 2601
        }
        if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) {
2602
            virReportSystemError(err = errno,
L
Laine Stump 已提交
2603
                                 _("cannot initgroups(\"%s\", %d)"),
E
Eric Blake 已提交
2604
                                 pwd.pw_name, (unsigned int) pwd.pw_gid);
L
Laine Stump 已提交
2605
            VIR_FREE(buf);
2606
            goto error;
L
Laine Stump 已提交
2607 2608 2609 2610
        }
        VIR_FREE(buf);
# endif
        if (setreuid(uid, uid) < 0) {
2611
            virReportSystemError(err = errno,
E
Eric Blake 已提交
2612 2613
                                 _("cannot change to uid to '%d'"),
                                 (unsigned int) uid);
2614
            goto error;
L
Laine Stump 已提交
2615 2616 2617
        }
    }
    return 0;
2618 2619 2620 2621

error:
    errno = err;
    return -1;
L
Laine Stump 已提交
2622 2623
}

2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
#else /* ! HAVE_GETPWUID_R */

# ifdef WIN32
/* These methods are adapted from GLib2 under terms of LGPLv2+ */
static int
virGetWin32SpecialFolder(int csidl, char **path)
{
    char buf[MAX_PATH+1];
    LPITEMIDLIST pidl = NULL;
    int ret = 0;

    *path = NULL;

    if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) {
        if (SHGetPathFromIDList(pidl, buf)) {
            if (!(*path = strdup(buf))) {
                virReportOOMError();
                ret = -1;
            }
        }
        CoTaskMemFree(pidl);
    }
    return ret;
}

static int
virGetWin32DirectoryRoot(char **path)
{
    char windowsdir[MAX_PATH];
    int ret = 0;

    *path = NULL;

    if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir)))
    {
        const char *tmp;
        /* Usually X:\Windows, but in terminal server environments
         * might be an UNC path, AFAIK.
         */
        tmp = virFileSkipRoot(windowsdir);
        if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) &&
            tmp[-2] != ':')
            tmp--;

        windowsdir[tmp - windowsdir] = '\0';
    } else {
        strcpy(windowsdir, "C:\\");
    }

    if (!(*path = strdup(windowsdir))) {
        virReportOOMError();
        ret = -1;
    }

    return ret;
}



char *
virGetUserDirectory(void)
{
    const char *dir;
    char *ret;

    dir = getenv("HOME");

    /* Only believe HOME if it is an absolute path and exists */
    if (dir) {
        if (!virFileIsAbsPath(dir) ||
            !virFileExists(dir))
            dir = NULL;
    }

    /* In case HOME is Unix-style (it happens), convert it to
     * Windows style.
     */
    if (dir) {
        char *p;
        while ((p = strchr (dir, '/')) != NULL)
            *p = '\\';
    }

    if (!dir)
        /* USERPROFILE is probably the closest equivalent to $HOME? */
        dir = getenv("USERPROFILE");

    if (dir) {
        if (!(ret = strdup(dir))) {
            virReportOOMError();
            return NULL;
        }
    }

    if (!ret &&
        virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0)
        return NULL;

    if (!ret &&
        virGetWin32DirectoryRoot(&ret) < 0)
        return NULL;

    if (!ret) {
        virUtilError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("Unable to determine home directory"));
        return NULL;
    }

    return ret;
}

char *
virGetUserConfigDirectory(void)
{
    char *ret;
    if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0)
        return NULL;
2741

2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770
    if (!ret) {
        virUtilError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("Unable to determine config directory"));
        return NULL;
    }
    return ret;
}

char *
virGetUserCacheDirectory(void)
{
    char *ret;
    if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0)
        return NULL;

    if (!ret) {
        virUtilError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("Unable to determine config directory"));
        return NULL;
    }
    return ret;
}

char *
virGetUserRuntimeDirectory(void)
{
    return virGetUserCacheDirectory();
}
# else /* !HAVE_GETPWUID_R && !WIN32 */
2771
char *
2772
virGetUserDirectory(void)
2773 2774
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
M
Matthias Bolte 已提交
2775
                 "%s", _("virGetUserDirectory is not available"));
2776 2777 2778 2779

    return NULL;
}

2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807
char *
virGetUserConfigDirectory(void)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virGetUserConfigDirectory is not available"));

    return NULL;
}

char *
virGetUserCacheDirectory(void)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virGetUserCacheDirectory is not available"));

    return NULL;
}

char *
virGetUserRuntimeDirectory(void)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virGetUserRuntimeDirectory is not available"));

    return NULL;
}
# endif /* ! HAVE_GETPWUID_R && ! WIN32 */

2808 2809 2810 2811
char *
virGetUserName(uid_t uid ATTRIBUTE_UNUSED)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
M
Matthias Bolte 已提交
2812
                 "%s", _("virGetUserName is not available"));
2813 2814 2815 2816 2817 2818 2819 2820

    return NULL;
}

int virGetUserID(const char *name ATTRIBUTE_UNUSED,
                 uid_t *uid ATTRIBUTE_UNUSED)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
M
Matthias Bolte 已提交
2821
                 "%s", _("virGetUserID is not available"));
2822 2823 2824 2825 2826 2827 2828 2829 2830

    return 0;
}


int virGetGroupID(const char *name ATTRIBUTE_UNUSED,
                  gid_t *gid ATTRIBUTE_UNUSED)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
M
Matthias Bolte 已提交
2831
                 "%s", _("virGetGroupID is not available"));
2832 2833 2834

    return 0;
}
L
Laine Stump 已提交
2835 2836 2837 2838 2839 2840 2841 2842 2843

int
virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED,
             gid_t gid ATTRIBUTE_UNUSED)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virSetUIDGID is not available"));
    return -1;
}
2844 2845 2846 2847 2848 2849 2850 2851 2852

char *
virGetGroupName(gid_t gid ATTRIBUTE_UNUSED)
{
    virUtilError(VIR_ERR_INTERNAL_ERROR,
                 "%s", _("virGetGroupName is not available"));

    return NULL;
}
2853
#endif /* HAVE_GETPWUID_R */
2854 2855


2856
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886
/* search /proc/mounts for mount point of *type; return pointer to
 * malloc'ed string of the path if found, otherwise return NULL
 * with errno set to an appropriate value.
 */
char *virFileFindMountPoint(const char *type)
{
    FILE *f;
    struct mntent mb;
    char mntbuf[1024];
    char *ret = NULL;

    f = setmntent("/proc/mounts", "r");
    if (!f)
        return NULL;

    while (getmntent_r(f, &mb, mntbuf, sizeof(mntbuf))) {
        if (STREQ(mb.mnt_type, type)) {
            ret = strdup(mb.mnt_dir);
            goto cleanup;
        }
    }

    if (!ret)
        errno = ENOENT;

cleanup:
    endmntent(f);

    return ret;
}
2887

2888
#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
2889 2890 2891 2892 2893 2894 2895 2896 2897

char *
virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED)
{
    errno = ENOSYS;

    return NULL;
}

2898
#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */
D
Daniel P. Berrange 已提交
2899

2900
#if defined(UDEVADM) || defined(UDEVSETTLE)
2901
void virFileWaitForDevices(void)
D
Daniel P. Berrange 已提交
2902
{
2903
# ifdef UDEVADM
D
Daniel P. Berrange 已提交
2904
    const char *const settleprog[] = { UDEVADM, "settle", NULL };
2905
# else
D
Daniel P. Berrange 已提交
2906
    const char *const settleprog[] = { UDEVSETTLE, NULL };
2907
# endif
D
Daniel P. Berrange 已提交
2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918
    int exitstatus;

    if (access(settleprog[0], X_OK) != 0)
        return;

    /*
     * NOTE: we ignore errors here; this is just to make sure that any device
     * nodes that are being created finish before we try to scan them.
     * If this fails for any reason, we still have the backup of polling for
     * 5 seconds for device nodes.
     */
2919
    if (virRun(settleprog, &exitstatus) < 0)
2920
    {}
D
Daniel P. Berrange 已提交
2921
}
2922
#else
2923
void virFileWaitForDevices(void) {}
D
Daniel P. Berrange 已提交
2924
#endif
2925 2926 2927 2928 2929 2930 2931 2932

int virBuildPathInternal(char **path, ...)
{
    char *path_component = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    va_list ap;
    int ret = 0;

E
Eric Blake 已提交
2933
    va_start(ap, path);
2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952

    path_component = va_arg(ap, char *);
    virBufferAdd(&buf, path_component, -1);

    while ((path_component = va_arg(ap, char *)) != NULL)
    {
        virBufferAddChar(&buf, '/');
        virBufferAdd(&buf, path_component, -1);
    }

    va_end(ap);

    *path = virBufferContentAndReset(&buf);
    if (*path == NULL) {
        ret = -1;
    }

    return ret;
}
2953

2954
#if HAVE_LIBDEVMAPPER_H
2955
bool
2956
virIsDevMapperDevice(const char *dev_name)
2957 2958 2959
{
    struct stat buf;

2960
    if (!stat(dev_name, &buf) &&
2961 2962 2963 2964 2965 2966
        S_ISBLK(buf.st_mode) &&
        dm_is_dm_major(major(buf.st_rdev)))
            return true;

    return false;
}
2967
#else
2968
bool virIsDevMapperDevice(const char *dev_name ATTRIBUTE_UNUSED)
2969 2970 2971 2972
{
    return false;
}
#endif