<feed xmlns='http://www.w3.org/2005/Atom'>
<title>src/lib/libbe/be_access.c, branch releng/12.2</title>
<subtitle>FreeBSD source tree</subtitle>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/'/>
<entry>
<title>MFC r357067: Drop "All Rights Reserved" from all libbe/bectl files</title>
<updated>2020-02-07T21:57:27+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2020-02-07T21:57:27+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=1d1ed1a5d73fd91fb6dfbd4dda0ae2f22593c9cf'/>
<id>1d1ed1a5d73fd91fb6dfbd4dda0ae2f22593c9cf</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r356876-r356877: add zfs_mount_at</title>
<updated>2020-01-22T22:51:55+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2020-01-22T22:51:55+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=ea3031df6333f509fc51940e0d53c00fe694b39d'/>
<id>ea3031df6333f509fc51940e0d53c00fe694b39d</id>
<content type='text'>
r356876:
libzfs: add zfs_mount_at

This will be used in libbe in place of the internal zmount(); libbe only
wants to be able to mount a dataset at an arbitrary mountpoint without
altering dataset/pool properties. The natural way to do this in a portable
way is by creating a zfs_mount_at() interface that's effectively zfs_mount()
+ a mountpoint parameter. zfs_mount() is now a light wrapper around the new
method.

The interface and implementation have already been accepted into ZFS On
Linux, and the next commit to switch libbe() over to this new interface will
solve the last compatibility issue with ZoL.  The next sysutils/openzfs
rebase against ZoL should be able to build libbe/bectl with only minor
adjustments to build glue.

r356877:
libbe: use the new zfs_mount_at()

More background is available in r356876, but this new interface is more
portable across ZFS implementations and cleaner for what libbe is attempting
to achieve anyways.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
r356876:
libzfs: add zfs_mount_at

This will be used in libbe in place of the internal zmount(); libbe only
wants to be able to mount a dataset at an arbitrary mountpoint without
altering dataset/pool properties. The natural way to do this in a portable
way is by creating a zfs_mount_at() interface that's effectively zfs_mount()
+ a mountpoint parameter. zfs_mount() is now a light wrapper around the new
method.

The interface and implementation have already been accepted into ZFS On
Linux, and the next commit to switch libbe() over to this new interface will
solve the last compatibility issue with ZoL.  The next sysutils/openzfs
rebase against ZoL should be able to build libbe/bectl with only minor
adjustments to build glue.

r356877:
libbe: use the new zfs_mount_at()

More background is available in r356876, but this new interface is more
portable across ZFS implementations and cleaner for what libbe is attempting
to achieve anyways.
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r355460: libbe: fix build against sysutils/openzfs, part 1</title>
<updated>2019-12-12T18:53:45+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2019-12-12T18:53:45+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=90681a6fdc6fa80b64e14f8f8891e65d82fcd512'/>
<id>90681a6fdc6fa80b64e14f8f8891e65d82fcd512</id>
<content type='text'>
This is the half of the changes required that work as-is with both in-tree
ZFS and the new hotness, sysutils/openzfs.  Highlights are less dependency
on header pollution (from somewhere) and using 'mnttab' instead of
'extmnttab'.   In the in-tree ZFS, the latter is a #define for the former,
but in the port extmnttab is actually a distinct struct that's a super-set
of mnttab.  We really want mnttab here anyways, so just use it.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This is the half of the changes required that work as-is with both in-tree
ZFS and the new hotness, sysutils/openzfs.  Highlights are less dependency
on header pollution (from somewhere) and using 'mnttab' instead of
'extmnttab'.   In the in-tree ZFS, the latter is a #define for the former,
but in the port extmnttab is actually a distinct struct that's a super-set
of mnttab.  We really want mnttab here anyways, so just use it.
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r349380, r349383, r349455: bectl(8)/libbe(3) fixes</title>
<updated>2019-07-26T01:49:58+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2019-07-26T01:49:58+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=686d5664a4ef7888aa499bf8e9fb58c800cd437a'/>
<id>686d5664a4ef7888aa499bf8e9fb58c800cd437a</id>
<content type='text'>
r349380:
libbe(3): mount: the BE dataset is mounted at /

Other parts of libbe(3) were fairly strict on the mountpoint property of the
BE dataset, and be_mount was not much better. It was improved in r347027 to
allow mountpoint=none for depth==0, but this bit was still sensitive to
mountpoint != / and mountpoint != none. Given that other parts of libbe(3)
no longer restrict the mountpoint property here, and the rest of the base
system is generally OK and will assume that a BE is mounted at /, let's do
the same.

