Re: [lxc-devel] [Lxc-users] Working LXC templates?

2013-09-09 Thread Natanael Copa
On Sun, 08 Sep 2013 20:33:16 -0400
"Michael H. Warfield"  wrote:

> With all due respect...
> 
> On Sun, 2013-09-08 at 16:08 -0700, Tony Su wrote: 
> > After putting some thought into this,
> > IMO LXC badly needs a universal tool with the following features
> > 
> > - A single script should be used to run on  HostOS, creating
> >  supported Container OS. Although this would make the script
> > extremely large, IMO it would actually be easier to maintain in the
> > long run.
> 
> Actually, no.  From my experience (30+ years in software development),
> it would turn into a morass.
> 
> The problem here is that the maintainer(s) would then need to understand
> how each and every distribution is installed and how it would be
> installed on each and every distribution.  It would distill the worse of
> all the problems we have now in the templates into one great big dung
> pile.  It would rapidly become unmaintainable.  The "extremely large" is
> the red letter warning that it will become unmaintainable as fewer and
> fewer people understand what this great big huge blob does.

I tend to agree with this.

What I do think could be done is to use template APIs. Either by having
a script "library" with helper functions (for things like:
generate_mac_address etc) or let the template scripts be "plugins" that
must provide a set of pre-defined functions (eg. install_distro,
configure_distro, copy_configuration etc) or maybe a combination of
those two.

-nc


signature.asc
Description: PGP signature
--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [Lxc-users] Working LXC templates?

2013-09-09 Thread Michael H. Warfield
On Mon, 2013-09-09 at 08:58 +0200, Natanael Copa wrote: 
> On Sun, 08 Sep 2013 20:33:16 -0400
> "Michael H. Warfield"  wrote:
> 
> > With all due respect...
> > 
> > On Sun, 2013-09-08 at 16:08 -0700, Tony Su wrote: 
> > > After putting some thought into this,
> > > IMO LXC badly needs a universal tool with the following features
> > > 
> > > - A single script should be used to run on  HostOS, creating
> > >  supported Container OS. Although this would make the script
> > > extremely large, IMO it would actually be easier to maintain in the
> > > long run.
> > 
> > Actually, no.  From my experience (30+ years in software development),
> > it would turn into a morass.
> > 
> > The problem here is that the maintainer(s) would then need to understand
> > how each and every distribution is installed and how it would be
> > installed on each and every distribution.  It would distill the worse of
> > all the problems we have now in the templates into one great big dung
> > pile.  It would rapidly become unmaintainable.  The "extremely large" is
> > the red letter warning that it will become unmaintainable as fewer and
> > fewer people understand what this great big huge blob does.

> I tend to agree with this.

> What I do think could be done is to use template APIs. Either by having
> a script "library" with helper functions (for things like:
> generate_mac_address etc) or let the template scripts be "plugins" that
> must provide a set of pre-defined functions (eg. install_distro,
> configure_distro, copy_configuration etc) or maybe a combination of
> those two.

I like this idea, it's just that, in the short term, we have to get past
this one gotcha.

In the git-stage current Fedora template, the entire problem is embodied
in the "download_fedora" function starting around line 201...  The
gotcha's are three commands around line 272 after we've identified and
downloaded the initial release rpm.  We have this:

mkdir -p $INSTALL_ROOT/var/lib/rpm
rpm --root $INSTALL_ROOT  --initdb
rpm --root $INSTALL_ROOT -ivh ${INSTALL_ROOT}/${RELEASE_RPM}
$YUM install $PKG_LIST

Ok...  Those are running in the host local run time environment.
Obviously, if the host does not have a (compatible) version of rpm
and/or yum in the host local environment, you're screwed.  That's the
catch-22 situation and it's the same situation with zypper in the
OpenSuse template.  That short space of code has to be recreated in a
totally distro-agnostic manner so it runs on any distro to create our
initial rootfs.  After that, we can do what ever distro (Fedora)
specific commands we want by chrooting into the target container first
(including rebuilding the rpm database to the target version).  That's
only even needed if you don't already have a cached rootfs for that
distro and version.

I was S close last week working on this while on vacation.  Recent
revs of Fedora have this downloadable LiveOS core that runs on the
netinst CD and others.  That's the 200MB - 300MB blob I was referring
to.  You just download it, mount it (requires squashfs) to a directory
and then mount the ext3 image it contains on another directory.  Then
create and bind mount a few rw directories (etc var run), mount proc in
the image, and bind mount your rootfs to run/install in the image.  Then
chroot into the image and voila, instant RTE.  Yum and rpm are capable
of installing other versions of Fedora, so I wouldn't (shouldn't) even
need a version specific instantiation of the RTE, just one that can
install every version we might be interested in.

Except...  It didn't work.  Sigh...  $#@$#@#@

