notification_email: lxc-devel@lists.linuxcontainers.org
build_command_prepend: "./autogen.sh && rm -Rf build && mkdir build && cd build && ../configure --enable-tests --with-distro=unknown"
build_command: "make -j4"
- branch_pattern: master
+ branch_pattern: coverity
before_install:
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
- sudo add-apt-repository ppa:ubuntu-lxc/daily -y
pay attention to a few things:
1 - your code must follow the coding style rules
- 2 - the format of the submission must be Github pull requests
+ 2 - the format of the submission must be GitHub pull requests
3 - your work must be signed
Submitting Modifications:
-------------------------
-The contributions must be Github pull requests.
+The contributions must be GitHub pull requests.
Licensing for new files:
------------------------
Language bindings for the libraries need to be released under LGPLv2.1+.
-Anything else (non-libaries) needs to be Free Software and needs to be
+Anything else (non-libraries) needs to be Free Software and needs to be
allowed to link with LGPLv2.1+ code (if needed). LXC upstream prefers
LGPLv2.1+ or GPLv2 for those.
If you want to become more active it is usually also a good idea to show up in
the LXC IRC channel `#lxc-dev` on `Freenode`. We try to do all development out
in the open and discussion of new features or bugs is done either in
-appropriate Github issues or on IRC.
+appropriate GitHub issues or on IRC.
When thinking about making security critical contributions or substantial
changes it is usually a good idea to ping the developers first and ask whether
mount options=(rw,bind) /sy[^s]*{,/**},
mount options=(rw,bind) /sys?*{,/**},
+ # allow various ro-bind-*re*-mounts
+ mount options=(ro,remount,bind),
+ mount options=(ro,remount,bind,nosuid),
+ mount options=(ro,remount,bind,noexec),
+ mount options=(ro,remount,bind,nodev),
+ mount options=(ro,remount,bind,nosuid,noexec),
+ mount options=(ro,remount,bind,noexec,nodev),
+ mount options=(ro,remount,bind,nodev,nosuid),
+ mount options=(ro,remount,bind,nosuid,noexec,nodev),
+
# allow moving mounts except for /proc, /sys and /dev
mount options=(rw,move) /[^spd]*{,/**},
mount options=(rw,move) /d[^e]*{,/**},
mount options=(rw,bind) /sy[^s]*{,/**},
mount options=(rw,bind) /sys?*{,/**},
+ # allow various ro-bind-*re*-mounts
+ mount options=(ro,remount,bind),
+ mount options=(ro,remount,bind,nosuid),
+ mount options=(ro,remount,bind,noexec),
+ mount options=(ro,remount,bind,nodev),
+ mount options=(ro,remount,bind,nosuid,noexec),
+ mount options=(ro,remount,bind,noexec,nodev),
+ mount options=(ro,remount,bind,nodev,nosuid),
+ mount options=(ro,remount,bind,nosuid,noexec,nodev),
+
# allow moving mounts except for /proc, /sys and /dev
mount options=(rw,move) /[^spd]*{,/**},
mount options=(rw,move) /d[^e]*{,/**},
mount options=(rw,move) /s[^y]*{,/**},
mount options=(rw,move) /sy[^s]*{,/**},
mount options=(rw,move) /sys?*{,/**},
-
# The stop is serialized and can take excessive time. We need to avoid
# delaying the system shutdown / reboot as much as we can since it's not
- # parallelized... Even 5 second timout may be too long.
+ # parallelized... Even 5 second timeout may be too long.
"$bindir"/lxc-autostart $STOPOPTS $SHUTDOWNDELAY
;;
# The stop is serialized and can take excessive time. We need to avoid
# delaying the system shutdown / reboot as much as we can since it's not
-# parallelized... Even 5 second timout may be too long.
+# parallelized... Even 5 second timeout may be too long.
post-stop script
[ -f /etc/default/lxc ] && . /etc/default/lxc
This adds `reboot2()` as a new API extension. This function properly waits
until a reboot succeeded. It takes a timeout argument. When set to `> 0`
`reboot2()` will block until the timeout is reached, if timeout is set to zero
-`reboot2()` will not block, if set to -1 `reboot2()` will block indefinitly.
+`reboot2()` will not block, if set to -1 `reboot2()` will block indefinitely.
## mount\_injection
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
+# http://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using prerendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
+# implemented using a web server instead of a web client using JavaScript. There
# are two flavours of web server based searching depending on the
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# searching and an index file used by the script. When EXTERNAL_SEARCH is
-# Container with new network withtout network devices
+# Container with new network without network devices
lxc.uts.name = omega
lxc.net.0.type = empty
lxc.net.0.flags = up
<citerefentry>
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
<manvolnum>5</manvolnum>
- </citerefentry>. By default, the current archictecture of the
+ </citerefentry>. By default, the current architecture of the
running container will be used.
-->
コマンドを実行するコンテナのアーキテクチャを指定します。
<para><!-- Specify the backing storage type to be used for the copy
where 'backingstorage' is of type 'btrfs', 'dir', 'lvm', 'loop',
'overlay', or 'zfs'. -->
- コピー先コンテナのバッキングストレージのタイプを指定します。ここで 'backingsotrage' は 'btrfs'、'dir'、'lvm'、'loop'、'overlay'、'zfs' のどれかです。
+ コピー先コンテナのバッキングストレージのタイプを指定します。ここで 'backingstorage' は 'btrfs'、'dir'、'lvm'、'loop'、'overlay'、'zfs' のどれかです。
</para>
</listitem>
</varlistentry>
<!--
The uid map to use in the user namespace. Each map consists of
four colon-separate values. First a character 'u', 'g' or 'b' to
- specify whether this map perttains to user ids, group ids, or
+ specify whether this map pertains to user ids, group ids, or
both; next the first userid in the user namespace; next the
first userid as seen on the host; and finally the number of
ids to be mapped.
<variablelist>
<varlistentry>
<term>
- <option>lxc.cgroup.[controll name]</option>
+ <option>lxc.cgroup.[control name]</option>
</term>
<listitem>
<para>
<para>
<!--
Specify the control group value to be set on the unified cgroup
- shierarchy. The controller name is the literal name of the control
+ hierarchy. The controller name is the literal name of the control
group. The permitted names and the syntax of their values is not
dictated by LXC, instead it depends on the features of the Linux
kernel running at the time the container is started, eg.
container should be run can be specified in the container
configuration. The default is <command>lxc-container-default-cgns</command>
if the host kernel is cgroup namespace aware, or
- <command>lxc-container-default</command> othewise.
+ <command>lxc-container-default</command> otherwise.
-->
lxc が apparmor サポートでコンパイルされ、インストールされている場合で、ホストで apparmor が有効な場合、コンテナが従って動くべき apparmor プロファイルは、コンテナの設定で指定することが可能です。
デフォルトは、ホストのカーネルで cgroup 名前空間が使える場合は <command>lxc-container-default-cgns</command>です。使えない場合は <command>lxc-container-default</command> です。
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
- sycall number per line. Each syscall number is whitelisted,
+ syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
-->
現時点では、バージョン番号は 1 と 2 をサポートしています。バージョン 1 では、ポリシーはシンプルなホワイトリストですので、2 行目は "whitelist" でなければなりません。
<citerefentry>
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
<manvolnum>5</manvolnum>
- </citerefentry>. By default, the current archictecture of the
+ </citerefentry>. By default, the current architecture of the
running container will be used.
-->
명령어를 실행하는 컨테이너의 아키텍처를 지정한다.
container. aufs or overlayfs snapshots of directory backed containers are
exempted from this rule.
-->
- 복사본의 저장소는 원본 컨테이너와 같은 종류가 된다. 단, aufs나 디렉토리로 구성된 컨테이너의 overayfs 스냅샷은 예외이다.
+ 복사본의 저장소는 원본 컨테이너와 같은 종류가 된다. 단, aufs나 디렉토리로 구성된 컨테이너의 overlayfs 스냅샷은 예외이다.
</para>
<para>
<!--
The uid map to use in the user namespace. Each map consists of
four colon-separate values. First a character 'u', 'g' or 'b' to
- specify whether this map perttains to user ids, group ids, or
+ specify whether this map pertains to user ids, group ids, or
both; next the first userid in the user namespace; next the
first userid as seen on the host; and finally the number of
ids to be mapped.
<listitem>
<para>
<!--
- UID to use within a private user namesapce for init.
+ UID to use within a private user namespace for init.
-->
init이 사용자 네임스페이스 안에서 사용할 UID.
</para>
<listitem>
<para>
<!--
- GID to use within a private user namesapce for init.
+ GID to use within a private user namespace for init.
-->
init이 사용자 네임스페이스 안에서 사용할 GID.
</para>
container should be run can be specified in the container
configuration. The default is <command>lxc-container-default-cgns</command>
if the host kernel is cgroup namespace aware, or
- <command>lxc-container-default</command> othewise.
+ <command>lxc-container-default</command> otherwise.
-->
lxc가 apparmor를 지원하도록 컴파일된 후 설치되었고, 호스트 시스템에서 apparmor가 활성화되었다면, 컨테이너에서 따라야할 apparmor 프로파일을 컨테이너 설정에서 지정할 수 있다. 기본값은 호스트 커널이 cgroup 네임스페이스를 지원하면 <command>lxc-container-default-cgns</command>이고, 그렇지 않다면 <command>lxc-container-default</command>이다.
</para>
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
- sycall number per line. Each syscall number is whitelisted,
+ syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
-->
현재는 버전1과 2만 지원된다. 버전 1에서는 정책은 단순한 화이트리스트이다. 그러므로 두번째 라인은 반드시 "whitelist"여야 한다. 파일의 나머지 내용은 한 줄에 하나의 시스템콜 번호로 채워진다. 화이트리스트에 없는 번호는 컨테이너에서 블랙리스트로 들어간다.
manage a container with simple command lines and complete enough
to be used for other purposes.
-->
- 이 프로젝트의 첫번째 목적은 컨테이너 프로젝트에 속해있는 커널 개발자들의 작업을 편하게 하며, 특히 새로운 기능인 Checkpoing/Restart에 대해 계속 작업을 진행해 나가는 것이다.
+ 이 프로젝트의 첫번째 목적은 컨테이너 프로젝트에 속해있는 커널 개발자들의 작업을 편하게 하며, 특히 새로운 기능인 Checkpoint/Restart에 대해 계속 작업을 진행해 나가는 것이다.
<command>lxc</command>는 작지만, 컨테이너를 간단한 명령어를 통해 쉽게 관리할 수 있고, 다목적으로 사용되기에도 충분하다.
</para>
</refsect1>
<citerefentry>
<refentrytitle><filename>lxc.conf</filename></refentrytitle>
<manvolnum>5</manvolnum>
- </citerefentry>. By default, the current archictecture of the
+ </citerefentry>. By default, the current architecture of the
running container will be used.
</para>
</listitem>
<listitem>
<para>
Specify the control group value to be set on the unified cgroup
- shierarchy. The controller name is the literal name of the control
+ hierarchy. The controller name is the literal name of the control
group. The permitted names and the syntax of their values is not
dictated by LXC, instead it depends on the features of the Linux
kernel running at the time the container is started, eg.
container should be run can be specified in the container
configuration. The default is <command>lxc-container-default-cgns</command>
if the host kernel is cgroup namespace aware, or
- <command>lxc-container-default</command> othewise.
+ <command>lxc-container-default</command> otherwise.
</para>
<variablelist>
<varlistentry>
Versions 1 and 2 are currently supported. In version 1, the
policy is a simple whitelist. The second line therefore must
read "whitelist", with the rest of the file containing one (numeric)
- sycall number per line. Each syscall number is whitelisted,
+ syscall number per line. Each syscall number is whitelisted,
while every unlisted number is blacklisted for use in the container
</para>
# Resolve every paths against the $ROOTFS environment variable.
# 'ip' just looks too weird. Also, we now have unit-tests! Those unit-tests
-# overwirte this line to use a fake ip-echo tool. It's also convenient
+# override this line to use a fake ip-echo tool. It's also convenient
# if your system holds ip tool in a non-standard location.
ip=/sbin/ip
# container as normal.
# a. echo none | ecryptfs-add-passphrase
# b. lxc-start -n q1
-# Note that you may well want to use a wrapped passhrase (see the ecryptfs-wrap-passphrase(1) manual page).
+# Note that you may well want to use a wrapped passphrase (see the ecryptfs-wrap-passphrase(1) manual page).
set -e
ecryptfs_crypt=$(echo $LXC_ROOTFS_PATH | sed 's/rootfs$/rootfs.crypt/')
/* Utilities for reading/writing fstab, mtab, etc.
- Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
- Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C 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.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright (C) 1995-2000, 2001, 2002, 2003, 2006
+ * Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * The GNU C 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.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
#include <alloca.h>
+#include <mntent.h>
#include <stdio.h>
#include <string.h>
-#include <mntent.h>
+#include "../lxc/macro.h"
/* Since the values in a line are separated by spaces, a name cannot
- contain a space. Therefore some programs encode spaces in names
- by the strings "\040". We undo the encoding when reading an entry.
- The decoding happens in place. */
-static char *
-decode_name (char *buf)
+ * contain a space. Therefore some programs encode spaces in names
+ * by the strings "\040". We undo the encoding when reading an entry.
+ * The decoding happens in place.
+ */
+static char *decode_name(char *buf)
{
- char *rp = buf;
- char *wp = buf;
-
- do
- if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' && rp[3] == '0')
- {
- /* \040 is a SPACE. */
- *wp++ = ' ';
- rp += 3;
- }
- else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '1')
- {
- /* \011 is a TAB. */
- *wp++ = '\t';
- rp += 3;
- }
- else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' && rp[3] == '2')
- {
- /* \012 is a NEWLINE. */
- *wp++ = '\n';
- rp += 3;
- }
- else if (rp[0] == '\\' && rp[1] == '\\')
- {
- /* We have to escape \\ to be able to represent all characters. */
- *wp++ = '\\';
- rp += 1;
- }
- else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' && rp[3] == '4')
- {
- /* \134 is also \\. */
- *wp++ = '\\';
- rp += 3;
- }
- else
- *wp++ = *rp;
- while (*rp++ != '\0');
-
- return buf;
+ char *rp = buf;
+ char *wp = buf;
+
+ do {
+ if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '4' &&
+ rp[3] == '0') {
+ /* \040 is a SPACE. */
+ *wp++ = ' ';
+ rp += 3;
+ } else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' &&
+ rp[3] == '1') {
+ /* \011 is a TAB. */
+ *wp++ = '\t';
+ rp += 3;
+ } else if (rp[0] == '\\' && rp[1] == '0' && rp[2] == '1' &&
+ rp[3] == '2') {
+ /* \012 is a NEWLINE. */
+ *wp++ = '\n';
+ rp += 3;
+ } else if (rp[0] == '\\' && rp[1] == '\\') {
+ /* We have to escape \\ to be able to represent all characters. */
+ *wp++ = '\\';
+ rp += 1;
+ } else if (rp[0] == '\\' && rp[1] == '1' && rp[2] == '3' &&
+ rp[3] == '4') {
+ /* \134 is also \\. */
+ *wp++ = '\\';
+ rp += 3;
+ } else {
+ *wp++ = *rp;
+ }
+ } while (*rp++ != '\0');
+
+ return buf;
}
/* Read one mount table entry from STREAM. Returns a pointer to storage
- reused on the next call, or null for EOF or error (use feof/ferror to
- check). */
-struct mntent *getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
+ * reused on the next call, or null for EOF or error (use feof/ferror to check).
+ */
+struct mntent *getmntent_r(FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
{
- char *cp;
- char *head;
-
- do
- {
- char *end_ptr;
-
- if (fgets (buffer, bufsiz, stream) == NULL)
- {
- return NULL;
- }
-
- end_ptr = strchr (buffer, '\n');
- if (end_ptr != NULL) /* chop newline */
- *end_ptr = '\0';
- else
- {
- /* Not the whole line was read. Do it now but forget it. */
- char tmp[1024];
- while (fgets (tmp, sizeof tmp, stream) != NULL)
- if (strchr (tmp, '\n') != NULL)
- break;
- }
-
- head = buffer + strspn (buffer, " \t");
- /* skip empty lines and comment lines: */
- }
- while (head[0] == '\0' || head[0] == '#');
-
- cp = strsep (&head, " \t");
- mp->mnt_fsname = cp != NULL ? decode_name (cp) : (char *) "";
- if (head)
- head += strspn (head, " \t");
- cp = strsep (&head, " \t");
- mp->mnt_dir = cp != NULL ? decode_name (cp) : (char *) "";
- if (head)
- head += strspn (head, " \t");
- cp = strsep (&head, " \t");
- mp->mnt_type = cp != NULL ? decode_name (cp) : (char *) "";
- if (head)
- head += strspn (head, " \t");
- cp = strsep (&head, " \t");
- mp->mnt_opts = cp != NULL ? decode_name (cp) : (char *) "";
- switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
- {
- case 0:
- mp->mnt_freq = 0;
- case 1:
- mp->mnt_passno = 0;
- case 2:
- break;
- }
-
- return mp;
+ char *cp;
+ char *head;
+
+ do {
+ char *end_ptr;
+
+ if (!fgets(buffer, bufsiz, stream))
+ return NULL;
+
+ end_ptr = strchr(buffer, '\n');
+ if (end_ptr != NULL) {
+ /* chop newline */
+ *end_ptr = '\0';
+ } else {
+ /* Not the whole line was read. Do it now but forget it. */
+ char tmp[1024] = {0};
+
+ while (fgets(tmp, sizeof tmp, stream))
+ if (strchr(tmp, '\n') != NULL)
+ break;
+ }
+
+ head = buffer + strspn(buffer, " \t");
+ /* skip empty lines and comment lines: */
+ } while (head[0] == '\0' || head[0] == '#');
+
+ cp = strsep(&head, " \t");
+ mp->mnt_fsname = cp ? decode_name(cp) : (char *)"";
+ if (head)
+ head += strspn(head, " \t");
+
+ cp = strsep(&head, " \t");
+ mp->mnt_dir = cp ? decode_name(cp) : (char *)"";
+ if (head)
+ head += strspn(head, " \t");
+
+ cp = strsep(&head, " \t");
+ mp->mnt_type = cp ? decode_name(cp) : (char *)"";
+ if (head)
+ head += strspn(head, " \t");
+
+ cp = strsep(&head, " \t");
+ mp->mnt_opts = cp ? decode_name(cp) : (char *)"";
+ if (head) {
+ int ret = sscanf(head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno);
+
+ switch (ret) {
+ case 0:
+ mp->mnt_freq = 0;
+ case 1:
+ mp->mnt_passno = 0;
+ case 2:
+ break;
+ }
+ } else {
+ mp->mnt_freq = 0;
+ }
+
+ return mp;
}
-struct mntent *getmntent (FILE *stream)
+struct mntent *getmntent(FILE *stream)
{
- static struct mntent m;
- static char *getmntent_buffer;
+ static struct mntent m;
+ static char *getmntent_buffer;
- #define BUFFER_SIZE 4096
- if (getmntent_buffer == NULL) {
- getmntent_buffer = (char *) malloc (BUFFER_SIZE);
- }
+ if (!getmntent_buffer) {
+ getmntent_buffer = (char *)malloc(LXC_MAX_BUFFER);
+ if (!getmntent_buffer)
+ return NULL;
+ }
- return getmntent_r (stream, &m, getmntent_buffer, BUFFER_SIZE);
- #undef BUFFER_SIZE
+ return getmntent_r(stream, &m, getmntent_buffer, LXC_MAX_BUFFER);
}
-
/* Prepare to begin reading and/or writing mount table entries from the
- beginning of FILE. MODE is as for `fopen'. */
-FILE *setmntent (const char *file, const char *mode)
+ * beginning of FILE. MODE is as for `fopen'.
+ */
+FILE *setmntent(const char *file, const char *mode)
{
- /* Extend the mode parameter with "c" to disable cancellation in the
- I/O functions and "e" to set FD_CLOEXEC. */
- size_t modelen = strlen (mode);
- char *newmode;
+ /* Extend the mode parameter with "c" to disable cancellation in the
+ * I/O functions and "e" to set FD_CLOEXEC.
+ */
+ size_t modelen = strlen(mode);
+ char *newmode;
- newmode = alloca(modelen + 3);
+ newmode = alloca(modelen + 3);
- memcpy (newmode, mode, modelen);
- memcpy (newmode + modelen, "ce", 3);
- FILE *result = fopen (file, newmode);
+ memcpy(newmode, mode, modelen);
+ memcpy(newmode + modelen, "ce", 3);
- return result;
+ return fopen (file, newmode);
}
-
/* Close a stream opened with `setmntent'. */
-int endmntent (FILE *stream)
+int endmntent(FILE *stream)
{
- if (stream) /* SunOS 4.x allows for NULL stream */
- fclose (stream);
- return 1; /* SunOS 4.x says to always return 1 */
+ /* SunOS 4.x allows for NULL stream */
+ if (stream)
+ fclose(stream);
+
+ /* SunOS 4.x says to always return 1 */
+ return 1;
}
/* Search MNT->mnt_opts for an option matching OPT.
- Returns the address of the substring, or null if none found. */
-char *hasmntopt (const struct mntent *mnt, const char *opt)
+ * Returns the address of the substring, or null if none found.
+ */
+char *hasmntopt(const struct mntent *mnt, const char *opt)
{
- const size_t optlen = strlen (opt);
- char *rest = mnt->mnt_opts, *p;
-
- while ((p = strstr (rest, opt)) != NULL)
- {
- if ((p == rest || p[-1] == ',')
- && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
- return p;
-
- rest = strchr (p, ',');
- if (rest == NULL)
- break;
- ++rest;
- }
-
- return NULL;
+ const size_t optlen = strlen(opt);
+ char *rest = mnt->mnt_opts, *p;
+
+ while ((p = strstr(rest, opt))) {
+ if ((p == rest || p[-1] == ',') &&
+ (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
+ return p;
+
+ rest = strchr(p, ',');
+ if (!rest)
+ break;
+
+ ++rest;
+ }
+
+ return NULL;
}
struct nlmsghdr *h),
void *ctx)
{
- char getlink_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) +
- __NETLINK_ALIGN(sizeof(struct ifinfomsg)) +
- __NETLINK_ALIGN(1024)];
- char getaddr_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) +
- __NETLINK_ALIGN(sizeof(struct ifaddrmsg)) +
- __NETLINK_ALIGN(1024)];
+ int r, property, ret;
char *buf;
struct nlmsghdr *hdr;
struct ifinfomsg *ifi_msg;
} req;
struct nlmsghdr reply;
} u;
- int r, property, ret;
-
- if (type == RTM_GETLINK)
- buf = getlink_buf;
- else if (type == RTM_GETADDR)
- buf = getaddr_buf;
- else
- return -1;
-
- memset(buf, 0, sizeof(*buf));
+ char getlink_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) +
+ __NETLINK_ALIGN(sizeof(struct ifinfomsg)) +
+ __NETLINK_ALIGN(1024)] = {0};
+ char getaddr_buf[__NETLINK_ALIGN(sizeof(struct nlmsghdr)) +
+ __NETLINK_ALIGN(sizeof(struct ifaddrmsg)) +
+ __NETLINK_ALIGN(1024)] = {0};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
- hdr = (struct nlmsghdr *)buf;
- if (type == RTM_GETLINK)
+ if (type == RTM_GETLINK) {
+ buf = getlink_buf;
+ hdr = (struct nlmsghdr *)buf;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi_msg));
+
ifi_msg = (struct ifinfomsg *)__NLMSG_DATA(hdr);
- else
- ifa_msg = (struct ifaddrmsg *)__NLMSG_DATA(hdr);
+ ifi_msg->ifi_family = af;
- if (type == RTM_GETLINK)
- hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi_msg));
- else
+ property = IFLA_TARGET_NETNSID;
+ } else if (type == RTM_GETADDR) {
+ buf = getaddr_buf;
+ hdr = (struct nlmsghdr *)buf;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*ifa_msg));
+
+ ifa_msg = (struct ifaddrmsg *)__NLMSG_DATA(hdr);
+ ifa_msg->ifa_family = af;
+
+ property = IFA_TARGET_NETNSID;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
#pragma GCC diagnostic pop
hdr->nlmsg_type = type;
hdr->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
hdr->nlmsg_pid = 0;
hdr->nlmsg_seq = seq;
- if (type == RTM_GETLINK)
- ifi_msg->ifi_family = af;
- else
- ifa_msg->ifa_family = af;
-
- errno = EINVAL;
- if (type == RTM_GETLINK)
- property = IFLA_TARGET_NETNSID;
- else if (type == RTM_GETADDR)
- property = IFA_TARGET_NETNSID;
- else
- return -1;
if (netns_id >= 0)
addattr(hdr, 1024, property, &netns_id, sizeof(netns_id));
terminal.h \
../tests/lxctest.h \
tools/arguments.h \
+ storage/storage_utils.h \
utils.h
if IS_BIONIC
lxc_ls_SOURCES = tools/lxc_ls.c \
tools/arguments.c tools/arguments.h
lxc_copy_SOURCES = tools/lxc_copy.c \
- tools/arguments.c tools/arguments.h
+ tools/arguments.c tools/arguments.h \
+ storage/storage_utils.c storage/storage_utils.h
lxc_start_SOURCES = tools/lxc_start.c \
tools/arguments.c tools/arguments.h
lxc_stop_SOURCES = tools/lxc_stop.c \
lxc_wait_SOURCES = tools/lxc_wait.c \
tools/arguments.c tools/arguments.h
lxc_create_SOURCES = tools/lxc_create.c \
- tools/arguments.c tools/arguments.h
+ tools/arguments.c tools/arguments.h \
+ storage/storage_utils.c storage/storage_utils.h
lxc_snapshot_SOURCES = tools/lxc_snapshot.c \
tools/arguments.c tools/arguments.h
lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c \
pam_LTLIBRARIES = pam_cgfs.la
pam_cgfs_la_SOURCES = pam/pam_cgfs.c \
- caps.c caps.h \
file_utils.c file_utils.h \
- log.c log.h \
macro.h \
string_utils.c string_utils.h
* just fork()s away without exec'ing directly after, the socket fd will
* exist in the forked process from the other thread and any close() in
* our own child process will not really cause the socket to close
- * properly, potentiall causing the parent to hang.
+ * properly, potentially causing the parent to hang.
*
* For this reason, while IPC is still active, we have to use shutdown()
* if the child exits prematurely in order to signal that the socket is
#include "caps.h"
#include "config.h"
+#include "file_utils.h"
#include "log.h"
#include "macro.h"
char *ptr;
char buf[INTTYPE_TO_STRLEN(int)] = {0};
- again:
- n = read(fd, buf, STRARRAYLEN(buf));
- if (n < 0 && errno == EINTR) {
- goto again;
- } else if (n >= 0) {
+ n = lxc_read_nointr(fd, buf, STRARRAYLEN(buf));
+ if (n >= 0) {
errno = 0;
result = strtol(buf, &ptr, 10);
if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
*
* This new implementation assumes that cgroup filesystems are mounted
* under /sys/fs/cgroup/clist where clist is either the controller, or
- * a comman-separated list of controllers.
+ * a comma-separated list of controllers.
*/
#ifndef _GNU_SOURCE
free(clist);
}
-/* Allocate a pointer, do not fail. */
-static void *must_alloc(size_t sz)
-{
- return must_realloc(NULL, sz);
-}
-
/* Given a pointer to a null-terminated array of pointers, realloc to add one
* entry, and point the new entry to NULL. Do not fail. Return the index to the
* second-to-last entry - that is, the one which is now available for use
char *prefixed;
len = strlen(entry);
- prefixed = must_alloc(len + 6);
+ prefixed = must_realloc(NULL, len + 6);
memcpy(prefixed, "name=", STRLITERALLEN("name="));
memcpy(prefixed + STRLITERALLEN("name="), entry, len);
if (len <= 0)
goto on_error;
- value = must_alloc(len + 1);
+ value = must_realloc(NULL, len + 1);
ret = lxc_read_from_file(fpath, value, len);
if (ret != len)
goto on_error;
char **cur;
struct hierarchy **hlist = ops->hierarchies;
- if (!controller_found(hlist, "freezer")) {
- ERROR("No freezer controller mountpoint found");
- return false;
- }
-
if (!ops->cgroup_use)
return true;
struct hierarchy *new;
int newentry;
- new = must_alloc(sizeof(*new));
+ new = must_realloc(NULL, sizeof(*new));
new->controllers = clist;
new->mountpoint = mountpoint;
new->container_base_path = container_base_path;
*p2 = '\0';
len = strlen(p);
- sret = must_alloc(len + 1);
+ sret = must_realloc(NULL, len + 1);
memcpy(sret, p, len);
sret[len] = '\0';
return sret;
return NULL;
len = p2 - p;
- sret = must_alloc(len + 1);
+ sret = must_realloc(NULL, len + 1);
memcpy(sret, p, len);
sret[len] = '\0';
return sret;
}
len = strlen(tmp) + 5; /* leave room for -NNN\0 */
- container_cgroup = must_alloc(len);
+ container_cgroup = must_realloc(NULL, len);
(void)strlcpy(container_cgroup, tmp, len);
free(tmp);
offset = container_cgroup + len - 5;
/* After $rootfs/sys/fs/container/controller/the/cg/path has been created,
* remount controller ro if needed and bindmount the cgroupfs onto
- * controll/the/cg/path.
+ * control/the/cg/path.
*/
static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
char *controllerpath, char *cgpath,
len = strlen(base_path) + STRLITERALLEN("/lxc-1000") +
STRLITERALLEN("/cgroup-procs");
- full_path = must_alloc(len + 1);
+ full_path = must_realloc(NULL, len + 1);
do {
if (idx)
ret = snprintf(full_path, len + 1, "%s/lxc-%d",
if (errno != EBUSY)
goto on_error;
- } while (++idx > 0 && idx < 1000);
+ idx++;
+ } while (idx < 1000);
on_success:
if (idx < 1000)
}
while (!feof(f)) {
- pid_t pid;
+ pid_t find_pid;
- if (fscanf(f, "%d ", &pid) != 1) {
+ if (fscanf(f, "%d ", &find_pid) != 1) {
if (my_args.quiet)
fprintf(stderr, "Failed to retrieve pid\n");
fclose(f);
return;
}
- kill_children(pid);
- kill(pid, SIGKILL);
+ (void)kill_children(find_pid);
+ (void)kill(find_pid, SIGKILL);
}
fclose(f);
struct lxc_epoll_descr descr;
};
-static struct lxc_monitor mon;
+static struct lxc_monitor monitor;
static int quit;
static int lxc_monitord_fifo_create(struct lxc_monitor *mon)
static void lxc_monitord_cleanup(void)
{
- lxc_monitord_delete(&mon);
+ lxc_monitord_delete(&monitor);
}
static void lxc_monitord_sig_handler(int sig)
ret = EXIT_FAILURE;
- memset(&mon, 0, sizeof(mon));
- mon.lxcpath = lxcpath;
- if (lxc_mainloop_open(&mon.descr)) {
+ memset(&monitor, 0, sizeof(monitor));
+ monitor.lxcpath = lxcpath;
+ if (lxc_mainloop_open(&monitor.descr)) {
ERROR("Failed to create mainloop");
goto on_error;
}
mainloop_opened = true;
- if (lxc_monitord_create(&mon))
+ if (lxc_monitord_create(&monitor))
goto on_error;
monitord_created = true;
;
close(pipefd);
- if (lxc_monitord_mainloop_add(&mon)) {
+ if (lxc_monitord_mainloop_add(&monitor)) {
ERROR("Failed to add mainloop handlers");
goto on_error;
}
NOTICE("lxc-monitord with pid %d is now monitoring lxcpath %s",
- lxc_raw_getpid(), mon.lxcpath);
+ lxc_raw_getpid(), monitor.lxcpath);
for (;;) {
- ret = lxc_mainloop(&mon.descr, 1000 * 30);
+ ret = lxc_mainloop(&monitor.descr, 1000 * 30);
if (ret) {
ERROR("mainloop returned an error");
break;
}
- if (mon.clientfds_cnt <= 0) {
+ if (monitor.clientfds_cnt <= 0) {
NOTICE("No remaining clients. lxc-monitord is exiting");
break;
}
if (quit == LXC_MAINLOOP_CLOSE) {
- NOTICE("Got quit command. lxc-monitord is exitting");
+ NOTICE("Got quit command. lxc-monitord is exiting");
break;
}
}
lxc_monitord_cleanup();
if (mainloop_opened)
- lxc_mainloop_close(&mon.descr);
+ lxc_mainloop_close(&monitor.descr);
exit(ret);
}
_exit(EXIT_FAILURE);
}
- /* Write names of veth pairs and their ifindeces to stout:
+ /* Write names of veth pairs and their ifindices to stout:
* (e.g. eth0:731:veth9MT2L4:730)
*/
fprintf(stdout, "%s:%d:%s:%d\n", newname, container_veth_ifidx, nicname,
SYSTRACE("Command \"%s\" failed to connect command socket",
lxc_cmd_str(cmd->req.cmd));
- if (errno == ECONNREFUSED)
+ if (errno == ECONNREFUSED || errno == EPIPE)
*stopped = 1;
- if (errno == EPIPE) {
- *stopped = 1;
- client_fd = 0;
- }
-
return -1;
}
if (ret < 0 && errno == ECONNRESET)
*stopped = 1;
- if (!stay_connected || ret <= 0)
- if (client_fd >= 0) {
- saved_errno = errno;
- close(client_fd);
- errno = saved_errno;
- }
+ if (!stay_connected || ret <= 0) {
+ saved_errno = errno;
+ close(client_fd);
+ errno = saved_errno;
+ return ret;
+ }
if (stay_connected && ret > 0)
cmd->rsp.ret = client_fd;
return 0;
}
-/* Implentations of the commands and their callbacks */
+/* Implementations of the commands and their callbacks */
/*
* lxc_cmd_get_init_pid: Get pid of the container's init process
if (ret < 0)
break;
- TRACE("Sent ty \"%s\" with master fd %d and slave fd %d to "
+ TRACE("Sent tty \"%s\" with master fd %d and slave fd %d to "
"parent", tty->name, tty->master, tty->slave);
}
return -1;
}
- /* The following code cleans up inhereted mounts which are not required
+ /* The following code cleans up inherited mounts which are not required
* for CT.
*
* The mountinfo file shows not all mounts, if a few points have been
* unmounted between read operations from the mountinfo. So we need to
* read mountinfo a few times.
*
- * This loop can be skipped if a container uses unserns, because all
+ * This loop can be skipped if a container uses userns, because all
* inherited mounts are locked and we should live with all this trash.
*/
for (;;) {
break;
}
- /* This also can be skipped if a container uses unserns. */
+ /* This also can be skipped if a container uses userns. */
(void)umount2("./proc", MNT_DETACH);
/* It is weird, but chdir("..") moves us in a new root */
*/
static int lxc_pivot_root(const char *rootfs)
{
- int newroot = -1, oldroot = -1, ret = -1;
+ int oldroot;
+ int newroot = -1, ret = -1;
- oldroot = open("/", O_DIRECTORY | O_RDONLY);
+ oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (oldroot < 0) {
SYSERROR("Failed to open old root directory");
return -1;
}
- newroot = open(rootfs, O_DIRECTORY | O_RDONLY);
+ newroot = open(rootfs, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (newroot < 0) {
SYSERROR("Failed to open new root directory");
goto on_error;
TRACE("pivot_root(\"%s\") successful", rootfs);
on_error:
- if (oldroot != -1)
- close(oldroot);
- if (newroot != -1)
+ close(oldroot);
+
+ if (newroot >= 0)
close(newroot);
return ret;
TRACE("Created temporary mount file");
}
- if (fd < 0) {
- SYSERROR("Could not create temporary mount file");
- return NULL;
- }
lxc_list_for_each (iterator, mount) {
size_t len;
* of the doubt. Otherwise we might fail even though all the necessary
* file capabilities are set.
*/
- DEBUG("Cannot check for file capabilites as full capability support is "
+ DEBUG("Cannot check for file capabilities as full capability support is "
"missing. Manual intervention needed");
fret = 1;
#endif
if (!had_entry)
continue;
- /* Try to catch the ouput of new{g,u}idmap to make debugging
+ /* Try to catch the output of new{g,u}idmap to make debugging
* easier.
*/
if (use_shadow) {
* This means we require only to establish a mapping from:
* - the container root {g,u}id as seen from the host > user's host {g,u}id
* - the container root -> some sub{g,u}id
- * The former we add, if the user did not specifiy a mapping. The latter we
- * retrieve from the ontainer's configured {g,u}id mappings as it must have been
+ * The former we add, if the user did not specify a mapping. The latter we
+ * retrieve from the container's configured {g,u}id mappings as it must have been
* there to start the container in the first place.
*/
int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
* @bev_type : optional backing store type
* @options : mount options
* @mountflags : the portion of @options that are flags
- * @data : the porition of @options that are not flags
+ * @data : the portion of @options that are not flags
* @managed : whether it is managed by LXC
*/
struct lxc_rootfs {
int stopsignal; /* signal used to hard stop container */
char *rcfile; /* Copy of the top level rcfile we read */
- /* Logfile and logleve can be set in a container config file. Those
- * function as defaults. The defaults can be overriden by command line.
+ /* Logfile and loglevel can be set in a container config file. Those
+ * function as defaults. The defaults can be overridden by command line.
* However we don't want the command line specified values to be saved
* on c->save_config(). So we store the config file specified values
* here. */
- char *logfile; /* the logfile as specifed in config */
- int loglevel; /* loglevel as specifed in config (if any) */
+ char *logfile; /* the logfile as specified in config */
+ int loglevel; /* loglevel as specified in config (if any) */
int logfd;
unsigned int start_auto;
lxc_config_define(sysctl);
lxc_config_define(proc);
-static struct lxc_config_t config[] = {
+static struct lxc_config_t config_jump_table[] = {
{ "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
{ "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
{ "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
{ "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, },
};
-static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
+static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t);
struct lxc_config_t *lxc_get_config(const char *key)
{
size_t i;
- for (i = 0; i < config_size; i++)
- if (!strncmp(config[i].name, key, strlen(config[i].name)))
- return &config[i];
+ for (i = 0; i < config_jump_table_size; i++)
+ if (!strncmp(config_jump_table[i].name, key, strlen(config_jump_table[i].name)))
+ return &config_jump_table[i];
return NULL;
}
lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
if (is_shmounts) {
- lxc_conf->shmount.path_host = strdup(token + STRLITERALLEN("shmounts:"));
- if (!lxc_conf->shmount.path_host) {
+ char *container_path;
+ char *host_path;
+
+ host_path = token + STRLITERALLEN("shmounts:");
+ if (*host_path == '\0') {
SYSERROR("Failed to copy shmounts host path");
goto on_error;
}
- if (strcmp(lxc_conf->shmount.path_host, "") == 0) {
- ERROR("Invalid shmounts path: empty");
+ container_path = strchr(host_path, ':');
+ if (!container_path || *(container_path + 1) == '\0')
+ container_path = "/dev/.lxc-mounts";
+ else
+ *container_path++ = '\0';
+
+ lxc_conf->shmount.path_host = strdup(host_path);
+ if (!lxc_conf->shmount.path_host) {
+ SYSERROR("Failed to copy shmounts host path");
goto on_error;
}
- lxc_conf->shmount.path_cont = strdup("/dev/.lxc-mounts");
+ lxc_conf->shmount.path_cont = strdup(container_path);
if(!lxc_conf->shmount.path_cont) {
SYSERROR("Failed to copy shmounts container path");
goto on_error;
/* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
* just the value(s) will be printed. Since there still could be more than one,
* it is newline-separated.
- * (Maybe that's ambigous, since some values, i.e. devices.list, will already
+ * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
* have newlines?)
* If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
* 'lxc.cgroup.subsystem.key = value' format.
return -1;
subkey = strchr(subkey + 1, '.');
+ if (!subkey)
+ return -1;
subkey++;
- if (!*subkey)
+ if (*subkey == '\0')
return -1;
for (i = 0; i < NUM_LXC_HOOKS; i++) {
ret = lxc_safe_uint((idx_start + 1), &tmpidx);
if (ret < 0) {
errno = -ret;
- SYSERROR("Failed to parse usigned integer from string \"%s\"",
+ SYSERROR("Failed to parse unsigned integer from string \"%s\"",
idx_start + 1);
*idx = ret;
goto on_error;
else
memset(retv, 0, inlen);
- for (i = 0; i < config_size; i++) {
- char *s = config[i].name;
+ for (i = 0; i < config_jump_table_size; i++) {
+ char *s = config_jump_table[i].name;
if (s[strlen(s) - 1] == '.')
continue;
retlen = strlcpy(valuep, value, size);
if (retlen >= size)
- ERROR("Network devie name \"%s\" is too long (>= %zu)", value,
+ ERROR("Network device name \"%s\" is too long (>= %zu)", value,
size);
return 0;
ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
if (ret < 0 || ret >= sizeof(path)) {
- ERROR("snprintf'd too many chacters: %d", ret);
+ ERROR("snprintf'd too many characters: %d", ret);
return -1;
}
return false;
}
- while (current_bit < sizeof(uint64_t) * 8) {
+ while (current_bit < (sizeof(uint64_t) * 8 - 1)) {
/* only test requested features */
if (!(features & (1ULL << current_bit))) {
/* skip this */
struct cgroup_ops *cgroup_ops;
/* Try to detach from the current controlling tty if it exists.
- * Othwerise, lxc_init (via lxc_console) will attach the container's
+ * Otherwise, lxc_init (via lxc_console) will attach the container's
* console output to the current tty, which is probably not what any
* library user wants, and if they do, they can just manually configure
* it :)
ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/console", c->init_pid(c));
if (ret < 0 || ret >= sizeof(path)) {
- ERROR("snprintf'd too many chacters: %d", ret);
+ ERROR("snprintf'd too many characters: %d", ret);
return -1;
}
#include "config.h"
#include "file_utils.h"
-#include "log.h"
#include "macro.h"
#include "string.h"
-lxc_log_define(file_utils, lxc);
-
int lxc_write_to_file(const char *filename, const void *buf, size_t count,
bool add_newline, mode_t mode)
{
if (ret == 0)
(void)strlcpy((char*)arg_start, title, len);
else
- SYSINFO("setting cmdline failed");
+ SYSWARN("Failed to set cmdline");
return ret;
}
for (__iterator = (__list)->next, __next = __iterator->next; \
__iterator != __list; __iterator = __next, __next = __next->next)
-/* Initalize list. */
+/* Initialize list. */
static inline void lxc_list_init(struct lxc_list *list)
{
list->elem = NULL;
#include "caps.h"
#include "config.h"
+#include "file_utils.h"
#include "log.h"
#include "lxccontainer.h"
#include "utils.h"
/* Transform hours to seconds. */
h_in_s = hours * 3600;
- /* Calculate minutes by substracting the seconds for all days in the
+ /* Calculate minutes by subtracting the seconds for all days in the
* epoch and for all hours in the epoch and divide by the number of
* minutes in an hour.
*/
minutes = (time->tv_sec - d_in_s - h_in_s) / 60;
- /* Calculate the seconds by substracting the seconds for all days in the
+ /* Calculate the seconds by subtracting the seconds for all days in the
* epoch, hours in the epoch and minutes in the epoch.
*/
seconds = (time->tv_sec - d_in_s - h_in_s - (minutes * 60));
* think you are, you __will__ cause trouble using them.
* (As a short example how this can cause trouble: LXD uses forkstart to fork
* off a new process that runs the container. At the same time the go runtime
- * LXD relies on does its own multi-threading thing which we can't controll. The
+ * LXD relies on does its own multi-threading thing which we can't control. The
* fork()ing + threading then seems to mess with the locking states in these
* time functions causing deadlocks.)
* The current solution is to be good old unix people and use the Epoch as our
buffer[n] = '\n';
-again:
- ret = write(fd_to_use, buffer, n + 1);
- if (ret < 0 && errno == EINTR)
- goto again;
-
- return ret;
+ return lxc_write_nointr(fd_to_use, buffer, n + 1);
}
#if HAVE_DLOG
ret = lxc_unpriv(mkdir(n, 0755));
if (ret && errno != EEXIST) {
- SYSERROR("Failed to create directory %s", n);
+ SYSERROR("Failed to create directory \"%s\"", n);
free(n);
return -1;
}
int fd;
int newfd;
- fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0666));
+ fd = lxc_unpriv(open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0660));
if (fd < 0) {
SYSERROR("Failed to open log file \"%s\"", name);
return -1;
/*
* lxc_log_init:
* Called from lxc front-end programs (like lxc-create, lxc-start) to
- * initalize the log defaults.
+ * initialize the log defaults.
*/
int lxc_log_init(struct lxc_log *log)
{
" mount options=(rw,bind) /sy[^s]*{,/**},\n"
" mount options=(rw,bind) /sys?*{,/**},\n"
"\n"
-" # allow read-only bind-mounts of anything except /proc, /sys and /dev\n"
-" mount options=(ro,remount,bind) -> /[^spd]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /d[^e]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /de[^v]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev/.[^l]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev/.l[^x]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev/.lx[^c]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev/.lxc?*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev/[^.]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /dev?*{,/**},\n"
-" mount options=(ro,remount,bind) -> /p[^r]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /pr[^o]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /pro[^c]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /proc?*{,/**},\n"
-" mount options=(ro,remount,bind) -> /s[^y]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /sy[^s]*{,/**},\n"
-" mount options=(ro,remount,bind) -> /sys?*{,/**},\n"
+" # allow various ro-bind-*re*-mounts\n"
+" mount options=(ro,remount,bind),\n"
+" mount options=(ro,remount,bind,nosuid),\n"
+" mount options=(ro,remount,bind,noexec),\n"
+" mount options=(ro,remount,bind,nodev),\n"
+" mount options=(ro,remount,bind,nosuid,noexec),\n"
+" mount options=(ro,remount,bind,noexec,nodev),\n"
+" mount options=(ro,remount,bind,nodev,nosuid),\n"
+" mount options=(ro,remount,bind,nosuid,noexec,nodev),\n"
"\n"
" # allow moving mounts except for /proc, /sys and /dev\n"
" mount options=(rw,move) /[^spd]*{,/**},\n"
/*
* Start the specified command inside a system container
* @name : the name of the container
- * @argv : an array of char * corresponding to the commande line
+ * @argv : an array of char * corresponding to the command line
* @conf : configuration
* @daemonize : whether or not the container is daemonized
* Returns 0 on success, < 0 otherwise
/*
* Start the specified command inside an application container
* @name : the name of the container
- * @argv : an array of char * corresponding to the commande line
+ * @argv : an array of char * corresponding to the command line
* @quiet : if != 0 then lxc-init won't produce any output
* @conf : configuration
* @daemonize : whether or not the container is daemonized
out_unlock:
umask(mask);
- if (partial_fd >= 0)
- remove_partial(c, partial_fd);
+ remove_partial(c, partial_fd);
out:
if (!ret)
if (!newnames[pos])
return false;
- /* Sort the arrray as we will use binary search on it. */
+ /* Sort the array as we will use binary search on it. */
qsort(newnames, pos + 1, sizeof(char *),
(int (*)(const void *, const void *))string_cmp);
*list = newlist;
newlist[pos] = c;
- /* Sort the arrray as we will use binary search on it. */
+ /* Sort the array as we will use binary search on it. */
if (sort)
qsort(newlist, pos + 1, sizeof(struct lxc_container *),
(int (*)(const void *, const void *))container_cmp);
char template[PATH_MAX], path[PATH_MAX];
pid_t pid, init_pid;
struct stat sb;
+ bool is_dir;
int ret = -1, fd = -EBADF;
if (!c || !c->lxc_conf) {
}
}
- if (S_ISDIR(sb.st_mode)) {
+ is_dir = (S_ISDIR(sb.st_mode) != 0);
+ if (is_dir) {
sret = mkdtemp(template);
if (!sret) {
SYSERROR("Could not create shmounts temporary dir");
ret = 0;
(void)umount2(template, MNT_DETACH);
- (void)unlink(template);
+ if (is_dir)
+ (void)rmdir(template);
+ else
+ (void)unlink(template);
out:
if (fd >= 0)
bool (*destroy)(struct lxc_container *c);
/*!
- * \brief Save configuaration to a file.
+ * \brief Save configuration to a file.
*
* \param c Container.
* \param alt_file Full path to file to save configuration in.
/*!
* \brief An API call to perform various migration operations
*
- * \param cmd One of the MIGRATE_ contstants.
+ * \param cmd One of the MIGRATE_ constants.
* \param opts A migrate_opts struct filled with relevant options.
* \param size The size of the migrate_opts struct, i.e. sizeof(struct migrate_opts).
*
/*
* Blocking read from multiple monitors for the next container state
* change with timeout
- * @fds : struct pollfd descripting the fds to use
+ * @fds : struct pollfd describing the fds to use
* @nfds : the number of entries in fds
* @msg : the variable which will be filled with the state
* @timeout : the timeout in seconds to wait for a state change
#ifdef __ia64__
ret = __clone2(do_clone, stack, stack_size, flags | SIGCHLD, &clone_arg);
#else
- ret = clone(do_clone, stack + stack_size, flags | SIGCHLD, &clone_arg);
+ ret = clone(do_clone, stack + stack_size, flags | SIGCHLD, &clone_arg);
#endif
if (ret < 0)
SYSERROR("Failed to clone (%#x)", flags);
netdev->link);
clear_ifindices:
- /* We need to clear any ifindeces we recorded so liblxc won't
+ /* We need to clear any ifindices we recorded so liblxc won't
* have cached stale data which would cause it to fail on reboot
* we're we don't re-read the on-disk config file.
*/
hostveth, netdev->link);
clear_ifindices:
- /* We need to clear any ifindeces we recorded so liblxc won't
+ /* We need to clear any ifindices we recorded so liblxc won't
* have cached stale data which would cause it to fail on reboot
* we're we don't re-read the on-disk config file.
*/
return -1;
}
- TRACE("Sent network device names and ifindeces to parent");
+ TRACE("Sent network device names and ifindices to parent");
return 0;
}
* Returns 0 on success, < 0 otherwise
*/
int netlink_transaction(struct nl_handler *handler,
- struct nlmsg *request, struct nlmsg *anwser);
+ struct nlmsg *request, struct nlmsg *answer);
int __netlink_transaction(struct nl_handler *handler, struct nlmsghdr *request,
- struct nlmsghdr *anwser);
+ struct nlmsghdr *answer);
/*
* nla_put_string: copy a null terminated string to a netlink message
#include <unistd.h>
#include "config.h"
+#include "file_utils.h"
#include "macro.h"
-#include "utils.h"
+#include "string_utils.h"
#define PAM_SM_SESSION
#include <security/_pam_macros.h>
static bool is_lxcfs(const char *line);
static bool is_cgv1(char *line);
static bool is_cgv2(char *line);
-static void *must_alloc(size_t sz);
static void must_add_to_list(char ***clist, char *entry);
static void must_append_controller(char **klist, char **nlist, char ***clist,
char *entry);
static void must_append_string(char ***list, char *entry);
static void mysyslog(int err, const char *format, ...) __attribute__((sentinel));
static char *read_file(char *fnam);
-static int read_from_file(const char *filename, void* buf, size_t count);
static int recursive_rmdir(char *dirname);
static inline void set_bit(unsigned bit, uint32_t *bitarr)
{
static char *string_join(const char *sep, const char **parts, bool use_as_prefix);
static void trim(char *s);
static bool write_int(char *path, int v);
-static ssize_t write_nointr(int fd, const void* buf, size_t count);
-static int write_to_file(const char *filename, const void *buf, size_t count,
- bool add_newline);
/* cgroupfs prototypes. */
static bool cg_belongs_to_uid_gid(const char *path, uid_t uid, gid_t gid);
s[--len] = '\0';
}
-/* Allocate pointer; do not fail. */
-static void *must_alloc(size_t sz)
-{
- return must_realloc(NULL, sz);
-}
-
/* Make allocated copy of string. End of string is taken to be '\n'. */
static char *copy_to_eol(char *s)
{
return NULL;
len = newline - s;
- sret = must_alloc(len + 1);
+ sret = must_realloc(NULL, len + 1);
memcpy(sret, s, len);
sret[len] = '\0';
*p2 = '\0';
len = strlen(p);
- sret = must_alloc(len + 1);
+ sret = must_realloc(NULL, len + 1);
memcpy(sret, p, len);
sret[len] = '\0';
size_t len;
len = strlen(entry);
- s = must_alloc(len + 6);
+ s = must_realloc(NULL, len + 6);
ret = snprintf(s, len + 6, "name=%s", entry);
if (ret < 0 || (size_t)ret >= (len + 6)) {
struct cgv1_hierarchy *new;
int newentry;
- new = must_alloc(sizeof(*new));
+ new = must_realloc(NULL, sizeof(*new));
new->controllers = clist;
new->mountpoint = mountpoint;
struct cgv2_hierarchy *new;
int newentry;
- new = must_alloc(sizeof(*new));
+ new = must_realloc(NULL, sizeof(*new));
new->controllers = clist;
new->mountpoint = mountpoint;
}
/* Detect and store information about the cgroupfs v2 hierarchy. Currently only
- * deals with the empty v2 hierachy as we do not retrieve enabled controllers.
+ * deals with the empty v2 hierarchy as we do not retrieve enabled controllers.
*/
static bool cgv2_init(uid_t uid, gid_t gid)
{
return cpus;
}
-static ssize_t write_nointr(int fd, const void* buf, size_t count)
-{
- ssize_t ret;
-
-again:
- ret = write(fd, buf, count);
- if (ret < 0 && errno == EINTR)
- goto again;
-
- return ret;
-}
-
-static int write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
-{
- int fd, saved_errno;
- ssize_t ret;
-
- fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
- if (fd < 0)
- return -1;
-
- ret = write_nointr(fd, buf, count);
- if (ret < 0)
- goto out_error;
- if ((size_t)ret != count)
- goto out_error;
-
- if (add_newline) {
- ret = write_nointr(fd, "\n", 1);
- if (ret != 1)
- goto out_error;
- }
-
- close(fd);
- return 0;
-
-out_error:
- saved_errno = errno;
- close(fd);
- errno = saved_errno;
- return -1;
-}
-
#define __ISOL_CPUS "/sys/devices/system/cpu/isolated"
static bool cg_filter_and_set_cpus(char *path, bool am_initialized)
{
free(fpath);
fpath = must_make_path(path, "cpuset.cpus", NULL);
- ret = write_to_file(fpath, cpulist, strlen(cpulist), false);
+ ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false, 0660);
if (ret < 0) {
pam_cgfs_debug("Could not write cpu list to: %s\n", fpath);
goto on_error;
return bret;
}
-int read_from_file(const char *filename, void* buf, size_t count)
-{
- int fd = -1, saved_errno;
- ssize_t ret;
-
- fd = open(filename, O_RDONLY | O_CLOEXEC);
- if (fd < 0)
- return -1;
-
- if (!buf || !count) {
- char buf2[100];
- size_t count2 = 0;
-
- while ((ret = read(fd, buf2, 100)) > 0)
- count2 += ret;
- if (ret >= 0)
- ret = count2;
- } else {
- memset(buf, 0, count);
- ret = read(fd, buf, count);
- }
-
- if (ret < 0)
- pam_cgfs_debug("read %s: %s", filename, strerror(errno));
-
- saved_errno = errno;
- close(fd);
- errno = saved_errno;
- return ret;
-}
-
/* Copy contents of parent(@path)/@file to @path/@file */
static bool cg_copy_parent_file(char *path, char *file)
{
*lastslash = '\0';
fpath = must_make_path(path, file, NULL);
- len = read_from_file(fpath, NULL, 0);
- if (len <= 0)
+ len = lxc_read_from_file(fpath, NULL, 0);
+ if (len <= 0) {
+ pam_cgfs_debug("Failed to read %s: %s", fpath, strerror(errno));
goto bad;
+ }
- value = must_alloc(len + 1);
- if (read_from_file(fpath, value, len) != len)
+ value = must_realloc(NULL, len + 1);
+ if (lxc_read_from_file(fpath, value, len) != len) {
+ pam_cgfs_debug("Failed to read %s: %s", fpath, strerror(errno));
goto bad;
+ }
free(fpath);
*lastslash = oldv;
fpath = must_make_path(path, file, NULL);
- ret = write_to_file(fpath, value, len, false);
+ ret = lxc_write_to_file(fpath, value, len, false, 0660);
if (ret < 0)
pam_cgfs_debug("Unable to write %s to %s", value, fpath);
clonechildrenpath = must_make_path(h->mountpoint, "cgroup.clone_children", NULL);
- if (read_from_file(clonechildrenpath, &v, 1) < 0) {
- pam_cgfs_debug("Failed to read '%s'", clonechildrenpath);
+ if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
+ pam_cgfs_debug("Failed to read %s: %s", clonechildrenpath, strerror(errno));
free(clonechildrenpath);
return false;
}
return true;
}
- if (write_to_file(clonechildrenpath, "1", 1, false) < 0) {
+ if (lxc_write_to_file(clonechildrenpath, "1", 1, false, 0660) < 0) {
/* Set clone_children so children inherit our settings */
pam_cgfs_debug("Failed to write 1 to %s", clonechildrenpath);
free(clonechildrenpath);
return true;
}
- if (read_from_file(clonechildrenpath, &v, 1) < 0) {
- pam_cgfs_debug("Failed to read '%s'", clonechildrenpath);
+ if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
+ pam_cgfs_debug("Failed to read %s: %s", clonechildrenpath, strerror(errno));
free(clonechildrenpath);
free(cgpath);
return false;
}
free(cgpath);
- if (write_to_file(clonechildrenpath, "1", 1, false) < 0) {
+ if (lxc_write_to_file(clonechildrenpath, "1", 1, false, 0660) < 0) {
/* Set clone_children so children inherit our settings */
pam_cgfs_debug("Failed to write 1 to %s", clonechildrenpath);
free(clonechildrenpath);
return -1;
}
-
/* sendfile() handles up to 2GB. No config file should be that big. */
bytes_sent = lxc_sendfile_nointr(memfd, fd, NULL, LXC_SENDFILE_MAX);
if (bytes_sent < 0) {
f = fopen(file, "r");
if (!f) {
- SYSERROR("failed to open %s", file);
+ SYSERROR("Failed to open \"%s\"", file);
return -1;
}
* error.
*/
if (err < 0)
- ERROR("Failed to parse config: %s", line);
+ ERROR("Failed to parse config: \"%s\"", line);
break;
}
}
pid_t lxc_raw_clone(unsigned long flags)
{
/*
- * These flags don't interest at all so we don't jump through any hoopes
+ * These flags don't interest at all so we don't jump through any hoops
* of retrieving them and passing them to the kernel.
*/
errno = EINVAL;
return (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO);
}
+#ifdef HAVE_DLOG
+static bool match_dlog_fds(struct dirent *direntp)
+{
+ char path[PATH_MAX] = {0};
+ char link[PATH_MAX] = {0};
+ ssize_t linklen;
+ int ret;
+
+ ret = snprintf(path, PATH_MAX, "/proc/self/fd/%s", direntp->d_name);
+ if (ret < 0 || ret >= PATH_MAX) {
+ ERROR("Failed to create file descriptor name");
+ return false;
+ }
+
+ linklen = readlink(path, link, PATH_MAX);
+ if (linklen < 0) {
+ SYSERROR("Failed to read link path - \"%s\"", path);
+ return false;
+ } else if (linklen >= PATH_MAX) {
+ ERROR("The name of link path is too long - \"%s\"", path);
+ return false;
+ }
+
+ if (strcmp(link, "/dev/log_main") == 0 ||
+ strcmp(link, "/dev/log_system") == 0 ||
+ strcmp(link, "/dev/log_radio") == 0)
+ return true;
+
+ return false;
+}
+#endif
+
int lxc_check_inherited(struct lxc_conf *conf, bool closeall,
int *fds_to_ignore, size_t len_fds)
{
if (match_stdfds(fd))
continue;
+#ifdef HAVE_DLOG
+ if (match_dlog_fds(direntp))
+ continue;
+
+#endif
if (closeall) {
close(fd);
closedir(dir);
struct lxc_conf *conf = handler->conf;
for (i = 0; i < LXC_NS_MAX; i++) {
- if (conf->ns_keep != 0) {
+ if (conf->ns_keep > 0) {
if ((conf->ns_keep & ns_info[i].clone_flag) == 0)
handler->ns_clone_flags |= ns_info[i].clone_flag;
- } else if (conf->ns_clone != 0) {
+ } else if (conf->ns_clone > 0) {
if ((conf->ns_clone & ns_info[i].clone_flag) > 0)
handler->ns_clone_flags |= ns_info[i].clone_flag;
} else {
* getpid() in the child would return the parent's pid. This is all fixed in
* newer glibc versions where the getpid() cache is removed and the pid/tid is
* not reset anymore.
- * However, if for whatever reason you - dear commiter - somehow need to get the
+ * However, if for whatever reason you - dear committer - somehow need to get the
* pid of the dummy intermediate process for do_share_ns() you need to call
* lxc_raw_getpid(). The next lxc_raw_clone() call does not employ CLONE_VM and
* will be fine.
return 0;
}
-static int lxc_setup_shmount(struct lxc_conf *conf)
-{
- size_t len_cont;
- char *full_cont_path;
- int ret = -1;
-
- /* Construct the shmount path under the container root. */
- len_cont = strlen(conf->rootfs.mount) + 1 + strlen(conf->shmount.path_cont);
- /* +1 for the terminating '\0' */
- full_cont_path = malloc(len_cont + 1);
- if (!full_cont_path) {
- SYSERROR("Not enough memory");
- return -ENOMEM;
- }
-
- ret = snprintf(full_cont_path, len_cont + 1, "%s/%s",
- conf->rootfs.mount, conf->shmount.path_cont);
- if (ret < 0 || ret >= len_cont + 1) {
- SYSERROR("Failed to create filename");
- free(full_cont_path);
- return -1;
- }
-
- /* Check if shmount point is already set up. */
- if (is_shared_mountpoint(conf->shmount.path_host)) {
- INFO("Path \"%s\" is already MS_SHARED. Reusing",
- conf->shmount.path_host);
- free(full_cont_path);
- return 0;
- }
-
- /* Create host and cont mount paths */
- ret = mkdir_p(conf->shmount.path_host, 0711);
- if (ret < 0 && errno != EEXIST) {
- SYSERROR("Failed to create directory \"%s\"",
- conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- ret = mkdir_p(full_cont_path, 0711);
- if (ret < 0 && errno != EEXIST) {
- SYSERROR("Failed to create directory \"%s\"", full_cont_path);
- free(full_cont_path);
- return ret;
- }
-
- /* Prepare host mountpoint */
- ret = mount("tmpfs", conf->shmount.path_host, "tmpfs", 0,
- "size=100k,mode=0711");
- if (ret < 0) {
- SYSERROR("Failed to mount \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- ret = mount(conf->shmount.path_host, conf->shmount.path_host, "none",
- MS_REC | MS_SHARED, "");
- if (ret < 0) {
- SYSERROR("Failed to make shared \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- INFO("Setup shared mount point \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return 0;
-}
-
/* lxc_spawn() performs crucial setup tasks and clone()s the new process which
* exec()s the requested container binary.
* Note that lxc_spawn() runs in the parent namespaces. Any operations performed
if (ret < 0)
goto out_sync_fini;
- if (conf->shmount.path_host) {
- if (!conf->shmount.path_cont)
- goto out_sync_fini;
-
- ret = lxc_setup_shmount(conf);
- if (ret < 0) {
- ERROR("Failed to setup shared mount point");
- goto out_sync_fini;
- }
- }
-
if (handler->ns_clone_flags & CLONE_NEWNET) {
if (!lxc_list_empty(&conf->network)) {
}
/* Now all networks are created, network devices are moved into place,
- * and the correct names and ifindeces in the respective namespaces have
+ * and the correct names and ifindices in the respective namespaces have
* been recorded. The corresponding structs have now all been filled. So
* log them for debugging purposes.
*/
(void)nanosleep(&onesec, NULL);
}
- if (state < 0) {
- ERROR("Failed to retrieve state from monitor");
- return -1;
- }
-
TRACE("Retrieved state of container %s", lxc_state2str(state));
if (!s[state])
return -1;
/*
* A backref key with the name and dirid of the parent
- * comes followed by the reoot ref key which has the
+ * comes followed by the root ref key which has the
* name of the child subvol in question.
*/
if (sh.objectid != root_id && sh.type == BTRFS_ROOT_BACKREF_KEY) {
(void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
if (args->thinpool)
- execlp("lvcreate", "lvcreate", "--thinpool", args->thinpool,
+ execlp("lvcreate", "lvcreate", "-qq", "--thinpool", args->thinpool,
"-V", args->size, args->vg, "-n", args->lv,
(char *)NULL);
else
- execlp("lvcreate", "lvcreate", "-L", args->size, args->vg, "-n",
+ execlp("lvcreate", "lvcreate", "-qq", "-L", args->size, args->vg, "-n",
args->lv, (char *)NULL);
return -1;
return ret;
}
-/* If we're not snaphotting, then storage_copy becomes a simple case of mount
+/* If we're not snapshotting, then storage_copy becomes a simple case of mount
* the original, mount the new, and rsync the contents.
*/
struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
p += l1;
nlen += (strlen(lxcpath) - l1);
}
+
l2 = strlen(oldname);
while ((p = strstr(p, oldname)) != NULL) {
p += l2;
/* move target pointer (p) */
p += p2 - src;
+
/* print new name in place of oldname */
p += sprintf(p, "%s", name);
+
/* move src to end of oldname */
src = p2 + l2;
}
/* copy the rest of src */
sprintf(p, "%s", src);
+
return ret;
}
const char *src;
src = lxc_storage_get_path(bdev->src, bdev->type);
- fd = open(src, O_RDONLY);
- if (fd < 0)
+
+ fd = open(src, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ SYSERROR("Failed to open \"%s\"", src);
return -1;
+ }
/* size of device in bytes */
ret = ioctl(fd, BLKGETSIZE64, size);
+ if (ret < 0)
+ SYSERROR("Failed to get block size of dev-src");
+
close(fd);
return ret;
}
srcdev = lxc_storage_get_path(bdev->src, bdev->type);
ret = pipe(p);
- if (ret < 0)
+ if (ret < 0) {
+ SYSERROR("Failed to create pipe");
return -1;
+ }
- if ((pid = fork()) < 0)
+ pid = fork();
+ if (pid < 0) {
+ SYSERROR("Failed to fork process");
return -1;
+ }
if (pid > 0) {
int status;
+
close(p[1]);
memset(type, 0, len);
+
ret = read(p[0], type, len - 1);
- close(p[0]);
if (ret < 0) {
- SYSERROR("error reading from pipe");
- wait(&status);
- return -1;
+ SYSERROR("Failed to read FSType from pipe");
} else if (ret == 0) {
- ERROR("child exited early - fstype not found");
- wait(&status);
- return -1;
+ ERROR("FSType not found - child exited early");
+ ret = -1;
}
+
+ close(p[0]);
wait(&status);
+
+ if (ret < 0)
+ return ret;
+
type[len - 1] = '\0';
- INFO("detected fstype %s for %s", type, srcdev);
+ INFO("Detected FSType \"%s\" for \"%s\"", type, srcdev);
+
return ret;
}
if (unshare(CLONE_NEWNS) < 0)
- exit(1);
+ _exit(EXIT_FAILURE);
- if (detect_shared_rootfs()) {
+ if (detect_shared_rootfs())
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
SYSERROR("Failed to make / rslave");
ERROR("Continuing...");
}
- }
ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
if (ret < 0) {
- ERROR("failed mounting %s onto %s to detect fstype", srcdev,
+ ERROR("Failed to mount \"%s\" onto \"%s\" to detect FSType", srcdev,
bdev->dest);
- exit(1);
+ _exit(EXIT_FAILURE);
}
l = linkderef(srcdev, devpath);
if (!l)
- exit(1);
+ _exit(EXIT_FAILURE);
+
f = fopen("/proc/self/mounts", "r");
if (!f)
- exit(1);
+ _exit(EXIT_FAILURE);
while (getline(&line, &linelen, f) != -1) {
sp1 = strchr(line, ' ');
if (!sp1)
- exit(1);
+ _exit(EXIT_FAILURE);
+
*sp1 = '\0';
if (strcmp(line, l))
continue;
+
sp2 = strchr(sp1 + 1, ' ');
if (!sp2)
- exit(1);
+ _exit(EXIT_FAILURE);
*sp2 = '\0';
+
sp3 = strchr(sp2 + 1, ' ');
if (!sp3)
- exit(1);
+ _exit(EXIT_FAILURE);
*sp3 = '\0';
+
sp2++;
if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
- exit(1);
+ _exit(EXIT_FAILURE);
- exit(0);
+ _exit(EXIT_SUCCESS);
}
- exit(1);
+ _exit(EXIT_FAILURE);
}
int do_mkfs_exec_wrapper(void *args)
return -1;
}
- TRACE("executing \"%s %s\"", mkfs, data[1]);
+ TRACE("Executing \"%s %s\"", mkfs, data[1]);
execlp(mkfs, mkfs, data[1], (char *)NULL);
- SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
+
+ SYSERROR("Failed to run \"%s %s\"", mkfs, data[1]);
free(mkfs);
+
return -1;
}
ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
if (ret < 0) {
- ERROR("failed to parse '%s'", fsfile[i]);
+ ERROR("Failed to parse \"%s\"", fsfile[i]);
return -1;
}
return 0;
}
- ERROR("failed to determine fs type for '%s'", rootfs);
+ ERROR("Failed to determine FSType for \"%s\"", rootfs);
+
return -1;
}
fstype += lxc_char_left_gc(fstype, strlen(fstype));
fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
- DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs,
+ DEBUG("Trying to mount \"%s\"->\"%s\" with FSType \"%s\"", cbarg->rootfs,
cbarg->target, fstype);
if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
}
if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
- SYSDEBUG("mount failed with error");
+ SYSDEBUG("Failed to mount");
free(mntdata);
return 0;
}
free(mntdata);
- INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs,
+ INFO("Mounted \"%s\" on \"%s\", with FSType \"%s\"", cbarg->rootfs,
cbarg->target, fstype);
return 1;
ssize_t ret;
ret = stat(path, &sbuf);
- if (ret < 0)
+ if (ret < 0) {
+ SYSERROR("Failed to get status of file - \"%s\"", path);
return NULL;
+ }
if (!S_ISLNK(sbuf.st_mode))
return path;
ret = readlink(path, dest, PATH_MAX);
if (ret < 0) {
- SYSERROR("error reading link %s", path);
+ SYSERROR("Failed to read link of \"%s\"", path);
return NULL;
} else if (ret >= PATH_MAX) {
- ERROR("link in %s too long", path);
+ ERROR("The name of link of \"%s\" is too long", path);
return NULL;
}
dest[ret] = '\0';
struct lxc_conf *conf = data;
if (setgid(0) < 0) {
- ERROR("Failed to setgid to 0");
+ SYSERROR("Failed to setgid to 0");
return -1;
}
if (setgroups(0, NULL) < 0)
- WARN("Failed to clear groups");
+ SYSWARN("Failed to clear groups");
if (setuid(0) < 0) {
- ERROR("Failed to setuid to 0");
+ SYSERROR("Failed to setuid to 0");
return -1;
}
- if (!storage_destroy(conf))
+ if (!storage_destroy(conf)) {
+ ERROR("Failed to destroy storage");
return -1;
+ }
return 0;
}
#include <inttypes.h>
#include <libgen.h>
#include <pthread.h>
+#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
-#include "log.h"
#include "lxclock.h"
#include "macro.h"
#include "namespace.h"
#include "include/strlcat.h"
#endif
-lxc_log_define(string_utils, lxc);
-
char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
{
va_list ap2;
}
va_end(args);
- dest[cur_len] = 0;
+ dest[cur_len] = '\0';
return dest;
}
/* Return copy of string @entry. Do not fail. */
extern char *must_copy_string(const char *entry);
-/* Re-alllocate a pointer, do not fail */
+/* Re-allocate a pointer, do not fail */
extern void *must_realloc(void *orig, size_t sz);
extern int lxc_char_left_gc(const char *buffer, size_t len);
* Must be called with process_lock held to protect the lxc_ttys list, or from
* a non-threaded context.
*
- * Note that the signal handler isn't installed as a classic asychronous
+ * Note that the signal handler isn't installed as a classic asynchronous
* handler, rather signalfd(2) is used so that we can handle the signal when
* we're ready for it. This avoids deadlocks since a signal handler (ie
* lxc_terminal_sigwinch()) would need to take the thread mutex to prevent
}
}
- /* We have a candidate continer to process */
+ /* We have a candidate container to process */
c->want_daemonize(c, 1);
if (my_args.shutdown) {
};
/* mount keys */
-static char *const keys[] = {
+static char *const mount_keys[] = {
[LXC_MNT_BIND] = "bind",
[LXC_MNT_OVL] = "overlay",
NULL
-t, --tmpfs place ephemeral container on a tmpfs\n\
(WARNING: On reboot all changes made to the container will be lost.)\n\
-L, --fssize size of the new block device for block device containers\n\
- -D, --keedata pass together with -e start a persistent snapshot \n\
+ -D, --keepdata pass together with -e start a persistent snapshot \n\
-K, --keepname keep the hostname of the original container\n\
-- hook options arguments passed to the hook program\n\
-M, --keepmac keep the MAC address of the original container\n\
break;
case 'm':
subopts = optarg;
- if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
+ if (parse_mntsubopts(subopts, mount_keys, mntparameters) < 0)
return -1;
break;
case 'B':
static bool stats;
static bool humanize = true;
static char **key = NULL;
-static int keys = 0;
+static int nr_keys = 0;
static int filter_count = 0;
static int my_parser(struct lxc_arguments *args, int c, char *arg)
switch (c) {
case 'c':
- newk = realloc(key, (keys + 1) * sizeof(key[0]));
+ newk = realloc(key, (nr_keys + 1) * sizeof(key[0]));
if (!newk)
return -1;
key = newk;
- key[keys] = arg;
- keys++;
+ key[nr_keys] = arg;
+ nr_keys++;
break;
case 'i': ips = true; filter_count += 1; break;
case 's': state = true; filter_count += 1; break;
return -1;
}
- if (!state && !pid && !ips && !stats && keys <= 0) {
+ if (!state && !pid && !ips && !stats && nr_keys <= 0) {
state = pid = ips = stats = true;
print_info_msg_str("Name:", c->name);
}
print_net_stats(c);
}
- for(i = 0; i < keys; i++) {
+ for(i = 0; i < nr_keys; i++) {
int len = c->get_config_item(c, key[i], NULL, 0);
if (len > 0) {
if (c->get_config_item(c, key[i], val, len + 1) != len) {
fprintf(stderr, "unable to read %s from configuration\n", key[i]);
} else {
- if (!humanize && keys == 1)
+ if (!humanize && nr_keys == 1)
printf("%s\n", val);
else
printf("%s = %s\n", key[i], val);
free(val);
} else if (len == 0) {
- if (!humanize && keys == 1)
+ if (!humanize && nr_keys == 1)
printf("\n");
else
printf("%s =\n", key[i]);
if (!l->name)
goto put_and_next;
- /* Do not record stuff the user did not explictly request. */
+ /* Do not record stuff the user did not explicitly request. */
if (args->ls_fancy) {
/* Maybe we should even consider the name sensitive and
* hide it when you're not allowed to control the
/* reboot */
if (my_args.reboot) {
- ret = c->reboot2(c, my_args.timeout);
- if (ret < 0)
+ if (!c->reboot2(c, my_args.timeout))
ret = EXIT_FAILURE;
else
ret = EXIT_SUCCESS;
struct blkio_stats io_serviced;
};
-struct ct {
+struct container_stats {
struct lxc_container *c;
struct stats *stats;
};
static char sort_by = 'n';
static int sort_reverse = 0;
static struct termios oldtios;
-static struct ct *ct = NULL;
+static struct container_stats *container_stats = NULL;
static int ct_alloc_cnt = 0;
static int my_parser(struct lxc_arguments *args, int c, char *arg)
return;
}
-static void stats_get(struct lxc_container *c, struct ct *ct, struct stats *total)
+static void stats_get(struct lxc_container *c, struct container_stats *ct, struct stats *total)
{
ct->c = c;
ct->stats->mem_used = stat_get_int(c, "memory.usage_in_bytes");
static int cmp_name(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return strncmp(ct2->c->name, ct1->c->name, strlen(ct2->c->name));
static int cmp_cpuuse(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return ct2->stats->cpu_use_nanos < ct1->stats->cpu_use_nanos;
static int cmp_blkio(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return ct2->stats->io_service_bytes.total < ct1->stats->io_service_bytes.total;
static int cmp_memory(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return ct2->stats->mem_used < ct1->stats->mem_used;
static int cmp_memorysw(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return ct2->stats->memsw_used < ct1->stats->memsw_used;
static int cmp_kmemory(const void *sct1, const void *sct2)
{
- const struct ct *ct1 = sct1;
- const struct ct *ct2 = sct2;
+ const struct container_stats *ct1 = sct1;
+ const struct container_stats *ct2 = sct2;
if (sort_reverse)
return ct2->stats->kmem_used < ct1->stats->kmem_used;
case 'k': cmp_func = cmp_kmemory; break;
}
- qsort(ct, active, sizeof(*ct), (int (*)(const void *,const void *))cmp_func);
+ qsort(container_stats, active, sizeof(*container_stats), (int (*)(const void *,const void *))cmp_func);
}
static void ct_free(void)
int i;
for (i = 0; i < ct_alloc_cnt; i++) {
- if (ct[i].c) {
- lxc_container_put(ct[i].c);
- ct[i].c = NULL;
+ if (container_stats[i].c) {
+ lxc_container_put(container_stats[i].c);
+ container_stats[i].c = NULL;
}
- free(ct[i].stats);
- ct[i].stats = NULL;
+ free(container_stats[i].stats);
+ container_stats[i].stats = NULL;
}
}
ct_free();
- ct = realloc(ct, sizeof(*ct) * active_cnt);
- if (!ct) {
+ container_stats = realloc(container_stats, sizeof(*container_stats) * active_cnt);
+ if (!container_stats) {
fprintf(stderr, "Cannot alloc mem\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < active_cnt; i++) {
- ct[i].stats = malloc(sizeof(*ct[0].stats));
- if (!ct[i].stats) {
+ container_stats[i].stats = malloc(sizeof(*container_stats[0].stats));
+ if (!container_stats[i].stats) {
fprintf(stderr, "Cannot alloc mem\n");
exit(EXIT_FAILURE);
}
memset(&total, 0, sizeof(total));
for (i = 0; i < active_cnt; i++)
- stats_get(active[i], &ct[i], &total);
+ stats_get(active[i], &container_stats[i], &total);
ct_sort(active_cnt);
}
for (i = 0; i < active_cnt && i < ct_print_cnt; i++) {
- stats_print(ct[i].c->name, ct[i].stats, &total);
+ stats_print(container_stats[i].c->name, container_stats[i].stats, &total);
printf("\n");
}
fflush(stdout);
for (i = 0; i < active_cnt; i++) {
- lxc_container_put(ct[i].c);
- ct[i].c = NULL;
+ lxc_container_put(container_stats[i].c);
+ container_stats[i].c = NULL;
}
in_char = '\0';
exit(EXIT_FAILURE);
}
- /* Call exit() directly on this function because it retuns an exit code. */
+ /* Call exit() directly on this function because it returns an exit code. */
exit(EXIT_SUCCESS);
}
{
struct dirent *direntp;
DIR *dir;
- int ret, failed=0;
+ int ret, failed = 0;
char pathname[PATH_MAX];
bool hadexclude = false;
dir = opendir(dirname);
if (!dir) {
- ERROR("failed to open %s", dirname);
+ ERROR("Failed to open \"%s\"", dirname);
return -1;
}
rc = snprintf(pathname, PATH_MAX, "%s/%s", dirname, direntp->d_name);
if (rc < 0 || rc >= PATH_MAX) {
- ERROR("pathname too long");
+ ERROR("The name of path is too long");
failed=1;
continue;
}
if (ret < 0) {
switch(errno) {
case ENOTEMPTY:
- INFO("Not deleting snapshot %s", pathname);
+ INFO("Not deleting snapshot \"%s\"", pathname);
hadexclude = true;
break;
case ENOTDIR:
ret = unlink(pathname);
if (ret)
- INFO("Failed to remove %s", pathname);
+ INFO("Failed to remove \"%s\"", pathname);
break;
default:
- SYSERROR("Failed to rmdir %s", pathname);
+ SYSERROR("Failed to rmdir \"%s\"", pathname);
failed = 1;
break;
}
}
+
continue;
}
ret = lstat(pathname, &mystat);
if (ret) {
- ERROR("Failed to stat %s", pathname);
+ SYSERROR("Failed to stat \"%s\"", pathname);
failed = 1;
continue;
}
/* TODO should we be checking /proc/self/mountinfo for
* pathname and not doing this if found? */
if (btrfs_try_remove_subvol(pathname))
- INFO("Removed btrfs subvolume at %s\n", pathname);
+ INFO("Removed btrfs subvolume at \"%s\"", pathname);
continue;
}
failed=1;
} else {
if (unlink(pathname) < 0) {
- SYSERROR("Failed to delete %s", pathname);
+ SYSERROR("Failed to delete \"%s\"", pathname);
failed=1;
}
}
}
if (rmdir(dirname) < 0 && !btrfs_try_remove_subvol(dirname) && !hadexclude) {
- ERROR("Failed to delete %s", dirname);
+ SYSERROR("Failed to delete \"%s\"", dirname);
failed=1;
}
ret = closedir(dir);
if (ret) {
- ERROR("Failed to close directory %s", dirname);
+ SYSERROR("Failed to close directory \"%s\"", dirname);
failed=1;
}
if (errno == ENOENT)
return 0;
- ERROR("Failed to stat %s", path);
+ SYSERROR("Failed to stat \"%s\"", path);
return -1;
}
{
const char *tmp = dir;
const char *orig = dir;
+
do {
int ret;
char *makeme;
free(makeme);
return -1;
}
- free(makeme);
+ free(makeme);
} while (tmp != dir);
return 0;
return rundir;
}
- INFO("XDG_RUNTIME_DIR isn't set in the environment.");
+ INFO("XDG_RUNTIME_DIR isn't set in the environment");
homedir = getenv("HOME");
if (!homedir) {
- ERROR("HOME isn't set in the environment.");
+ ERROR("HOME isn't set in the environment");
return NULL;
}
f = fopen_cloexec(fnam, "r");
if (!f) {
- SYSERROR("Error opening template");
+ SYSERROR("Failed to open template \"%s\"", fnam);
return -1;
}
if (fseek(f, 0, SEEK_END) < 0) {
- SYSERROR("Error seeking to end of template");
+ SYSERROR("Failed to seek to end of template");
fclose(f);
return -1;
}
if ((flen = ftell(f)) < 0) {
- SYSERROR("Error telling size of template");
+ SYSERROR("Failed to tell size of template");
fclose(f);
return -1;
}
if (fseek(f, 0, SEEK_SET) < 0) {
- SYSERROR("Error seeking to start of template");
+ SYSERROR("Failed to seek to start of template");
fclose(f);
return -1;
}
}
if (fread(buf, 1, flen, f) != flen) {
- SYSERROR("Failure reading template");
+ SYSERROR("Failed to read template");
free(buf);
fclose(f);
return -1;
}
if (fclose(f) < 0) {
- SYSERROR("Failre closing template");
+ SYSERROR("Failed to close template");
free(buf);
return -1;
}
int randseed(bool srand_it)
{
+ FILE *f;
/*
- srand pre-seed function based on /dev/urandom
- */
+ * srand pre-seed function based on /dev/urandom
+ */
unsigned int seed = time(NULL) + getpid();
- FILE *f;
f = fopen("/dev/urandom", "r");
if (f) {
int ret = fread(&seed, sizeof(seed), 1, f);
if (ret != 1)
- SYSDEBUG("unable to fread /dev/urandom, fallback to time+pid rand seed");
+ SYSDEBUG("Unable to fread /dev/urandom, fallback to time+pid rand seed");
fclose(f);
}
char *line = NULL;
size_t sz = 0;
uid_t nsid, hostid, range;
- FILE *f = fopen("/proc/self/uid_map", "r");
- if (!f)
+ FILE *f;
+
+ f = fopen("/proc/self/uid_map", "r");
+ if (!f) {
+ SYSERROR("Failed to open uid_map");
return 0;
+ }
while (getline(&line, &sz, f) != -1) {
if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
char *line = NULL;
size_t sz = 0;
gid_t nsid, hostid, range;
- FILE *f = fopen("/proc/self/gid_map", "r");
- if (!f)
+ FILE *f;
+
+ f = fopen("/proc/self/gid_map", "r");
+ if (!f) {
+ SYSERROR("Failed to open gid_map");
return 0;
+ }
while (getline(&line, &sz, f) != -1) {
if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
{
unsigned char *bp;
- for(bp = buf; bp < (unsigned char *)buf + len; bp++)
- {
+ for(bp = buf; bp < (unsigned char *)buf + len; bp++) {
/* xor the bottom with the current octet */
hval ^= (uint64_t)*bp;
{
if (is_shared_mountpoint("/"))
return 1;
+
return 0;
}
fd = open(nspath, O_RDONLY);
if (fd < 0) {
- SYSERROR("Failed to open %s", nspath);
+ SYSERROR("Failed to open \"%s\"", nspath);
return false;
}
ret = setns(fd, 0);
if (ret) {
- SYSERROR("Failed to set process %d to %s of %d.", pid, ns, fd);
+ SYSERROR("Failed to set process %d to \"%s\" of %d.", pid, ns, fd);
close(fd);
return false;
}
int i;
f = fopen("/proc/self/mountinfo", "r");
- if (!f)
+ if (!f) {
+ SYSERROR("Failed to open mountinfo");
return false;
+ }
while (getline(&line, &len, f) != -1) {
for (p = line, i = 0; p && i < 4; i++)
retv = on_path("init.lxc", rootfs);
- if (env_set) {
+ if (env_set)
if (unsetenv("PATH"))
SYSERROR("Failed to unsetenv");
- }
if (retv)
return retv;
ret = snprintf(retv, PATH_MAX, "%s/%s/%s", tmp, SBINDIR, "/init.lxc");
if (ret < 0 || ret >= PATH_MAX) {
- ERROR("pathname too long");
+ ERROR("The name of path is too long");
goto out1;
}
ret = snprintf(retv, PATH_MAX, "%s/%s/%s", tmp, LXCINITDIR, "/lxc/lxc-init");
if (ret < 0 || ret >= PATH_MAX) {
- ERROR("pathname too long");
+ ERROR("The name of path is too long");
goto out1;
}
ret = snprintf(retv, PATH_MAX, "%s/usr/lib/lxc/lxc-init", tmp);
if (ret < 0 || ret >= PATH_MAX) {
- ERROR("pathname too long");
+ ERROR("The name of path is too long");
goto out1;
}
ret = snprintf(retv, PATH_MAX, "%s/sbin/lxc-init", tmp);
if (ret < 0 || ret >= PATH_MAX) {
- ERROR("pathname too long");
+ ERROR("The name of path is too long");
goto out1;
}
offset++;
*offsetp = offset;
+
return (offset < fulllen) ? &path[offset] : NULL;
}
static int open_without_symlink(const char *target, const char *prefix_skip)
{
int curlen = 0, dirfd, fulllen, i;
- char *dup = NULL;
+ char *dup;
fulllen = strlen(target);
if (prefix_skip && strlen(prefix_skip) > 0) {
curlen = strlen(prefix_skip);
if (!is_subdir(target, prefix_skip, curlen)) {
- ERROR("WHOA there - target '%s' didn't start with prefix '%s'",
- target, prefix_skip);
+ ERROR("WHOA there - target \"%s\" didn't start with prefix \"%s\"",
+ target, prefix_skip);
return -EINVAL;
}
/* Make a copy of target which we can hack up, and tokenize it */
if ((dup = strdup(target)) == NULL) {
- SYSERROR("Out of memory checking for symbolic link");
+ ERROR("Out of memory checking for symbolic link");
return -ENOMEM;
}
}
dirfd = open(prefix_skip, O_RDONLY);
- if (dirfd < 0)
+ if (dirfd < 0) {
+ SYSERROR("Failed to open path \"%s\"", prefix_skip);
goto out;
+ }
while (1) {
int newfd, saved_errno;
/* todo - allow symlinks for relative paths if 'allowsymlinks' option is passed */
if (flags & MS_BIND && src && src[0] != '/') {
- INFO("this is a relative bind mount");
+ INFO("This is a relative bind mount");
srcfd = open_without_symlink(src, NULL);
if (srcfd < 0)
close(destfd);
if (ret < 0) {
errno = saved_errno;
- SYSERROR("Failed to mount %s onto %s", src ? src : "(null)", dest);
+ SYSERROR("Failed to mount \"%s\" onto \"%s\"", src ? src : "(null)", dest);
return ret;
}
*/
int lxc_mount_proc_if_needed(const char *rootfs)
{
- char path[PATH_MAX];
+ char path[PATH_MAX] = {0};
int link_to_pid, linklen, mypid, ret;
char link[INTTYPE_TO_STRLEN(pid_t)] = {0};
ret = snprintf(path, PATH_MAX, "%s/proc/self", rootfs);
if (ret < 0 || ret >= PATH_MAX) {
- SYSERROR("proc path name too long");
+ SYSERROR("The name of proc path is too long");
return -1;
}
ret = snprintf(path, PATH_MAX, "%s/proc", rootfs);
if (ret < 0 || ret >= PATH_MAX) {
- SYSERROR("proc path name too long");
+ SYSERROR("The name of proc path is too long");
return -1;
}
goto domount;
} else if (linklen >= sizeof(link)) {
link[linklen - 1] = '\0';
- ERROR("readlink returned truncated content: \"%s\"", link);
+ ERROR("Readlink returned truncated content: \"%s\"", link);
return -1;
}
ret = umount2(path, MNT_DETACH);
if (ret < 0)
- WARN("failed to umount \"%s\" with MNT_DETACH", path);
+ SYSWARN("Failed to umount \"%s\" with MNT_DETACH", path);
domount:
/* rootfs is NULL */
if (ret < 0)
return -1;
- INFO("mounted /proc in container for security transition");
+ INFO("Mounted /proc in container for security transition");
return 1;
}
int open_devnull(void)
{
int fd = open("/dev/null", O_RDWR);
-
if (fd < 0)
SYSERROR("Can't open /dev/null");
bool task_blocks_signal(pid_t pid, int signal)
{
int ret;
- char status[__PROC_STATUS_LEN];
+ char status[__PROC_STATUS_LEN] = {0};
FILE *f;
uint64_t sigblk = 0, one = 1;
size_t n = 0;
return true;
}
-/* Simple covenience function which enables uniform logging. */
+/* Simple convenience function which enables uniform logging. */
bool lxc_setgroups(int size, gid_t list[])
{
if (setgroups(size, list) < 0) {
int dfd = -1, fd = -1, ret = -1;
dir = opendir("/dev");
- if (!dir)
+ if (!dir) {
+ SYSERROR("Failed to open \"/dev\"");
return -1;
+ }
while ((dp = readdir(dir))) {
if (strncmp(dp->d_name, "loop", 4) != 0)
int fd_ctl = -1, fd_tmp = -1;
fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
- if (fd_ctl < 0)
+ if (fd_ctl < 0) {
+ SYSERROR("Failed to open loop control");
return -ENODEV;
+ }
loop_nr = ioctl(fd_ctl, LOOP_CTL_GET_FREE);
- if (loop_nr < 0)
+ if (loop_nr < 0) {
+ SYSERROR("Failed to get loop control");
goto on_error;
+ }
ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/loop%d", loop_nr);
if (ret < 0 || ret >= LO_NAME_SIZE)
fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
if (fd_tmp < 0)
- goto on_error;
+ SYSERROR("Failed to open loop \"%s\"", name_loop);
on_error:
close(fd_ctl);
fd_loop = lxc_get_unused_loop_dev(loop_dev);
if (fd_loop < 0) {
- if (fd_loop == -ENODEV)
- fd_loop = lxc_get_unused_loop_dev_legacy(loop_dev);
- else
+ if (fd_loop != -ENODEV)
+ goto on_error;
+
+ fd_loop = lxc_get_unused_loop_dev_legacy(loop_dev);
+ if (fd_loop < 0)
goto on_error;
}
fd_img = open(source, O_RDWR | O_CLOEXEC);
- if (fd_img < 0)
+ if (fd_img < 0) {
+ SYSERROR("Failed to open source \"%s\"", source);
goto on_error;
+ }
ret = ioctl(fd_loop, LOOP_SET_FD, fd_img);
- if (ret < 0)
+ if (ret < 0) {
+ SYSERROR("Failed to set loop fd");
goto on_error;
+ }
memset(&lo64, 0, sizeof(lo64));
lo64.lo_flags = flags;
ret = ioctl(fd_loop, LOOP_SET_STATUS64, &lo64);
- if (ret < 0)
+ if (ret < 0) {
+ SYSERROR("Failed to set loop status64");
goto on_error;
+ }
fret = 0;
buf[0] = '\0';
if (pipe(pipefd) < 0) {
- SYSERROR("failed to create pipe");
+ SYSERROR("Failed to create pipe");
return -1;
}
if (child < 0) {
close(pipefd[0]);
close(pipefd[1]);
- SYSERROR("failed to create new process");
+ SYSERROR("Failed to create new process");
return -1;
}
close(pipefd[1]);
if (ret < 0) {
- SYSERROR("failed to duplicate std{err,out} file descriptor");
+ SYSERROR("Failed to duplicate std{err,out} file descriptor");
_exit(EXIT_FAILURE);
}
/* Does not return. */
child_fn(args);
- ERROR("failed to exec command");
+ ERROR("Failed to exec command");
_exit(EXIT_FAILURE);
}
return -1;
}
- if (ret < 0) {
- SYSERROR("Failed to set PR_SET_PDEATHSIG to %d", signal);
+ if (ret < 0)
return -1;
- }
return 0;
}
int r = 0;
dir = opendir(dirname);
- if (!dir)
+ if (!dir) {
+ SYSERROR("Failed to open dir \"%s\"", dirname);
return -1;
+ }
while ((direntp = readdir(dir))) {
char *pathname;
ret = lstat(pathname, &mystat);
if (ret < 0) {
if (!r)
- WARN("Failed to stat \"%s\"", pathname);
+ SYSWARN("Failed to stat \"%s\"", pathname);
r = -1;
goto next;
break;
default:
SYSERROR("Failed to create kernel keyring");
- ret = -1;
break;
}
}
/* return copy of string @entry; do not fail. */
extern char *must_copy_string(const char *entry);
-/* Re-alllocate a pointer, do not fail */
+/* Re-allocate a pointer, do not fail */
extern void *must_realloc(void *orig, size_t sz);
extern bool lxc_nic_exists(char *nic);
/*
* try opening a file attached to a container. Return 0 on open fail. Return
- * 1 if the file open succeeded. Return -1 if attach itself failed - perhas an
+ * 1 if the file open succeeded. Return -1 if attach itself failed - perhaps an
* older kernel.
*/
static int do_test_file_open(struct lxc_container *c, char *fnam)
goto on_error_put;
}
- /* do the actual fature check for memory tracking */
+ /* do the actual feature check for memory tracking */
m_opts.features_to_check = FEATURE_MEM_TRACK;
if (c->migrate(c, MIGRATE_FEATURE_CHECK, &m_opts, sizeof(struct migrate_opts))) {
lxc_debug("%s\n", "System does not support \"FEATURE_MEM_TRACK\".");
# This would be much simpler if we could run it as
# root. However, in order to not have the bind mount
-# of an empty directory over the securitfs 'mount' directory
+# of an empty directory over the securityfs 'mount' directory
# be removed, we need to do this as non-root.
which newuidmap >/dev/null 2>&1 || { echo "'newuidmap' command is missing" >&2; exit 1; }
return perform_container_test(NAME"unprivileged", config_items);
}
+static bool lxc_setup_shmount(const char *shmount_path)
+{
+ int ret;
+
+ ret = mkdir_p(shmount_path, 0711);
+ if (ret < 0 && errno != EEXIST) {
+ fprintf(stderr, "Failed to create directory \"%s\"\n", shmount_path);
+ return false;
+ }
+
+ /* Prepare host mountpoint */
+ ret = mount("tmpfs", shmount_path, "tmpfs", 0, "size=100k,mode=0711");
+ if (ret < 0) {
+ fprintf(stderr, "Failed to mount \"%s\"\n", shmount_path);
+ return false;
+ }
+
+ ret = mount(shmount_path, shmount_path, "none", MS_REC | MS_SHARED, "");
+ if (ret < 0) {
+ fprintf(stderr, "Failed to make shared \"%s\"\n", shmount_path);
+ return false;
+ }
+
+ return true;
+}
+
+static void lxc_teardown_shmount(char *shmount_path)
+{
+ (void)umount2(shmount_path, MNT_DETACH);
+ (void)recursive_destroy(shmount_path);
+}
+
int main(int argc, char *argv[])
{
+ if (!lxc_setup_shmount("/tmp/mount_injection_test"))
+ exit(EXIT_FAILURE);
+
if (do_priv_container_test()) {
fprintf(stderr, "Privileged mount injection test failed\n");
- return -1;
+ exit(EXIT_FAILURE);
}
- if(do_unpriv_container_test()) {
+ if (do_unpriv_container_test()) {
fprintf(stderr, "Unprivileged mount injection test failed\n");
- return -1;
+ exit(EXIT_FAILURE);
}
- return 0;
+
+ lxc_teardown_shmount("/tmp/mount_injection_test");
+
+ exit(EXIT_SUCCESS);
}
/* Test whether we can start a really short-lived daemonized container with lxc-init. */
for (i = 0; i < 10; i++) {
/* An container started with lxc-init will always start
- * succesfully unless lxc-init has a bug.
+ * successfully unless lxc-init has a bug.
*/
if (!c->startl(c, 1, NULL)) {
fprintf(stderr, "%d: %s failed to start on %dth iteration\n", __LINE__, c->name, i);
sprintf(buf, "0");
b = c->set_cgroup_item(c, "cpuset.cpus", buf);
if (b) {
- fprintf(stderr, "%d: %s not running but coudl set cgroup settings\n", __LINE__, MYNAME);
+ fprintf(stderr, "%d: %s not running but could set cgroup settings\n", __LINE__, MYNAME);
goto out;
}