r349383:
libbe(3): restructure be_mount, skip canmount check for BE dataset

Further cleanup after r349380; loader and kernel will both ignore canmount
on the root dataset as well, so we should not be so strict about it when
mounting it. be_mount is restructured to make it more clear that depth==0 is
special, and to not try fetching these properties that we won't care about.

r349455:
bectl(8): create non-recursive boot environments

bectl advertises that it has the ability to create recursive and
non-recursive boot environments. This patch implements that functionality
using the be_create_depth API provided by libbe. With this patch, bectl now
works as bectl(8) describes in regards to creating recursive/non-recursive
boot environments.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
r349380:
libbe(3): mount: the BE dataset is mounted at /

Other parts of libbe(3) were fairly strict on the mountpoint property of the
BE dataset, and be_mount was not much better. It was improved in r347027 to
allow mountpoint=none for depth==0, but this bit was still sensitive to
mountpoint != / and mountpoint != none. Given that other parts of libbe(3)
no longer restrict the mountpoint property here, and the rest of the base
system is generally OK and will assume that a BE is mounted at /, let's do
the same.

r349383:
libbe(3): restructure be_mount, skip canmount check for BE dataset

Further cleanup after r349380; loader and kernel will both ignore canmount
on the root dataset as well, so we should not be so strict about it when
mounting it. be_mount is restructured to make it more clear that depth==0 is
special, and to not try fetching these properties that we won't care about.

r349455:
bectl(8): create non-recursive boot environments

bectl advertises that it has the ability to create recursive and
non-recursive boot environments. This patch implements that functionality
using the be_create_depth API provided by libbe. With this patch, bectl now
works as bectl(8) describes in regards to creating recursive/non-recursive
boot environments.
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r347640: libbe(3): Descend into children of datasets w/ mountpoint=none</title>
<updated>2019-05-22T22:55:27+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2019-05-22T22:55:27+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=ba24448aee928421c5e69285647c848e0d37e115'/>
<id>ba24448aee928421c5e69285647c848e0d37e115</id>
<content type='text'>
These datasets will generally be canmount=noauto,mountpoint=none (e.g.
zroot/var) but have children that may need to be mounted. Instead of
skipping that segment for no good reason, descend.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
These datasets will generally be canmount=noauto,mountpoint=none (e.g.
zroot/var) but have children that may need to be mounted. Instead of
skipping that segment for no good reason, descend.
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r347027-r347028: libbe(3) mountpoint handling fixes</title>
<updated>2019-05-06T02:10:04+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2019-05-06T02:10:04+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=1b33ee4e2a8d2e95cae348186282b1b7ba0198f0'/>
<id>1b33ee4e2a8d2e95cae348186282b1b7ba0198f0</id>
<content type='text'>
r347027:
libbe(3): Properly mount BEs with mountpoint=none

Instead of pretending to successfully mount them while not actually
mounting anything, we'll now actually mount them *and* claim we mounted them
successfully.

Reported by:	ler

r347028:
libbe: set mountpoint=none in be_import

If we're going to set a mountpoint at all, mountpoint=none makes more sense
than mountpoint=/.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
r347027:
libbe(3): Properly mount BEs with mountpoint=none

Instead of pretending to successfully mount them while not actually
mounting anything, we'll now actually mount them *and* claim we mounted them
successfully.

Reported by:	ler

r347028:
libbe: set mountpoint=none in be_import

If we're going to set a mountpoint at all, mountpoint=none makes more sense
than mountpoint=/.
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r342903, r342911: libbe(3)/bectl(8) refactor and fix mount for deep BEs</title>
<updated>2019-01-21T02:57:57+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2019-01-21T02:57:57+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=33ae5285c5f6b1124cc40a18cda5a62a239ef29a'/>
<id>33ae5285c5f6b1124cc40a18cda5a62a239ef29a</id>
<content type='text'>
r342903: libbe(3): move altroot augmentation bits around a little bit

We could perhaps have a method that does this given a dataset, but it's yet
clear that we'll always want to bypass the altroot when we grab the
mountpoint. For now, we'll refactor things a bit so we grab the altroot
length when libbe is initialized and have a common method that does the
necessary augmentation (replace with / if it's the root, return a pointer to
later in the string if not).

This will be used in some upcoming work to make be_mount work properly for
deep BEs.