Fedora came so close and then face planted for what I wanted to do.
Sure rpm is in there.  But rpmdb is not.  So, no --initdb and no
--rebuilddb.  They've got yum in there, but no yummain.py so yum hurls
chunks immediately upon execution trying to import yummain.  What the
hell good does it do to have yum in there but no yummain?!?!  But,
something, fixed up, like that from all the distros would be a perfect
answer (albeit somewhat less than high performance thanks to that
download, but it's a single download that could be cached).  The only
potential gotcha I see in there is requiring squashfs available for
mounting the image.  Anyone have heartburn over that?

That squashfs image has to be able to do an install or it would be
useless on the netinst CD.  I'm not sure if they still have anaconda on
there or not but it has to be able to do a kickstart install, so all I
need is a minimal.ks kickstart file to perform essentially an unattended
install of a minimal build into the target rootfs.  That's where I'm at
now, trying to get that to work.

But it's all that work just to replace those few lines of code above
where you can not perform a host native install of the rootfs.  That's
all that's standing in the way and it's frustratingly close for the
Fedora template.

We've got the following distro templates in the project, currently:

lxc-alpine
lxc-alt
lxc-arch
l

Re: [lxc-devel] [Lxc-users] Working LXC templates?

2013-09-09 Thread Michael H. Warfield
On Mon, 2013-09-09 at 17:23 +0530, Shridhar Daithankar wrote: 
> On Monday, September 09, 2013 07:28:43 AM Michael H. Warfield wrote:
> > In the git-stage current Fedora template, the entire problem is embodied
> > in the "download_fedora" function starting around line 201...  The
> > gotcha's are three commands around line 272 after we've identified and
> > downloaded the initial release rpm.  We have this:
> > 
> > mkdir -p $INSTALL_ROOT/var/lib/rpm
> > rpm --root $INSTALL_ROOT  --initdb
> > rpm --root $INSTALL_ROOT -ivh ${INSTALL_ROOT}/${RELEASE_RPM}
> > $YUM install $PKG_LIST
> > 
> > Ok...  Those are running in the host local run time environment.
> > Obviously, if the host does not have a (compatible) version of rpm
> > and/or yum in the host local environment, you're screwed.  That's the
> > catch-22 situation and it's the same situation with zypper in the
> > OpenSuse template.  That short space of code has to be recreated in a
> > totally distro-agnostic manner so it runs on any distro to create our
> > initial rootfs.  After that, we can do what ever distro (Fedora)
> > specific commands we want by chrooting into the target container first
> > (including rebuilding the rpm database to the target version).  That's
> > only even needed if you don't already have a cached rootfs for that
> > distro and version.

> Another approach could be to popularize the container downloads by the 
> distro. 
> If each distro. could add a .tar.gz for a working container of a given 
> release, one could just download and configure them, no?

> then the lxc project upstream, could just list those links or include them in 
> the a separate tool, that just downloads and untars the same?

> That would completely sidestep the bootstrapping one-distro.-on-another 
> problem.

True, and that's been mentioned before in several different contexts.
The problem is that we have to get the cooperation of ALL the distros we
wish to support, which seems to be a bit of an intractable problem.  In
Fedora, it would require someone to take that on as a project and be the
maintainer.  It would also have to be architected into the build system
so it would be automatically build when a release it cut.

Since they already have the squashfs LiveOS system (which is 95% of what
we need), I don't think it would be a major leap for them to add a
parallel build to build an LXC LiveOS to live, say, in the same download
directory.  In fact, if they fixed some of the deficiencies in the
LiveOS image, we could work directly from the squashfs image that's
already there.

The problem is in getting someone interested (I'm not a Fedora
maintainer) and getting them to do it.  It would probably have to be
filled as an enhancement request and go through the months long vetting
process at best.  We might have a better shot (in this case) of filing a
bug report in bugzilla for the busted components of the LiveOS image and
getting them to fix it.  Even there, though, it's likely impossible to
get them to retroactively fix any of the previous images.

I agree it would work, I just don't think we can depend on getting
everyone else to agree to it and implement it in their distros.

Considering the direction Fedora has been taking in recent decisions
(removing sendmail / any MTA as well as the syslog server from the base
install) makes me seriously question if they would even care. 

> -- 
> Regards
>  Shridhar

Regards,
Mike
-- 
Michael H. Warfield (AI4NB) | (770) 985-6132 |  m...@wittsend.com
   /\/\|=mhw=|\/\/  | (678) 463-0932 |  http://www.wittsend.com/mhw/
   NIC whois: MHW9  | An optimist believes we live in the best of all
 PGP Key: 0x674627FF| possible worlds.  A pessimist is sure of it!


signature.asc
Description: This is a digitally signed message part
--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [Lxc-users] Working LXC templates?

2013-09-09 Thread Shridhar Daithankar
On Monday, September 09, 2013 07:28:43 AM Michael H. Warfield wrote:
> In the git-stage current Fedora template, the entire problem is embodied
> in the "download_fedora" function starting around line 201...  The
> gotcha's are three commands around line 272 after we've identified and
> downloaded the initial release rpm.  We have this:
> 
> mkdir -p $INSTALL_ROOT/var/lib/rpm
> rpm --root $INSTALL_ROOT  --initdb
> rpm --root $INSTALL_ROOT -ivh ${INSTALL_ROOT}/${RELEASE_RPM}
> $YUM install $PKG_LIST
> 
> Ok...  Those are running in the host local run time environment.
> Obviously, if the host does not have a (compatible) version of rpm
> and/or yum in the host local environment, you're screwed.  That's the
> catch-22 situation and it's the same situation with zypper in the
> OpenSuse template.  That short space of code has to be recreated in a
> totally distro-agnostic manner so it runs on any distro to create our
> initial rootfs.  After that, we can do what ever distro (Fedora)
> specific commands we want by chrooting into the target container first
> (including rebuilding the rpm database to the target version).  That's
> only even needed if you don't already have a cached rootfs for that
> distro and version.

Another approach could be to popularize the container downloads by the distro. 
If each distro. could add a .tar.gz for a working container of a given 
release, one could just download and configure them, no?

then the lxc project upstream, could just list those links or include them in 
the a separate tool, that just downloads and untars the same?

That would completely sidestep the bootstrapping one-distro.-on-another 
problem.


-- 
Regards
 Shridhar

--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [Lxc-users] Working LXC templates?

2013-09-09 Thread Tony Su
Hello Michael,

Yes, I would really appreciate your comments on what I'm attempting to do.

Here is my thought process...

In general, I've found that the problems you describe are all too
common exactly because no one seems to have sat down and taken a close
look at the flow involved in creating a Container, installing the OS
from scratch like any other install instead of using pre-built
bootstrap file systems.

The problem has been exaccerbated by using templates which are
literally spaghetti code with little organization. When code like that
works, no one can modify the code because no one can reasonably see
what the consequences are and things will break without seeming rhyme
or reason.

This is why after looking at each template script, I'm choosing to
build on the Fedora template. Although it's broken several ways, I
admire its modularity and organization.so it should be a good
foundation.

I had considered something similar to what you're describing you are
building but decided against it because as I described eariler... If
you require a whole new set of tools (even cross platform) then it's
something else that needs to be maintained which I'd think should be
unnecessary. But, if someone decided to go down this path, then I
strongly considered using a standardized, cross platform packaging
system like Ruby.

But, as I said eariler, given a preference I would rather not require
installing new applications which largely duplicate what is already
available and likely installed in each distro when the problem is
mainly one of , not missing functionality.



Without the bits of early code, this(following, below) is the
organization and structure of my proposed script...
I'm also still looking at the best cross-platform/cross-packaging way
to download the initial bootstrap packages, the fedora template
invokes pycurl. Still investigating whether it will work everywhere
and if something else (like wget if http is supported everywhere) is
more appropriate. But, after the bootstrap packages are downloaded,
the ContainerOS' native packaging manager can be used without
installing into the HostOS.

Note that putting everything in one large script also emphasizes the
re-usability of a number of modules across all distros, both HostOS
and Container creation.



Variables which apply to any and all Containers regardless of HostOS
or ContainerOS



Within this section there will be a section for each supported distro
Probably initially this may also be the main place to specify a
desired distro version for a Container but eventually making the
script interactive could be an eventual objective
These items will largely be determined by the content of the
 section




All the code in this section utilizes packages from the HostOS repos


This is the first part that is specific to the HostOS, so unless you
want to distribute different versions of this script for each distro,
this is where the HostOS must be identified, likely by reading
/etc/os-release




Note that executing lxc-create is still in the context of the
HostOS,  which means at this stage you
can't be for instance be using package managers not supported by the
HostOS. From what I can see lxc-create most importantly sets up the
chroot.

This section also most importantly configures and downloads the
required packages into


Execute a standard network install for the target distro or
something similar
Any package managers specific to the target distro should run only
within this chroot environment










































On Mon, Sep 9, 2013 at 5:10 AM, Michael H. Warfield  wrote:
> On Mon, 2013-09-09 at 17:23 +0530, Shridhar Daithankar wrote:
>> On Monday, September 09, 2013 07:28:43 AM Michael H. Warfield wrote:
>> > In the git-stage current Fedora template, the entire problem is embodied
>> > in the "download_fedora" function starting around line 201...  The
>> > gotcha's are three commands around line 272 after we've identified and
>> > downloaded the initial release rpm.  We have this:
>> >
>> > mkdir -p $INSTALL_ROOT/var/lib/rpm
>> > rpm --root $INSTALL_ROOT  --initdb
>> > rpm --root $INSTALL_ROOT -ivh ${INSTALL_ROOT}/${RELEASE_RPM}
>> > $YUM install $PKG_LIST
>> >
>> > Ok...  Those are running in the host local run time environment.
>> > Obviously, if the host does not have a (compatible) version of rpm
>> > and/or yum in the host local environment, you're screwed.  That's the
>> > catch-22 situation and it's the same situation with zypper in the
>> > OpenSuse template.  That short space of code has to be recreated in a
>> > totally distro-agnostic manner so it runs on any distro to create our
>> > initial rootfs.  After that, we can do what ever distro (Fedora)
>> > specific commands we want by chrooting into the target container first
>> > (including rebuilding the rpm database to the target version).  That's
>> > only even needed if you don't already have a cached rootfs for that
>> 

Re: [lxc-devel] [RFC] [PATCH 0/6] Major cgroup logic rewrite

2013-09-09 Thread Christian Seiler
Hi Serge,

> Thanks, Christian.  I did need the trivial white-space-damaged patch below, 
> but
> with that it built and ran for me, both with %n and default (/lxc/%n) 
> patterns.
> This was in a nested container, I haven't tested at host level but have no
> reason to think that would fail if nested worked :)
> 
> However I didn't get occasional cgroups left behind - every cgroup was left
> behind in my case.  I'll take another look.  I am to send acks and push
> tomorrow.