r342911: libbe(3): Change be_mount to mount/unmount child datasets

This set of changes is geared towards making bectl respect deep boot
environments when they exist and are mounted. The deep BE composition
functionality (`bectl add`) remains disabled for the time being. This set of
changes has no effect for the average user. but allows deep BE users to
upgrade properly with their current setup.

libbe(3): Open the target boot environment and get a zfs handle, then pass
that with the target mountpoint to be_mount_iter; If the BE_MNT_DEEP flag is
set call zfs_iter_filesystems and mount the child datasets.

Similar logic is employed when unmounting the datasets, save for children
are unmounted first.

bectl(8): Change bectl_cmd_jail to pass the BE_MNT_DEEP flag when
calling be_mount as well as call be_unmount when cleaning up after the
jail has exited instead of umount(2) directly.

PR:		234795
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
r342903: libbe(3): move altroot augmentation bits around a little bit

We could perhaps have a method that does this given a dataset, but it's yet
clear that we'll always want to bypass the altroot when we grab the
mountpoint. For now, we'll refactor things a bit so we grab the altroot
length when libbe is initialized and have a common method that does the
necessary augmentation (replace with / if it's the root, return a pointer to
later in the string if not).

This will be used in some upcoming work to make be_mount work properly for
deep BEs.

r342911: libbe(3): Change be_mount to mount/unmount child datasets

This set of changes is geared towards making bectl respect deep boot
environments when they exist and are mounted. The deep BE composition
functionality (`bectl add`) remains disabled for the time being. This set of
changes has no effect for the average user. but allows deep BE users to
upgrade properly with their current setup.

libbe(3): Open the target boot environment and get a zfs handle, then pass
that with the target mountpoint to be_mount_iter; If the BE_MNT_DEEP flag is
set call zfs_iter_filesystems and mount the child datasets.

Similar logic is employed when unmounting the datasets, save for children
are unmounted first.

bectl(8): Change bectl_cmd_jail to pass the BE_MNT_DEEP flag when
calling be_mount as well as call be_unmount when cleaning up after the
jail has exited instead of umount(2) directly.

PR:		234795
</pre>
</div>
</content>
</entry>
<entry>
<title>MFC r340507-r340508, r340592-r340594, r340635-r340636: bectl(8) fixes</title>
<updated>2018-11-22T01:25:44+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2018-11-22T01:25:44+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=fa6c19ac9a2137471c4f07ccb2e8995924c8a61b'/>
<id>fa6c19ac9a2137471c4f07ccb2e8995924c8a61b</id>
<content type='text'>
r340507:
libbe(3): rewrite init to support chroot usage

libbe(3) currently uses zfs_be_root and locates which of its children is
currently mounted at "/". This is reasonable, but not correct in the case of
a chroot, for two reasons:

- chroot root may be of a different zpool than zfs_be_root
- chroot root will not show up as mounted at "/"

Fix both of these by rewriting libbe_init to work from the rootfs down.
zfs_path_to_zhandle on / will resolve to the dataset mounted at the new
root, rather than the real root. From there, we can derive the BE root/pool
and grab the bootfs off of the new pool. This does no harm in the average
case, and opens up bectl to operating on different pools for scenarios where
one may be, for instance, updating a pool that generally gets re-rooted into
from a separate UFS root or zfs bootpool.

While here, I've also:
- Eliminated the check for /boot and / to be on the same partition. This
  leaves one open to a setup where /boot (and consequently, kernel/modules)
  are not included in the boot environment. This may very well be an
  intentional setup done by someone that knows what they're doing, we should
  not kill BE usage because of it.

- Eliminated the validation bits of BEs and snapshots that enforced
  'mountpoint' to be "/" -- this broke when trying to operate on an imported
  pool with an altroot, but we need not be this picky.

Reported by:	philip
Reviewed by:	philip, allanjude (previous version)
Tested by:	philip
Differential Revision:	https://reviews.freebsd.org/D18012

r340508:
libbe(3): Rewrite be_unmount to stop mucking with getmntinfo(2)

Go through the ZFS layer instead; given a BE, we can derive the dataset,
zfs_open it, then zfs_unmount. ZFS takes care of the dirty details and
likely gets it more correct than we did for more interesting setups.

r340592:
bectl(3)/libbe(3): Allow BE root to be specified

Add an undocumented -r option preceding the bectl subcommand to specify a BE
root to operate out of. This will remain undocumented for now, as some
caveats apply:

- BEs cannot be activated in the pool that doesn't contain the rootfs
- bectl create cannot work out of the box without the -e option right now,
  since it defaults to the rootfs and cross-pool cloning doesn't work like
  that (IIRC)

Plumb the BE root through to libbe(3) so that some things -can- be done to
it, e.g.

bectl -r tank/ROOT create -e default upgrade
bectl -r tank/ROOT mount upgrade /mnt

this aides in some upgrade setups where rootfs is not necessarily ZFS, and
also makes it easier/possible to regression-test bectl when combined with a
file-backed zpool.

Differential Revision:	https://reviews.freebsd.org/D18029

r340593:
libbe(3): Properly account for altroot when creating new BEs

Previously we would blindly copy the 'mountpoint' property, which includes
the altroot. The altroot needs to be snipped off prior to setting it on the
new BE, though, or you'll end up with a new BE and a mountpoint of /mnt with
altroot=/mnt

r340594:
bectl(8): Add some regression tests

These tests operate on a file-backed zpool that gets created in the kyua
temp dir. root and ZFS support are both required for these tests. Current
tests cover create, destroy, export/import, jail, list (kind of), mount,
rename, and jail.

List tests should later be extended to cover formatting and the different
list flags, but for now only covers basic "are create/destroy actually
reflected properly"

r340635:
libbe(3): Handle non-ZFS rootfs better

If rootfs isn't ZFS, current version will emit an error claiming so and fail
to initialize libbe. As a consumer, bectl -r (undocumented) can be specified
to operate on a BE independently of whether on a UFS or ZFS root.

Unbreak this for the UFS case by only erroring out the init if we can't
determine a ZFS dataset for rootfs and no BE root was specified. Consumers
of libbe should take care to ensure that rootfs is non-empty if they're
trying to use it, because this could certainly be the case.

Some check is needed before zfs_path_to_zhandle because it will
unconditionally emit to stderr if the path isn't a ZFS filesystem, which is
unhelpful for our purposes.

This should also unbreak the bectl(8) tests on a UFS root, as is the case in
Jenkins' -test runs.

r340636:
bectl(8) tests: attempt to load the ZFS module

Observed in a CI test image, bectl_create test will run and be marked as
skipped because the module is not loaded. The first zpool invocation will
automagically load the module, but bectl_create is still skipped. Subsequent
tests all pass as expected because the module is now loaded and everything
is OK.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
r340507:
libbe(3): rewrite init to support chroot usage

libbe(3) currently uses zfs_be_root and locates which of its children is
currently mounted at "/". This is reasonable, but not correct in the case of
a chroot, for two reasons:

- chroot root may be of a different zpool than zfs_be_root
- chroot root will not show up as mounted at "/"

Fix both of these by rewriting libbe_init to work from the rootfs down.
zfs_path_to_zhandle on / will resolve to the dataset mounted at the new
root, rather than the real root. From there, we can derive the BE root/pool
and grab the bootfs off of the new pool. This does no harm in the average
case, and opens up bectl to operating on different pools for scenarios where
one may be, for instance, updating a pool that generally gets re-rooted into
from a separate UFS root or zfs bootpool.

While here, I've also:
- Eliminated the check for /boot and / to be on the same partition. This
  leaves one open to a setup where /boot (and consequently, kernel/modules)
  are not included in the boot environment. This may very well be an
  intentional setup done by someone that knows what they're doing, we should
  not kill BE usage because of it.

- Eliminated the validation bits of BEs and snapshots that enforced
  'mountpoint' to be "/" -- this broke when trying to operate on an imported
  pool with an altroot, but we need not be this picky.

Reported by:	philip
Reviewed by:	philip, allanjude (previous version)
Tested by:	philip
Differential Revision:	https://reviews.freebsd.org/D18012

r340508:
libbe(3): Rewrite be_unmount to stop mucking with getmntinfo(2)

Go through the ZFS layer instead; given a BE, we can derive the dataset,
zfs_open it, then zfs_unmount. ZFS takes care of the dirty details and
likely gets it more correct than we did for more interesting setups.

r340592:
bectl(3)/libbe(3): Allow BE root to be specified

Add an undocumented -r option preceding the bectl subcommand to specify a BE
root to operate out of. This will remain undocumented for now, as some
caveats apply:

- BEs cannot be activated in the pool that doesn't contain the rootfs
- bectl create cannot work out of the box without the -e option right now,
  since it defaults to the rootfs and cross-pool cloning doesn't work like
  that (IIRC)