I think I found the problem with that... cgroup.c line 907,
lxc_cgroup_process_info_free_and_remove should call itself recursively,
but a C&P error on my end made it call lxc_cgroup_process_info_free
instead... So only in the first hierarchy are cgroups removed properly,
in the others they aren't.

As I said, there are probably still bugs in there. ;-)

-- Christian

--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [RFC] [PATCH 0/6] Major cgroup logic rewrite

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Hi all,
> 
> As discussed previously, I've now done a major rewrite of the entire
> cgroup logic. There are now no assumptions made whatsoever when it
> comes to the cgroup mount points, the kernel information will be used
> to determine the proper locations for everything. (Only /proc is
> assumed to be working properly.)
> 
> The patch series can also be found at my github under
> 
> 
> I ended up almost completely rewriting cgroup.c to make it fit the new
> scheme. For this reason, for the last patch for cgroup.[ch] it's
> probably better to look at the new version and not the diff.
> 
> I did test the whole enchilada quite a bit, but I'm very sure that
> there are a lot more bugs in there. What does work:
> 
>  - lxc-start (and -info, -stop)
>  - Choosing $name-1, $name-2, ... as cgroup if $name is already used up
>  - lxc-attach
>  - lxc-freeze / lxc-unfreeze
>  - lxc-stop -k on a frozen container
>  - All subsystems mounted together in /sys/fs/cgroup directly
>  - All subsystems mounted into different subdirectories beneath
>/sys/fs/cgroup
>  - Although I didn't try actual nesting, on the systems with
>subsystems together in /sys/fs/cgroup I did:
>   mkdir /sys/fs/cgroup/init /foo
>   echo 1 > /sys/fs/cgroup/init/tasks
>   mount --bind /sys/fs/cgroup/init /foo
>   umount /sys/fs/cgroup
>   mount --bind /foo /sys/fs/cgroup
>   umount /foo
>And then lxc-start, which worked and correctly put the container
>in the /init/lxc/$name cgroup. This means that even with the current
>mountcgroups hook nesting should work (although as discussed before,
>the current mountcgroups logic breaks other software relying on
>cgroups [1])
> 
> Known issues:
> 
>  - Sometimes cgroup cleanup doesn't work 100%, sometimes cgroups are
>left behind. With the name collision avoidance this isn't a