Plumb the BE root through to libbe(3) so that some things -can- be done to
it, e.g.

bectl -r tank/ROOT create -e default upgrade
bectl -r tank/ROOT mount upgrade /mnt

this aides in some upgrade setups where rootfs is not necessarily ZFS, and
also makes it easier/possible to regression-test bectl when combined with a
file-backed zpool.

Differential Revision:	https://reviews.freebsd.org/D18029

r340593:
libbe(3): Properly account for altroot when creating new BEs

Previously we would blindly copy the 'mountpoint' property, which includes
the altroot. The altroot needs to be snipped off prior to setting it on the
new BE, though, or you'll end up with a new BE and a mountpoint of /mnt with
altroot=/mnt

r340594:
bectl(8): Add some regression tests

These tests operate on a file-backed zpool that gets created in the kyua
temp dir. root and ZFS support are both required for these tests. Current
tests cover create, destroy, export/import, jail, list (kind of), mount,
rename, and jail.

List tests should later be extended to cover formatting and the different
list flags, but for now only covers basic "are create/destroy actually
reflected properly"

r340635:
libbe(3): Handle non-ZFS rootfs better

If rootfs isn't ZFS, current version will emit an error claiming so and fail
to initialize libbe. As a consumer, bectl -r (undocumented) can be specified
to operate on a BE independently of whether on a UFS or ZFS root.

Unbreak this for the UFS case by only erroring out the init if we can't
determine a ZFS dataset for rootfs and no BE root was specified. Consumers
of libbe should take care to ensure that rootfs is non-empty if they're
trying to use it, because this could certainly be the case.

Some check is needed before zfs_path_to_zhandle because it will
unconditionally emit to stderr if the path isn't a ZFS filesystem, which is
unhelpful for our purposes.

This should also unbreak the bectl(8) tests on a UFS root, as is the case in
Jenkins' -test runs.

r340636:
bectl(8) tests: attempt to load the ZFS module

Observed in a CI test image, bectl_create test will run and be marked as
skipped because the module is not loaded. The first zpool invocation will
automagically load the module, but bectl_create is still skipped. Subsequent
tests all pass as expected because the module is now loaded and everything
is OK.
</pre>
</div>
</content>
</entry>
<entry>
<title>libbe(3): Fix error handling with respect to be_exists</title>
<updated>2018-09-01T02:22:26+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2018-09-01T02:22:26+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=162ec569493ba1919857c22a957c97700246da14'/>
<id>162ec569493ba1919857c22a957c97700246da14</id>
<content type='text'>
Some paths through be_exists will set the error state, others will not
There are multiple reasons that a call can fail, so clean it up a bit: all
paths now return an appropriate error code so the caller can attempt to
distinguish between a BE legitimately not existing and just having the wrong
mountpoint. The caller is expected to bubble the error through to the
internal error handler as needed.

This fixes some unfriendliness with bectl(8)'s activate subcommand, where
it might fail due to a bad mountpoint but the only message output is a
generic "failed to activate" message.

Approved by:	re (gjb)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Some paths through be_exists will set the error state, others will not
There are multiple reasons that a call can fail, so clean it up a bit: all
paths now return an appropriate error code so the caller can attempt to
distinguish between a BE legitimately not existing and just having the wrong
mountpoint. The caller is expected to bubble the error through to the
internal error handler as needed.

This fixes some unfriendliness with bectl(8)'s activate subcommand, where
it might fail due to a bad mountpoint but the only message output is a
generic "failed to activate" message.

Approved by:	re (gjb)
</pre>
</div>
</content>
</entry>
<entry>
<title>libbe(3): Prefer safer versions of strcat/strcpy</title>
<updated>2018-08-16T18:37:47+00:00</updated>
<author>
<name>Kyle Evans</name>
<email>kevans@FreeBSD.org</email>
</author>
<published>2018-08-16T18:37:47+00:00</published>
<link rel='alternate' type='text/html' href='http://cgit.freebsd.org/src/commit/?id=a8e44f4da0e8b8892688d88a8faea5abfff2219e'/>
<id>a8e44f4da0e8b8892688d88a8faea5abfff2219e</id>
<content type='text'>
Or, in the activate case, just use snprintf since that's effectively what
we're doing anyways.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Or, in the activate case, just use snprintf since that's effectively what
we're doing anyways.
</pre>
</div>
</content>
</entry>
</feed>