Thanks, Christian.  I did need the trivial white-space-damaged patch below, but
with that it built and ran for me, both with %n and default (/lxc/%n) patterns.
This was in a nested container, I haven't tested at host level but have no
reason to think that would fail if nested worked :)

However I didn't get occasional cgroups left behind - every cgroup was left
behind in my case.  I'll take another look.  I am to send acks and push
tomorrow.

thanks,
-serge

diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 288aa2e..86d89e9 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -538,7 +538,7 @@ struct cgroup_process_info 
*lxc_cgroup_process_info_get_self(struct cgroup_meta_
 /* create a new cgroup */
 extern struct cgroup_process_info *lxc_cgroup_create(const char *name, const 
char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
 {
-   char **cgroup_path_components;
+   char **cgroup_path_components = NULL;
char **p = NULL;
char *path_so_far = NULL;
char **new_cgroup_paths = NULL;


--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [RFC] [PATCH 0/6] Major cgroup logic rewrite

2013-09-09 Thread Serge Hallyn
Quoting Serge Hallyn (serge.hal...@ubuntu.com):
> Quoting Christian Seiler (christ...@iwakd.de):
> > Hi Serge,
> > 
> > > Thanks, Christian.  I did need the trivial white-space-damaged patch 
> > > below, but
> > > with that it built and ran for me, both with %n and default (/lxc/%n) 
> > > patterns.
> > > This was in a nested container, I haven't tested at host level but have no
> > > reason to think that would fail if nested worked :)
> > > 
> > > However I didn't get occasional cgroups left behind - every cgroup was 
> > > left
> > > behind in my case.  I'll take another look.  I am to send acks and push
> > > tomorrow.
> > 
> > I think I found the problem with that... cgroup.c line 907,
> > lxc_cgroup_process_info_free_and_remove should call itself recursively,
> 
> Yup, I had just found and tested that, works for me :)
> 
> > but a C&P error on my end made it call lxc_cgroup_process_info_free
> > instead... So only in the first hierarchy are cgroups removed properly,
> > in the others they aren't.
> > 
> > As I said, there are probably still bugs in there. ;-)
> 
> I notice lxc-start is always exiting with -1 for me.  But everything
> seems to be working... i'll start looking for the cause of that.

Nm, that happens without your patchset.

--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


[lxc-devel] [PATCH 1/1] error.c: don't return error if container init signaled

2013-09-09 Thread Serge Hallyn
We log that at INFO level in case it is needed.  However, in a modern
kernel a container which was shut down using 'shutdown' will always
have been signaled with SIGINT.  Making lxc-start return an error to
reflect that seems overkill.

It's *conceivable* that someone is depending on this behavior, so I'm
sending this out for anyone to NACK, but if I hear no complaints I'll
apply.

Signed-off-by: Serge Hallyn 
---
 src/lxc/error.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/lxc/error.c b/src/lxc/error.c
index 15e6ab0..46c34bb 100644
--- a/src/lxc/error.c
+++ b/src/lxc/error.c
@@ -50,7 +50,6 @@ extern int  lxc_error_set_and_log(int pid, int status)
 
if (WIFSIGNALED(status)) {
int signal = WTERMSIG(status);
-   ret = ret + 128 + signal;
 
INFO("child <%d> ended on signal (%d)", pid, signal);
}
-- 
1.8.3.2


--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [RFC] [PATCH 0/6] Major cgroup logic rewrite

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Hi Serge,
> 
> > Thanks, Christian.  I did need the trivial white-space-damaged patch below, 
> > but
> > with that it built and ran for me, both with %n and default (/lxc/%n) 
> > patterns.
> > This was in a nested container, I haven't tested at host level but have no
> > reason to think that would fail if nested worked :)
> > 
> > However I didn't get occasional cgroups left behind - every cgroup was left
> > behind in my case.  I'll take another look.  I am to send acks and push
> > tomorrow.
> 
> I think I found the problem with that... cgroup.c line 907,
> lxc_cgroup_process_info_free_and_remove should call itself recursively,

Yup, I had just found and tested that, works for me :)

> but a C&P error on my end made it call lxc_cgroup_process_info_free
> instead... So only in the first hierarchy are cgroups removed properly,
> in the others they aren't.
> 
> As I said, there are probably still bugs in there. ;-)

I notice lxc-start is always exiting with -1 for me.  But everything
seems to be working... i'll start looking for the cause of that.

--
Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
Discover the easy way to master current and previous Microsoft technologies
and advance your career. Get an incredible 1,500+ hours of step-by-step
tutorial videos with LearnDevNow. Subscribe today and save!
http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [PATCH 1/6] global config: Unify parsing, add additional checks

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Instead of duplicating the code for parsing the global config file for
> each option, write one main function, lxc_global_config_value, that
> does the parsing for an arbitrary option name and just call that
> function from the existing ones.
> 
> Signed-off-by: Christian Seiler 

Acked-by: Serge E. Hallyn 

> ---
>  src/lxc/utils.c |  137 
> ---
>  src/lxc/utils.h |6 ++-
>  2 files changed, 63 insertions(+), 80 deletions(-)
> 
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index 9a7a41d..fd892c1 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -198,7 +198,7 @@ extern int mkdir_p(const char *dir, mode_t mode)
>   return 0;
>  }
>  
> -static char *copypath(char *p)
> +static char *copy_global_config_value(char *p)
>  {
>   int len = strlen(p);
>   char *retbuf;
> @@ -216,116 +216,97 @@ static char *copypath(char *p)
>   return retbuf;
>  }
>  
> -char *default_lxcpath;
>  #define DEFAULT_VG "lxc"
> -char *default_lvmvg;
>  #define DEFAULT_ZFSROOT "lxc"
> -char *default_zfsroot;
>  
> -const char *default_lvm_vg(void)
> +const char *lxc_global_config_value(const char *option_name)
>  {
> - char buf[1024], *p;
> - FILE *fin;
> -
> - if (default_lvmvg)
> - return default_lvmvg;
> + static const char *options[][2] = {
> + { "lvm_vg",  DEFAULT_VG  },
> + { "zfsroot", DEFAULT_ZFSROOT },
> + { "lxcpath", LXCPATH },
> + { NULL, NULL },
> + };
> + static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
> + const char *(*ptr)[2];
> + size_t i;
> + char buf[1024], *p, *p2;
> + FILE *fin = NULL;
> +
> + for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
> + if (!strcmp(option_name, (*ptr)[0]))
> + break;
> + }
> + if (!(*ptr)[0]) {
> + errno = EINVAL;
> + return NULL;
> + }
> + if (values[i])
> + return values[i];
>  
>   fin = fopen(LXC_GLOBAL_CONF, "r");
>   if (fin) {
>   while (fgets(buf, 1024, fin)) {
>   if (buf[0] == '#')
>   continue;
> - p = strstr(buf, "lvm_vg");
> + p = strstr(buf, option_name);
>   if (!p)
>   continue;
> + /* see if there was just white space in front
> +  * of the option name
> +  */
> + for (p2 = buf; p2 < p; p2++) {
> + if (*p2 != ' ' && *p2 != '\t')
> + break;
> + }
> + if (p2 < p)
> + continue;
>   p = strchr(p, '=');
>   if (!p)
>   continue;
> + /* see if there was just white space after
> +  * the option name
> +  */
> + for (p2 += strlen(option_name); p2 < p; p2++) {
> + if (*p2 != ' ' && *p2 != '\t')
> + break;
> + }
> + if (p2 < p)
> + continue;
>   p++;
>   while (*p && (*p == ' ' || *p == '\t')) p++;
>   if (!*p)
>   continue;
> - default_lvmvg = copypath(p);
> + values[i] = copy_global_config_value(p);
>   goto out;
>   }
>   }
> - default_lvmvg = DEFAULT_VG;
> + /* could not find value, use default */
> + values[i] = (*ptr)[1];
> + /* special case: if default value is NULL,
> +  * and there is no config, don't view that
> +  * as an error... */
> + if (!values[i])
> + errno = 0;
>  
>  out:
>   if (fin)
>   fclose(fin);
> - return default_lvmvg;
> + return values[i];
>  }
>  
> -const char *default_zfs_root(void)
> +const char *default_lvm_vg(void)
>  {
> - char buf[1024], *p;
> - FILE *fin;
> -
> - if (default_zfsroot)
> - return default_zfsroot;
> -
> - fin = fopen(LXC_GLOBAL_CONF, "r");
> - if (fin) {
> - while (fgets(buf, 1024, fin)) {
> - if (buf[0] == '#')
> - continue;
> - p = strstr(buf, "zfsroot");
> - if (!p)
> - continue;
> - p = strchr(p, '=');
> - if (!p)
> - continue;
> - p++;
> - while (*p && (*p == ' ' || *p == '\t')) p++;
> - if (!*p)
> -   

Re: [lxc-devel] [PATCH 2/6] Add cgroup.pattern global configuration option

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Signed-off-by: Christian Seiler 

Acked-by: Serge E. Hallyn 

> ---
>  configure.ac|7 +++
>  src/lxc/Makefile.am |3 ++-
>  src/lxc/utils.c |1 +
>  3 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/configure.ac b/configure.ac
> index 4eaf329..f0f417c 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -260,6 +260,12 @@ AC_ARG_WITH([rootfs-path],
>   [--with-rootfs-path=dir],
>   [lxc rootfs mount point]
>   )], [], [with_rootfs_path=['${libdir}/lxc/rootfs']])
> +# cgroup pattern specification
> +AC_ARG_WITH([cgroup-pattern],
> + [AC_HELP_STRING(
> + [--with-cgroup-pattern=pattern],
> + [pattern for container cgroups]
> + )], [], [with_cgroup_pattern=['/lxc/%n']])
>  
>  # Container log path.  By default, use $lxcpath.
>  AC_MSG_CHECKING([Whether to place logfiles in container config path])
> @@ -303,6 +309,7 @@ AS_AC_EXPAND(LXCTEMPLATEDIR, "$datadir/lxc/templates")
>  AS_AC_EXPAND(LXCHOOKDIR, "$datadir/lxc/hooks")
>  AS_AC_EXPAND(LXCINITDIR, "$libexecdir")
>  AS_AC_EXPAND(LOGPATH, "$with_log_path")
> +AC_SUBST(DEFAULT_CGROUP_PATTERN, ["$with_cgroup_pattern"])
>  
>  # Check for some standard kernel headers
>  AC_CHECK_HEADERS([linux/unistd.h linux/netlink.h linux/genetlink.h],
> diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> index da5ff15..8ee279f 100644
> --- a/src/lxc/Makefile.am
> +++ b/src/lxc/Makefile.am
> @@ -100,7 +100,8 @@ AM_CFLAGS=-I$(top_srcdir)/src \
>   -DLOGPATH=\"$(LOGPATH)\" \
>   -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \
>   -DLXC_USERNIC_DB=\"$(LXC_USERNIC_DB)\" \
> - -DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\"
> + -DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\" \
> + -DDEFAULT_CGROUP_PATTERN=\"$(DEFAULT_CGROUP_PATTERN)\"
>  
>  if ENABLE_APPARMOR
>  AM_CFLAGS += -DHAVE_APPARMOR
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index fd892c1..36d80b9 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -225,6 +225,7 @@ const char *lxc_global_config_value(const char 
> *option_name)
>   { "lvm_vg",  DEFAULT_VG  },
>   { "zfsroot", DEFAULT_ZFSROOT },
>   { "lxcpath", LXCPATH },
> + { "cgroup.pattern",  DEFAULT_CGROUP_PATTERN },
>   { NULL, NULL },
>   };
>   static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
> -- 
> 1.7.10.4
> 
> 
> --
> Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
> Discover the easy way to master current and previous Microsoft technologies
> and advance your career. Get an incredible 1,500+ hours of step-by-step
> tutorial videos with LearnDevNow. Subscribe today and save!
> http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
> ___
> Lxc-devel mailing list
> Lxc-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

--
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=5127&iu=/4140/ostg.clktrk
___
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel


Re: [lxc-devel] [PATCH 3/6] Add fopen_cloexec function to emulate 'e' mode

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Newer glibc versions (that we can't require) allow for an additional
> letter 'e' in the fopen mode that will cause the file to be opened with
> the O_CLOEXEC flag, so that it will be closed if the program exec()s
> away. This is important because if liblxc is used in a multithreaded
> program, another thread might want to run a program. This options
> prevents the leakage of file descriptors from LXC. This patch adds an
> emulation for that that uses the open(2) syscall and fdopen(3). At some
> later point in time, it may be dropped against fopen(..., "...e").
> 
> This commit also converts all fopen() calls in utils.c (where the
> function is added) to fopen_cloexec(). Subsequently, other calls to
> fopen() and open() should also be adapted.
> 
> Signed-off-by: Christian Seiler 

Acked-by: Serge E. Hallyn 

Though the special case for calling open() without a mode arg seems
unnecessary since when called without O_CREAT, mode is supposed to be
ignored.

> ---
>  src/lxc/utils.c |   50 --
>  src/lxc/utils.h |3 +++
>  2 files changed, 51 insertions(+), 2 deletions(-)
> 
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index 36d80b9..b188c47 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -245,7 +245,7 @@ const char *lxc_global_config_value(const char 
> *option_name)
>   if (values[i])
>   return values[i];
>  
> - fin = fopen(LXC_GLOBAL_CONF, "r");
> + fin = fopen_cloexec(LXC_GLOBAL_CONF, "r");
>   if (fin) {
>   while (fgets(buf, 1024, fin)) {
>   if (buf[0] == '#')
> @@ -391,7 +391,7 @@ int sha1sum_file(char *fnam, unsigned char *digest)
>  
>   if (!fnam)
>   return -1;
> - if ((f = fopen(fnam, "r")) < 0) {
> + if ((f = fopen_cloexec(fnam, "r")) < 0) {
>   SYSERROR("Error opening template");
>   return -1;
>   }
> @@ -477,3 +477,49 @@ const char** lxc_va_arg_list_to_argv_const(va_list ap, 
> size_t skip)
>  {
>   return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
>  }
> +
> +FILE *fopen_cloexec(const char *path, const char *mode)
> +{
> + int open_mode = 0;
> + int step = 0;
> + int fd;
> + int saved_errno = 0;
> + FILE *ret;
> +
> + if (!strncmp(mode, "r+", 2)) {
> + open_mode = O_RDWR;
> + step = 2;
> + } else if (!strncmp(mode, "r", 1)) {
> + open_mode = O_RDONLY;
> + step = 1;
> + } else if (!strncmp(mode, "w+", 2)) {
> + open_mode = O_RDWR | O_TRUNC | O_CREAT;
> + step = 2;
> + } else if (!strncmp(mode, "w", 1)) {
> + open_mode = O_WRONLY | O_TRUNC | O_CREAT;
> + step = 1;
> + } else if (!strncmp(mode, "a+", 2)) {
> + open_mode = O_RDWR | O_CREAT | O_APPEND;
> + step = 2;
> + } else if (!strncmp(mode, "a", 1)) {
> + open_mode = O_WRONLY | O_CREAT | O_APPEND;
> + step = 1;
> + }
> + for (; mode[step]; step++)
> + if (mode[step] == 'x')
> + open_mode |= O_EXCL;
> + open_mode |= O_CLOEXEC;
> +
> + fd = (open_mode & O_CREAT) ?
> + open(path, open_mode, 0666) :
> + open(path, open_mode);
> + if (fd < 0)
> + return NULL;
> +
> + ret = fdopen(fd, mode);
> + saved_errno = errno;
> + if (!ret)
> + close(fd);
> + errno = saved_errno;
> + return ret;
> +}
> diff --git a/src/lxc/utils.h b/src/lxc/utils.h
> index 0ad9505..b79be44 100644
> --- a/src/lxc/utils.h
> +++ b/src/lxc/utils.h
> @@ -148,6 +148,9 @@ static inline int signalfd(int fd, const sigset_t *mask, 
> int flags)
>  }
>  #endif
>  
> +/* open a file with O_CLOEXEC */
> +FILE *fopen_cloexec(const char *path, const char *mode);
> +
>  
>  /**
>   * BUILD_BUG_ON - break compile if a condition is true.
> -- 
> 1.7.10.4
> 
> 
> --
> Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
> Discover the easy way to master current and previous Microsoft technologies
> and advance your career. Get an incredible 1,500+ hours of step-by-step
> tutorial videos with LearnDevNow. Subscribe today and save!
> http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
> ___
> Lxc-devel mailing list
> Lxc-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

--
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=5127&iu=/4140/os

Re: [lxc-devel] [PATCH 5/6] utils: Add utility functions that write/read to entire files

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Signed-off-by: Christian Seiler 

Acked-by: Serge E. Hallyn 

but I notice that lxc_read_line_from_file() is not being used here
or later.  The function would seem more useful if it accepted a line
number to read.  Otherwise I'd suggest we drop the function.  Thoughts?

> ---
>  src/lxc/utils.c |   91 
> +++
>  src/lxc/utils.h |5 +++
>  2 files changed, 96 insertions(+)
> 
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index dc98443..02336d7 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -39,6 +39,12 @@
>  #include 
>  #include 
>  
> +#ifndef HAVE_GETLINE
> +#ifdef HAVE_FGETLN
> +#include <../include/getline.h>
> +#endif
> +#endif
> +
>  #include "utils.h"
>  #include "log.h"
>  
> @@ -807,3 +813,88 @@ void **lxc_dup_array(void **array, lxc_dup_fn 
> element_dup_fn, lxc_free_fn elemen
>  
>   return result;
>  }
> +
> +int lxc_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 = lxc_write_nointr(fd, buf, count);
> + if (ret < 0)
> + goto out_error; 
> + if ((size_t)ret != count)
> + goto out_error;
> + if (add_newline) {
> + ret = lxc_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;
> +}
> +
> +int lxc_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)
> + ERROR("read %s: %s", filename, strerror(errno));
> +
> + saved_errno = errno;
> + close(fd);
> + errno = saved_errno;
> + return ret;
> +}
> +
> +char *lxc_read_line_from_file(const char *filename)
> +{
> + FILE *f;
> + char *line = NULL;
> + int saved_errno;
> + size_t sz = 0;
> +
> + f = fopen_cloexec(filename, "r");
> + if (!f)
> + return NULL;
> +
> + if (getline(&line, &sz, f) == -1) {
> + saved_errno = errno;
> + fclose(f);
> + errno = saved_errno;
> + return NULL;
> + }
> +
> + fclose(f);
> +
> + /* trim line, if necessary */
> + if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
> + line[strlen(line) - 1] = '\0';
> +
> + return line;
> +}
> diff --git a/src/lxc/utils.h b/src/lxc/utils.h
> index 7261846..4c2ab29 100644
> --- a/src/lxc/utils.h
> +++ b/src/lxc/utils.h
> @@ -194,6 +194,11 @@ extern ssize_t lxc_read_nointr_expect(int fd, void* buf, 
> size_t count, const voi
>  extern int sha1sum_file(char *fnam, unsigned char *md_value);
>  #endif
>  
> +/* read and write whole files */
> +extern int lxc_write_to_file(const char *filename, const void* buf, size_t 
> count, bool add_newline);
> +extern int lxc_read_from_file(const char *filename, void* buf, size_t count);
> +extern char *lxc_read_line_from_file(const char *filename);
> +
>  /* convert variadic argument lists to arrays (for execl type argument lists) 
> */
>  extern char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int 
> do_strdup);
>  extern const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip);
> -- 
> 1.7.10.4
> 
> 
> --
> Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more!
> Discover the easy way to master current and previous Microsoft technologies
> and advance your career. Get an incredible 1,500+ hours of step-by-step
> tutorial videos with LearnDevNow. Subscribe today and save!
> http://pubads.g.doubleclick.net/gampad/clk?id=58041391&iu=/4140/ostg.clktrk
> ___
> Lxc-devel mailing list
> Lxc-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

--
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http

Re: [lxc-devel] [PATCH 4/6] utils: Add string and array utility functions

2013-09-09 Thread Serge Hallyn
Quoting Christian Seiler (christ...@iwakd.de):
> Adds a few useful string and array manipulation functions to utils.[ch]
> 
> Signed-off-by: Christian Seiler 

Acked-by: Serge E. Hallyn 

However, a comment about
+/* Normalize and split path: Leading and trailing / are removed, multiple
+ * / are compactified, .. and . are resolved (.. on the top level is considered
+ * identical to .).
+ * Examples:
+ * /->   { NULL }
+ * foo/../bar   ->   { bar, NULL }
+ * ../../   ->   { NULL }
+ * ./bar/baz/.. ->   { bar, NULL }
+ * foo//bar ->   { foo, bar, NULL }
+ */
+extern char **lxc_normalize_path(const char *path);

That's fine for what you're doing with cgroup paths, but given the
function name people might want to start using it for general pathnames.
If they do, they'll need to separately check path[0] to determine
whether the normalized path was absolute or not.

Maybe the comment you have here is clear enough to warn anyone against
getting confused...  I'm just a bit worried it could bite us later.

> ---
>  src/lxc/utils.c |  284 
> +++
>  src/lxc/utils.h |   32 +++
>  2 files changed, 316 insertions(+)
> 
> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
> index b188c47..dc98443 100644
> --- a/src/lxc/utils.c
> +++ b/src/lxc/utils.c
> @@ -37,6 +37,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include "utils.h"
>  #include "log.h"
> @@ -523,3 +524,286 @@ FILE *fopen_cloexec(const char *path, const char *mode)
>   errno = saved_errno;
>   return ret;
>  }
> +
> +char *lxc_string_replace(const char *needle, const char *replacement, const 
> char *haystack)
> +{
> + ssize_t len = -1, saved_len = -1;
> + char *result = NULL;
> + size_t replacement_len = strlen(replacement);
> + size_t needle_len = strlen(needle);
> +
> + /* should be executed exactly twice */
> + while (len == -1 || result == NULL) {
> + char *p;
> + char *last_p;
> + ssize_t part_len;
> +
> + if (len != -1) {
> + result = calloc(1, len + 1);
> + if (!result)
> + return NULL;
> + saved_len = len;
> + }
> +
> + len = 0;
> +
> + for (last_p = (char *)haystack, p = strstr(last_p, needle); p; 
> last_p = p, p = strstr(last_p, needle)) {
> + part_len = (ssize_t)(p - last_p);
> + if (result && part_len > 0)
> + memcpy(&result[len], last_p, part_len);
> + len += part_len;
> + if (result && replacement_len > 0)
> + memcpy(&result[len], replacement, 
> replacement_len);
> + len += replacement_len;
> + p += needle_len;
> + }
> + part_len = strlen(last_p);
> + if (result && part_len > 0)
> + memcpy(&result[len], last_p, part_len);
> + len += part_len;
> + }
> +
> + /* make sure we did the same thing twice,
> +  * once for calculating length, the other
> +  * time for copying data */
> + assert(saved_len == len);
> + /* make sure we didn't overwrite any buffer,
> +  * due to calloc the string should be 0-terminated */
> + assert(result[len] == '\0');
> +
> + return result;
> +}
> +
> +bool lxc_string_in_array(const char *needle, const char **haystack)
> +{
> + for (; haystack && *haystack; haystack++)
> + if (!strcmp(needle, *haystack))
> + return true;
> + return false;
> +}
> +
> +char *lxc_string_join(const char *sep, const char **parts, bool 
> use_as_prefix)
> +{
> + char *result;
> + char **p;
> + size_t sep_len = strlen(sep);
> + size_t result_len = use_as_prefix * sep_len;
> +
> + /* calculate new string length */
> + for (p = (char **)parts; *p; p++)
> + result_len += (p > (char **)parts) * sep_len + strlen(*p);
> +
> + result = calloc(result_len + 1, 1);
> + if (!result)
> + return NULL;
> +
> + if (use_as_prefix)
> + strcpy(result, sep);
> + for (p = (char **)parts; *p; p++) {
> + if (p > (char **)parts)
> + strcat(result, sep);
> + strcat(result, *p);
> + }
> +
> + return result;
> +}
> +
> +char **lxc_normalize_path(const char *path)
> +{
> + char **components;
> + char **p;
> + size_t components_len = 0;
> + size_t pos = 0;
> +
> + components = lxc_string_split(path, '/');
> + if (!components)
> + return NULL;
> + for (p = components; *p; p++)
> + components_len++;
> +
> + /* resolve '.' and '..' */
> + for (pos = 0; pos < components_len; ) {
> + if (!strcmp(components[pos], ".") || (!strcmp(components[pos], 
> "..") &&