Merge lp:~sergiusens/snappy/seccompError into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by Sergio Schvezov
Status: Superseded
Proposed branch: lp:~sergiusens/snappy/seccompError
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Diff against target: 1765 lines (+1354/-8) (has conflicts)
20 files modified
cmd/snappy/cmd_internal_unpack.go (+4/-0)
cmd/snappy/cmd_internal_unpack_test.go (+20/-0)
cmd/snappy/cmd_rollback.go (+9/-0)
cmd/snappy/cmd_set.go (+14/-0)
cmd/snappy/main.go (+4/-0)
etc/grub.d/09_snappy.OTHER (+441/-0)
helpers/helpers.go (+170/-8)
helpers/helpers_test.go (+104/-0)
oauth/oauth_test.go (+72/-0)
partition/bootloader_uboot.go (+104/-0)
partition/bootloader_uboot_test.go (+37/-0)
partition/partition.go (+20/-0)
snappy/click.go (+258/-0)
snappy/errors.go (+23/-0)
snappy/security.go (+7/-0)
snappy/snapp.go (+21/-0)
snappy/snapp_test.go (+19/-0)
snappy/systemimage.go (+7/-0)
systemd/systemd.go (+14/-0)
systemd/systemd_test.go (+6/-0)
Text conflict in cmd/snappy/cmd_internal_unpack.go
Text conflict in cmd/snappy/cmd_internal_unpack_test.go
Text conflict in cmd/snappy/cmd_set.go
Text conflict in cmd/snappy/main.go
Conflict adding files to etc.  Created directory.
Conflict because etc is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to etc/grub.d.  Created directory.
Conflict because etc/grub.d is not versioned, but has versioned children.  Versioned directory.
Contents conflict in etc/grub.d/09_snappy
Text conflict in helpers/helpers.go
Text conflict in helpers/helpers_test.go
Text conflict in oauth/oauth_test.go
Text conflict in partition/bootloader_uboot.go
Text conflict in partition/partition.go
Text conflict in snappy/click.go
Text conflict in snappy/errors.go
Text conflict in snappy/security.go
Text conflict in snappy/snapp.go
Text conflict in snappy/snapp_test.go
Text conflict in snappy/systemimage.go
Text conflict in systemd/systemd.go
Text conflict in systemd/systemd_test.go
To merge this branch: bzr merge lp:~sergiusens/snappy/seccompError
Reviewer Review Type Date Requested Status
Snappy Developers Pending
Review via email: mp+263963@code.launchpad.net

Commit message

Backport, Provide a more specific error than '%f is a directory' when missing a seccomp entry

To post a comment you must log in.

Unmerged revisions

457. By Sergio Schvezov

Provide a more specific error than '%f is a directory' when missing a seccomp entry

456. By Michael Terry

Restart systemd services on failure by default

This is a backport of r492 from trunk. by mterry approved by rsalveti

455. By Michael Terry

Add an are-we-root-check/mutex-lock to the set command and make the message nicer.

This is a backport of r528 from trunk. by mterry approved by rsalveti

454. By John Lenton

Cherry picked r493 to fix oauth quoting. Fixes LP:1461262. by chipaca approved by rsalveti

453. By Ricardo Salveti

Fixing lint errors by rsalveti approved by mterry

452. By Sergio Schvezov

Backport 09_snappy to support azure kernel cmdline requirements by sergiusens approved by chipaca

451. By Michael Terry

When rolling back. output version info, especially any messages about rebooting to pick up the new version.

This is a backport of r485 from trunk. by mterry approved by sergiusens

450. By Sergio Schvezov

Don't allow installation of packages with unsupported architectures (backported from trunk with bzr merge -c 484 from trunk) by sergiusens approved by chipaca

449. By Michael Terry

Allow ".." in file paths as long as it isn't an entire element. (i.e. allow "hello..you" or "...")

We call filepath.Clean right before our ".." check. So the only instances of ".." will be in the first element. That lets us simplify the check a lot.

This is a backport of r457 from trunk. by mterry approved by chipaca

448. By Michael Terry

Fix intermittent "permission denied" errors when installing snaps by making sure that we always unpack in the same OS thread that dropped its privileges.

This is a backport of r481 from trunk. by mterry approved by chipaca

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'clickdeb/deb.go'
2=== modified file 'clickdeb/deb_test.go'
3=== modified file 'cmd/snappy/cmd_internal_unpack.go'
4--- cmd/snappy/cmd_internal_unpack.go 2015-07-02 16:01:11 +0000
5+++ cmd/snappy/cmd_internal_unpack.go 2015-07-06 19:58:38 +0000
6@@ -129,6 +129,7 @@
7
8 // first find out what user to use
9 passFile := passwdFile(rootDir, "passwd")
10+<<<<<<< TREE
11 for _, dropPrivsUser = range dropPrivsUsers {
12 _, err := readUID(dropPrivsUser, passFile)
13 if err == nil {
14@@ -138,6 +139,9 @@
15
16 // then get uid/gid
17 uid, err := readUID(dropPrivsUser, passFile)
18+=======
19+ uid, err := readUID(dropPrivsUser, passFile)
20+>>>>>>> MERGE-SOURCE
21 if err != nil {
22 return err
23 }
24
25=== modified file 'cmd/snappy/cmd_internal_unpack_test.go'
26--- cmd/snappy/cmd_internal_unpack_test.go 2015-07-02 16:01:11 +0000
27+++ cmd/snappy/cmd_internal_unpack_test.go 2015-07-06 19:58:38 +0000
28@@ -42,7 +42,11 @@
29 snappypkg:x:101:104::/nonexistent:/bin/false
30 `)
31
32+<<<<<<< TREE
33 uid, err := readUID("snappypkg", f.Name())
34+=======
35+ uid, err := readUID("clickpkg", f.Name())
36+>>>>>>> MERGE-SOURCE
37 c.Assert(err, IsNil)
38 c.Assert(uid, Equals, 101)
39 }
40@@ -53,7 +57,11 @@
41 snappypkg:x:104:
42 `)
43
44+<<<<<<< TREE
45 gid, err := readUID("snappypkg", f.Name())
46+=======
47+ gid, err := readUID("clickpkg", f.Name())
48+>>>>>>> MERGE-SOURCE
49 c.Assert(err, IsNil)
50 c.Assert(gid, Equals, 104)
51 }
52@@ -66,7 +74,11 @@
53 `)
54 defer os.Remove(f.Name())
55
56+<<<<<<< TREE
57 uid, err := readUID("snappypkg", f.Name())
58+=======
59+ uid, err := readUID("clickpkg", f.Name())
60+>>>>>>> MERGE-SOURCE
61 c.Assert(err, IsNil)
62 c.Assert(uid, Equals, 102)
63 }
64@@ -77,7 +89,11 @@
65 snappypkg:x:
66 `)
67
68+<<<<<<< TREE
69 _, err := readUID("snappypkg", f.Name())
70+=======
71+ _, err := readUID("clickpkg", f.Name())
72+>>>>>>> MERGE-SOURCE
73 c.Assert(err, NotNil)
74 }
75
76@@ -86,6 +102,10 @@
77 daemon:
78 `)
79
80+<<<<<<< TREE
81 _, err := readUID("snappypkg", f.Name())
82+=======
83+ _, err := readUID("clickpkg", f.Name())
84+>>>>>>> MERGE-SOURCE
85 c.Assert(err, NotNil)
86 }
87
88=== modified file 'cmd/snappy/cmd_rollback.go'
89--- cmd/snappy/cmd_rollback.go 2015-07-02 17:16:11 +0000
90+++ cmd/snappy/cmd_rollback.go 2015-07-06 19:58:38 +0000
91@@ -77,5 +77,14 @@
92 parts := snappy.FindSnapsByNameAndVersion(pkg, nowVersion, installed)
93 showVerboseList(parts, os.Stdout)
94
95+ m := snappy.NewMetaRepository()
96+ installed, err := m.Installed()
97+ if err != nil {
98+ return err
99+ }
100+
101+ parts := snappy.FindSnapsByNameAndVersion(pkg, nowVersion, installed)
102+ showVerboseList(parts, os.Stdout)
103+
104 return nil
105 }
106
107=== modified file 'cmd/snappy/cmd_set.go'
108--- cmd/snappy/cmd_set.go 2015-06-30 12:52:52 +0000
109+++ cmd/snappy/cmd_set.go 2015-07-06 19:58:38 +0000
110@@ -23,8 +23,12 @@
111 "fmt"
112 "strings"
113
114+<<<<<<< TREE
115 "launchpad.net/snappy/i18n"
116 "launchpad.net/snappy/logger"
117+=======
118+ "launchpad.net/snappy/priv"
119+>>>>>>> MERGE-SOURCE
120 "launchpad.net/snappy/progress"
121 "launchpad.net/snappy/snappy"
122 )
123@@ -53,8 +57,18 @@
124 }
125
126 func (x *cmdSet) Execute(args []string) (err error) {
127+<<<<<<< TREE
128 x.args = args
129 return withMutex(x.doSet)
130+=======
131+ privMutex := priv.New()
132+ if err := privMutex.TryLock(); err != nil {
133+ return err
134+ }
135+ defer privMutex.Unlock()
136+
137+ return set(args)
138+>>>>>>> MERGE-SOURCE
139 }
140
141 func (x *cmdSet) doSet() (err error) {
142
143=== modified file 'cmd/snappy/main.go'
144--- cmd/snappy/main.go 2015-06-11 20:30:46 +0000
145+++ cmd/snappy/main.go 2015-07-06 19:58:38 +0000
146@@ -52,10 +52,14 @@
147 // the CLI user.
148 err = snappy.ErrNeedRoot
149 }
150+<<<<<<< TREE
151 fmt.Fprintln(os.Stderr, err)
152 if _, ok := err.(*flags.Error); !ok {
153 logger.Debugf("%v failed: %v", os.Args, err)
154 }
155+=======
156+ fmt.Fprintln(os.Stderr, err)
157+>>>>>>> MERGE-SOURCE
158 os.Exit(1)
159 }
160 }
161
162=== added directory 'etc'
163=== added directory 'etc/grub.d'
164=== added file 'etc/grub.d/09_snappy.OTHER'
165--- etc/grub.d/09_snappy.OTHER 1970-01-01 00:00:00 +0000
166+++ etc/grub.d/09_snappy.OTHER 2015-07-06 19:58:38 +0000
167@@ -0,0 +1,441 @@
168+#!/bin/sh
169+#---------------------------------------------------------------------
170+# Summary: Grub bootloader logic for Ubuntu Snappy systems.
171+# Description: This is a heavily modified "10_linux" grub snippet that
172+# deals with Snappy dual-rootfs systems.
173+#
174+# XXX: Note that this script is called from within a chroot environment
175+# on snappy systems!
176+#
177+#---------------------------------------------------------------------
178+
179+set -e
180+
181+prefix="/usr"
182+exec_prefix="/usr"
183+datarootdir="/usr/share"
184+
185+# Utility functions
186+. "${datarootdir}/grub/grub-mkconfig_lib"
187+
188+# Globals
189+machine=`uname -m`
190+
191+SNAPPY_OS="Ubuntu Core Snappy"
192+SNAPPY_TYPE=simple
193+
194+#---------------------------------------------------------------------
195+
196+# Display message and exit
197+die()
198+{
199+ msg="$*"
200+ echo "ERROR: $msg" >&2
201+ exit 1
202+}
203+
204+# Create a grub menu entry by writing a menuentry to stdout.
205+linux_entry_ext()
206+{
207+ local name="$1"
208+ local os="$2"
209+ local version="$3"
210+ local type="$4"
211+ local args="$5"
212+ local device="$6"
213+ local kernel="$7"
214+ local initrd="$8"
215+
216+ local boot_device_id=
217+ local prepare_root_cache=
218+ local prepare_boot_cache=
219+
220+ if [ -z "$boot_device_id" ]; then
221+ boot_device_id="$(grub_get_device_id "${device}")"
222+ fi
223+
224+ echo "menuentry '$name' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
225+
226+ if [ x$type != xrecovery ] ; then
227+ save_default_entry | grub_add_tab
228+ fi
229+
230+ # Use ELILO's generic "efifb" when it's known to be available.
231+ # FIXME: We need an interface to select vesafb in case efifb can't be used.
232+ if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
233+ echo " load_video" | sed "s/^/$submenu_indentation/"
234+ else
235+ if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
236+ echo " load_video" | sed "s/^/$submenu_indentation/"
237+ fi
238+ fi
239+ if ([ "$ubuntu_recovery" = 0 ] || [ x$type != xrecovery ]) && \
240+ ([ "x$GRUB_GFXPAYLOAD_LINUX" != x ] || [ "$gfxpayload_dynamic" = 1 ]); then
241+ echo " gfxmode \$linux_gfx_mode" | sed "s/^/$submenu_indentation/"
242+ fi
243+
244+ echo " insmod gzio" | sed "s/^/$submenu_indentation/"
245+ echo " if [ x\$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi" | sed "s/^/$submenu_indentation/"
246+
247+ # device may be a label (LABEL=name), so convert back to full path
248+ label_name=$(echo "$device"|sed 's/^LABEL=//g')
249+ if [ "$device" = "$label_name" ]
250+ then
251+ device_path="$device"
252+ else
253+ # found a label
254+ device_path=$(get_partition_from_label "$label_name")
255+ fi
256+
257+ if [ x$dirname = x/ ]; then
258+ if [ -z "${prepare_root_cache}" ]; then
259+
260+ prepare_root_cache="$(prepare_grub_to_access_device ${device_path} | grub_add_tab)"
261+ fi
262+ printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
263+ else
264+ if [ -z "${prepare_boot_cache}" ]; then
265+ prepare_boot_cache="$(prepare_grub_to_access_device ${device_path} | grub_add_tab)"
266+ fi
267+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
268+ fi
269+
270+ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
271+ message="$(gettext_printf "Loading Linux %s ..." ${version})"
272+ sed "s/^/$submenu_indentation/" << EOF
273+ echo '$(echo "$message" | grub_quote)'
274+EOF
275+ fi
276+
277+ sed "s/^/$submenu_indentation/" << EOF
278+ linux ${kernel} root=${device} ro ${args}
279+EOF
280+
281+ if test -n "${initrd}"; then
282+ # TRANSLATORS: ramdisk isn't identifier. Should be translated.
283+ if [ x"$quiet_boot" = x0 ] || [ x"$type" != xsimple ]; then
284+ message="$(gettext_printf "Loading initial ramdisk ...")"
285+ sed "s/^/$submenu_indentation/" << EOF
286+ echo '$(echo "$message" | grub_quote)'
287+EOF
288+ fi
289+ sed "s/^/$submenu_indentation/" << EOF
290+ initrd ${initrd}
291+EOF
292+ fi
293+
294+ sed "s/^/$submenu_indentation/" << EOF
295+}
296+EOF
297+}
298+
299+# Returns a list of the currently available kernels.
300+# $1: If set, look for kernel below "$1/boot/".
301+get_kernels()
302+{
303+ local prefix_dir="$1"
304+ local list
305+
306+ case "x$machine" in
307+ xi?86 | xx86_64)
308+ list=`for i in $prefix_dir/boot/vmlinuz-* \
309+ $prefix_dir/vmlinuz-* \
310+ $prefix_dir/boot/kernel-* ; do
311+ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
312+ done` ;;
313+ *)
314+ list=`for i in $prefix_dir/boot/vmlinuz-* \
315+ $prefix_dir/boot/vmlinux-* \
316+ $prefix_dir/vmlinuz-* \
317+ $prefix_dir/vmlinux-* \
318+ $prefix_dir/boot/kernel-* ; do
319+ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
320+ done` ;;
321+ esac
322+ echo "$list"
323+}
324+
325+# Composes and returns a kernel cmd line
326+get_cmdline() {
327+ channel_ini="/etc/system-image/channel.ini"
328+ grep -q 'device: azure_amd64' "$channel_ini" && azure_cmdline="rootdelay=300"
329+
330+ echo "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} $azure_cmdline"
331+}
332+
333+# Returns the path to the initrd for the kernel specified by $1.
334+# $1: kernel version.
335+# $2: directory to look in.
336+get_initrd()
337+{
338+ local version="$1"
339+ local dir="$2"
340+
341+ local alt_version=`echo $version | sed -e "s,\.old$,,g"`
342+ local initrd=
343+ local i=
344+
345+ for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \
346+ "initrd-${version}" "initramfs-${version}.img" \
347+ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \
348+ "initrd-${alt_version}" "initramfs-${alt_version}.img" \
349+ "initramfs-genkernel-${version}" \
350+ "initramfs-genkernel-${alt_version}" \
351+ "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \
352+ "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do
353+ if test -e "${dir}/${i}" ; then
354+ initrd="${dir}/${i}"
355+ break
356+ fi
357+ done
358+ echo "$initrd"
359+}
360+
361+# Determine full path to disk partition given a filesystem label.
362+get_partition_from_label()
363+{
364+ local label="$1"
365+ local part=
366+ local path=
367+
368+ [ -n "$label" ] || grub_warn "need FS label"
369+
370+ part=$(find /dev -name "$label"|tail -1)
371+ [ -z "$part" ] && return
372+ path=$(readlink -f "$part")
373+ [ -n "$path" ] && echo "$path"
374+}
375+
376+# Return the partition label for the given partition device.
377+# $1: full path to partition device.
378+get_label_from_device()
379+{
380+ local root="$1"
381+
382+ local label=
383+ local std_label=
384+ local label_rootfs=
385+
386+ for std_label in system-a system-b; do
387+ label_rootfs=$(findfs "PARTLABEL=$std_label" 2>/dev/null || :)
388+ if [ "$label_rootfs" = "$root" ]; then
389+ label="$std_label"
390+ break
391+ fi
392+ done
393+
394+ echo "$label"
395+}
396+
397+# Return the full path to the device corresponding to the given
398+# partition label.
399+#
400+# $1: partition label.
401+get_device_from_label()
402+{
403+ local label="$1"
404+ local device=
405+
406+ device=$(findfs "PARTLABEL=$label" 2>/dev/null || :)
407+ echo "$device"
408+}
409+
410+# Given a rootfs label, return the rootfs label corresponding to the
411+# "other" rootfs partition.
412+get_other_rootfs_label()
413+{
414+ local label="$1"
415+
416+ if [ "$label" = "system-a" ]; then
417+ echo "system-b"
418+ else
419+ echo "system-a"
420+ fi
421+}
422+
423+# Given a mountpoint, return the corresponding device path
424+# $1: mountpoint.
425+get_device_from_mountpoint()
426+{
427+ local mountpoint="$1"
428+ local device=
429+
430+ # XXX: Parse mount output rather than looking in /proc/mounts to
431+ # avoid seeing the mounts outside the chroot.
432+ device=$(/bin/mount | grep "^/dev/.* on ${mountpoint}[[:space:]]" 2>/dev/null |\
433+ awk '{print $1}' || :)
434+
435+ echo "$device"
436+}
437+
438+# Convert a partition label name to a menuentry name
439+make_name()
440+{
441+ local label="$1"
442+
443+ echo "$SNAPPY_OS $label rootfs" | grub_quote
444+}
445+
446+# Arrange for a grub menuentry to be created for the given partition.
447+#
448+# $1: full path to rootfs partition device
449+# $2: partition label associated with $1
450+# $3: mountpoint of $1.
451+handle_menu_entry()
452+{
453+ local rootfs_device="$1"
454+ local label="$2"
455+ local mountpoint="$3"
456+
457+ local name=
458+ local device=
459+ local mount_prefix=
460+ local list=
461+ local linux=
462+ local basename=
463+ local dirname=
464+ local rel_dirname=
465+ local version=
466+ local initrd=
467+ local cmdline=
468+
469+ # boot by label
470+ device="LABEL=$label"
471+
472+ name=$(make_name "$label")
473+
474+ # avoid double-leading slashes and the subsequent need to call
475+ # 'readlink -f'.
476+ if [ "$mountpoint" = "/" ]; then
477+ mount_prefix=""
478+ else
479+ mount_prefix="$mountpoint"
480+ fi
481+ list=$(get_kernels "$mount_prefix")
482+
483+ linux=$(version_find_latest $list)
484+ basename=$(basename "$linux")
485+ dirname=$(dirname "$linux")
486+ rel_dirname=$(make_system_path_relative_to_its_root "$dirname")
487+ version=$(echo "$basename" | sed -e "s,^[^0-9]*-,,g")
488+
489+ initrd=$(get_initrd "$version" "$dirname")
490+
491+ cmdline=$(get_cmdline)
492+
493+ # convert the path to the mounted "other" rootfs back to a
494+ # a standard one by removing the mountpoint prefix.
495+ if [ "$mountpoint" != "/" ]; then
496+ linux=$(echo "$linux" | sed "s!^${mountpoint}!!g")
497+ initrd=$(echo "$initrd" | sed "s!^${mountpoint}!!g")
498+ fi
499+
500+ # Create menu entries for the 2 snappy rootfs's.
501+ linux_entry_ext "$name" "$SNAPPY_OS" "$version" \
502+ "$SNAPPY_TYPE" "$cmdline" "$device" \
503+ "$linux" "$initrd"
504+}
505+
506+#---------------------------------------------------------------------
507+# main
508+
509+case "$machine" in
510+ i?86) GENKERNEL_ARCH="x86" ;;
511+ mips|mips64) GENKERNEL_ARCH="mips" ;;
512+ mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
513+ arm*) GENKERNEL_ARCH="arm" ;;
514+ *) GENKERNEL_ARCH="$machine" ;;
515+esac
516+
517+# Determine which partition label is being used for the current root
518+# directory. This is slightly convoluted but required since this code
519+# runs within a chroot environment (where lsblk does not work).
520+#
521+# XXX: Note that since this code is run from within a chroot (where the
522+# "other" rootfs is mounted), it might appear that the logic is
523+# inverted. However, the code below simply
524+this_mountpoint="/"
525+this_root=$(get_device_from_mountpoint "$this_mountpoint")
526+[ -z "$this_root" ] && {
527+ die "cannot determine rootfs for $this_mountpoint"
528+}
529+
530+this_label=$(get_label_from_device "$this_root")
531+[ -z "$this_label" ] && {
532+ die "cannot determine partition label for rootfs $this_root"
533+}
534+
535+handle_menu_entry "$this_root" "$this_label" "$this_mountpoint"
536+
537+other_mountpoint="/writable/cache/system"
538+
539+# When this script is run on a real snappy system, even if there is only
540+# a single rootfs provisioned, the other rootfs partition is expected to
541+# be formatted and mounted.
542+#
543+# However this script is also run at provisioning time where
544+# $other_mountpoint will not be a mountpoint. Therefore in the provisioning
545+# scenario, only a single menuentry will be generated if only a single
546+# rootfs is provisioned.
547+if $(mountpoint -q "$other_mountpoint"); then
548+ other_label=$(get_other_rootfs_label "$this_label")
549+
550+ other_root=$(get_device_from_label "$other_label")
551+ [ -z "$other_root" ] && {
552+ die "cannot determine rootfs"
553+ }
554+
555+ handle_menu_entry "$other_root" "$other_label" "$other_mountpoint"
556+fi
557+
558+# Toggle rootfs if previous boot failed.
559+#
560+# Since grub sets snappy_trial_boot, if it is _already_ set when grub starts
561+# and we're in try mode, the previous boot must have failed to unset it,
562+# so toggle the rootfs.
563+sed "s/^/$submenu_indentation/" << EOF
564+ # set defaults
565+ if [ -z "\$snappy_mode" ]; then
566+ set snappy_mode=regular
567+ save_env snappy_mode
568+ fi
569+ if [ -z "\$snappy_ab" ]; then
570+ set snappy_ab=a
571+ save_env snappy_ab
572+ fi
573+
574+ if [ "\$snappy_mode" = "try" ]; then
575+ if [ "\$snappy_trial_boot" = "1" ]; then
576+ # Previous boot failed to unset snappy_trial_boot, so toggle
577+ # rootfs.
578+ if [ "\$snappy_ab" = "a" ]; then
579+ set default="$(make_name system-b)"
580+ set snappy_ab=b
581+ else
582+ set snappy_ab=a
583+ set default="$(make_name system-a)"
584+ fi
585+ save_env snappy_ab
586+ else
587+ # Trial mode so set the snappy_trial_boot (which snappy is
588+ # expected to unset).
589+ #
590+ # Note: don't use the standard recordfail variable since that forces
591+ # the menu to be displayed and sets an infinite timeout if set.
592+ set snappy_trial_boot=1
593+ save_env snappy_trial_boot
594+
595+ if [ "\$snappy_ab" = "a" ]; then
596+ set default="$(make_name system-a)"
597+ else
598+ set default="$(make_name system-b)"
599+ fi
600+ fi
601+ else
602+ if [ "\$snappy_ab" = "a" ]; then
603+ set default="$(make_name system-a)"
604+ else
605+ set default="$(make_name system-b)"
606+ fi
607+ fi
608+EOF
609
610=== modified file 'helpers/helpers.go'
611--- helpers/helpers.go 2015-07-01 21:09:59 +0000
612+++ helpers/helpers.go 2015-07-06 19:58:38 +0000
613@@ -26,6 +26,7 @@
614 "encoding/hex"
615 "fmt"
616 "io"
617+ "io/ioutil"
618 "math/rand"
619 "os"
620 "os/exec"
621@@ -198,14 +199,37 @@
622 }
623 }
624
625-// IsSupportedArchitecture returns true if the system architecture is in the
626-// list of architectures.
627-func IsSupportedArchitecture(architectures []string) bool {
628- systemArch := UbuntuArchitecture()
629-
630- for _, arch := range architectures {
631- if arch == "all" || arch == systemArch {
632- return true
633+<<<<<<< TREE
634+// IsSupportedArchitecture returns true if the system architecture is in the
635+// list of architectures.
636+func IsSupportedArchitecture(architectures []string) bool {
637+ systemArch := UbuntuArchitecture()
638+
639+ for _, arch := range architectures {
640+ if arch == "all" || arch == systemArch {
641+ return true
642+=======
643+// IsSupportedArchitecture returns true if the system architecture is in the
644+// list of architectures.
645+func IsSupportedArchitecture(architectures []string) bool {
646+ systemArch := UbuntuArchitecture()
647+
648+ for _, arch := range architectures {
649+ if arch == "all" || arch == systemArch {
650+ return true
651+ }
652+ }
653+
654+ return false
655+}
656+
657+// EnsureDir ensures that the given directory exists and if
658+// not creates it with the given permissions.
659+func EnsureDir(dir string, perm os.FileMode) (err error) {
660+ if _, err := os.Stat(dir); os.IsNotExist(err) {
661+ if err := os.MkdirAll(dir, perm); err != nil {
662+ return err
663+>>>>>>> MERGE-SOURCE
664 }
665 }
666
667@@ -346,6 +370,7 @@
668 return syscall.Getuid() == 0 || syscall.Getgid() == 0
669
670 }
671+<<<<<<< TREE
672
673 // MajorMinor returns the major/minor number of the given os.FileInfo
674 func MajorMinor(info os.FileInfo) (uint32, uint32, error) {
675@@ -509,3 +534,140 @@
676
677 return nil
678 }
679+=======
680+
681+func makeDirMap(dirName string) (map[string]struct{}, error) {
682+ dir, err := ioutil.ReadDir(dirName)
683+ if err != nil {
684+ return nil, err
685+ }
686+
687+ dirMap := make(map[string]struct{})
688+ for _, dent := range dir {
689+ if dent.IsDir() {
690+ return nil, fmt.Errorf("subdirs are not supported")
691+ }
692+ dirMap[dent.Name()] = struct{}{}
693+ }
694+
695+ return dirMap, nil
696+}
697+
698+// RSyncWithDelete syncs srcDir to destDir
699+func RSyncWithDelete(srcDirName, destDirName string) error {
700+
701+ // first remove everything thats not in srcdir
702+ err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error {
703+ if err != nil {
704+ return err
705+ }
706+
707+ // relative to the root "destDirName"
708+ relPath := path[len(destDirName):]
709+ if !FileExists(filepath.Join(srcDirName, relPath)) {
710+ if err := os.RemoveAll(path); err != nil {
711+ return err
712+ }
713+ if info.IsDir() {
714+ return filepath.SkipDir
715+ }
716+ }
717+ return nil
718+ })
719+ if err != nil {
720+ return err
721+ }
722+
723+ // then copy or update the data from srcdir to destdir
724+ err = filepath.Walk(srcDirName, func(path string, info os.FileInfo, err error) error {
725+ if err != nil {
726+ return err
727+ }
728+
729+ // relative to the root "srcDirName"
730+ relPath := path[len(srcDirName):]
731+ if info.IsDir() {
732+ return os.MkdirAll(filepath.Join(destDirName, relPath), info.Mode())
733+ }
734+ src := path
735+ dst := filepath.Join(destDirName, relPath)
736+ if !FilesAreEqual(src, dst) {
737+ // XXX: on snappy-trunk we can use CopyFile here
738+ output, err := exec.Command("cp", "-va", src, dst).CombinedOutput()
739+ if err != nil {
740+ fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output)
741+ }
742+ }
743+ return nil
744+ })
745+
746+ return err
747+}
748+
749+func fillSnapEnvVars(desc interface{}, vars []string) []string {
750+ for i, v := range vars {
751+ var templateOut bytes.Buffer
752+ t := template.Must(template.New("wrapper").Parse(v))
753+ if err := t.Execute(&templateOut, desc); err != nil {
754+ // this can never happen, except we forget a variable
755+ logger.LogAndPanic(err)
756+ }
757+ vars[i] = templateOut.String()
758+ }
759+ return vars
760+}
761+
762+// GetBasicSnapEnvVars returns the app-level environment variables for a snap.
763+// Despite this being a bit snap-specific, this is in helpers.go because it's
764+// used by so many other modules, we run into circular dependencies if it's
765+// somewhere more reasonable like the snappy module.
766+func GetBasicSnapEnvVars(desc interface{}) []string {
767+ return fillSnapEnvVars(desc, []string{
768+ "TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
769+ "TEMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
770+ "SNAP_APP_PATH={{.AppPath}}",
771+ "SNAP_APP_DATA_PATH=/var/lib{{.AppPath}}",
772+ "SNAP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
773+ "SNAP_NAME={{.AppName}}",
774+ "SNAP_VERSION={{.Version}}",
775+ "SNAP_ORIGIN={{.Namespace}}",
776+ "SNAP_FULLNAME={{.UdevAppName}}",
777+ "SNAP_ARCH={{.AppArch}}",
778+ })
779+}
780+
781+// GetUserSnapEnvVars returns the user-level environment variables for a snap.
782+// Despite this being a bit snap-specific, this is in helpers.go because it's
783+// used by so many other modules, we run into circular dependencies if it's
784+// somewhere more reasonable like the snappy module.
785+func GetUserSnapEnvVars(desc interface{}) []string {
786+ return fillSnapEnvVars(desc, []string{
787+ "SNAP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
788+ })
789+}
790+
791+// GetDeprecatedBasicSnapEnvVars returns the app-level deprecated environment
792+// variables for a snap.
793+// Despite this being a bit snap-specific, this is in helpers.go because it's
794+// used by so many other modules, we run into circular dependencies if it's
795+// somewhere more reasonable like the snappy module.
796+func GetDeprecatedBasicSnapEnvVars(desc interface{}) []string {
797+ return fillSnapEnvVars(desc, []string{
798+ "SNAPP_APP_PATH={{.AppPath}}",
799+ "SNAPP_APP_DATA_PATH=/var/lib{{.AppPath}}",
800+ "SNAPP_APP_TMPDIR=/tmp/snaps/{{.UdevAppName}}/{{.Version}}/tmp",
801+ "SNAPPY_APP_ARCH={{.AppArch}}",
802+ })
803+}
804+
805+// GetDeprecatedUserSnapEnvVars returns the user-level deprecated environment
806+// variables for a snap.
807+// Despite this being a bit snap-specific, this is in helpers.go because it's
808+// used by so many other modules, we run into circular dependencies if it's
809+// somewhere more reasonable like the snappy module.
810+func GetDeprecatedUserSnapEnvVars(desc interface{}) []string {
811+ return fillSnapEnvVars(desc, []string{
812+ "SNAPP_APP_USER_DATA_PATH={{.Home}}{{.AppPath}}",
813+ })
814+}
815+>>>>>>> MERGE-SOURCE
816
817=== modified file 'helpers/helpers_test.go'
818--- helpers/helpers_test.go 2015-07-01 18:27:44 +0000
819+++ helpers/helpers_test.go 2015-07-06 19:58:38 +0000
820@@ -271,6 +271,7 @@
821 c.Assert(err, IsNil)
822 c.Assert(home, Equals, oldHome)
823 }
824+<<<<<<< TREE
825
826 func skipOnMissingDevKmsg(c *C) {
827 _, err := os.Stat("/dev/kmsg")
828@@ -483,3 +484,106 @@
829 err := CopyIfDifferent(src, dst)
830 c.Assert(err, NotNil)
831 }
832+=======
833+
834+func makeTestFiles(c *C, srcDir, destDir string) {
835+ // a new file
836+ err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644)
837+ c.Assert(err, IsNil)
838+
839+ // a existing file that needs update
840+ err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644)
841+ c.Assert(err, IsNil)
842+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644)
843+ c.Assert(err, IsNil)
844+
845+ // existing file that needs no update
846+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644)
847+ c.Assert(err, IsNil)
848+ err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run()
849+ c.Assert(err, IsNil)
850+
851+ // a file that needs removal
852+ err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644)
853+ c.Assert(err, IsNil)
854+}
855+
856+func compareDirs(c *C, srcDir, destDir string) {
857+ d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput()
858+ c.Assert(err, IsNil)
859+ d2, err := exec.Command("ls", "-al", destDir).CombinedOutput()
860+ c.Assert(err, IsNil)
861+ c.Assert(string(d1), Equals, string(d2))
862+ // ensure content got updated
863+ c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput()
864+ c.Assert(err, IsNil)
865+ c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput()
866+ c.Assert(err, IsNil)
867+ c.Assert(string(c1), Equals, string(c2))
868+}
869+
870+func (ts *HTestSuite) TestSyncDirs(c *C) {
871+
872+ for _, l := range [][2]string{
873+ [2]string{"src-short", "dst-loooooooooooong"},
874+ [2]string{"src-loooooooooooong", "dst-short"},
875+ [2]string{"src-eq", "dst-eq"},
876+ } {
877+
878+ // ensure we have src, dest dirs with different length
879+ srcDir := filepath.Join(c.MkDir(), l[0])
880+ err := os.MkdirAll(srcDir, 0755)
881+ c.Assert(err, IsNil)
882+ destDir := filepath.Join(c.MkDir(), l[1])
883+ err = os.MkdirAll(destDir, 0755)
884+ c.Assert(err, IsNil)
885+
886+ // add a src subdir
887+ subdir := filepath.Join(srcDir, "subdir")
888+ err = os.Mkdir(subdir, 0755)
889+ c.Assert(err, IsNil)
890+ makeTestFiles(c, subdir, destDir)
891+
892+ // add a dst subdir that needs to get deleted
893+ subdir2 := filepath.Join(destDir, "to-be-deleted-subdir")
894+ err = os.Mkdir(subdir2, 0755)
895+ subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir")
896+ err = os.Mkdir(subdir3, 0755)
897+
898+ // and a toplevel
899+ makeTestFiles(c, srcDir, destDir)
900+
901+ // do it
902+ err = RSyncWithDelete(srcDir, destDir)
903+ c.Assert(err, IsNil)
904+
905+ // ensure meta-data is identical
906+ compareDirs(c, srcDir, destDir)
907+ compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir"))
908+ }
909+}
910+
911+func (ts *HTestSuite) TestSyncDirFails(c *C) {
912+ srcDir := c.MkDir()
913+ err := os.MkdirAll(srcDir, 0755)
914+ c.Assert(err, IsNil)
915+
916+ destDir := c.MkDir()
917+ err = os.MkdirAll(destDir, 0755)
918+ c.Assert(err, IsNil)
919+
920+ err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644)
921+ c.Assert(err, IsNil)
922+
923+ // ensure remove fails
924+ err = os.Chmod(destDir, 0100)
925+ c.Assert(err, IsNil)
926+ // make tempdir cleanup work again
927+ defer os.Chmod(destDir, 0755)
928+
929+ // do it
930+ err = RSyncWithDelete(srcDir, destDir)
931+ c.Check(err, NotNil)
932+ c.Check(err, ErrorMatches, ".*permission denied.*")
933+}
934+>>>>>>> MERGE-SOURCE
935
936=== modified file 'helpers/touch.go'
937=== modified file 'oauth/oauth_test.go'
938--- oauth/oauth_test.go 2015-06-09 13:02:35 +0000
939+++ oauth/oauth_test.go 2015-07-06 19:58:38 +0000
940@@ -1,3 +1,4 @@
941+<<<<<<< TREE
942 // -*- Mode: Go; indent-tabs-mode: t -*-
943
944 /*
945@@ -67,3 +68,74 @@
946 c.Check(needsEscape(no), Equals, false)
947 }
948 }
949+=======
950+// -*- Mode: Go; indent-tabs-mode: t -*-
951+
952+/*
953+ * Copyright (C) 2014-2015 Canonical Ltd
954+ *
955+ * This program is free software: you can redistribute it and/or modify
956+ * it under the terms of the GNU General Public License version 3 as
957+ * published by the Free Software Foundation.
958+ *
959+ * This program is distributed in the hope that it will be useful,
960+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
961+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
962+ * GNU General Public License for more details.
963+ *
964+ * You should have received a copy of the GNU General Public License
965+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
966+ *
967+ */
968+
969+package oauth
970+
971+import (
972+ "testing"
973+
974+ . "launchpad.net/gocheck"
975+)
976+
977+func Test(t *testing.T) { TestingT(t) }
978+
979+type OAuthTestSuite struct{}
980+
981+var _ = Suite(&OAuthTestSuite{})
982+
983+func (s *OAuthTestSuite) TestMakePlaintextSignature(c *C) {
984+ mockToken := Token{
985+ ConsumerKey: "consumer-key+",
986+ ConsumerSecret: "consumer-secret+",
987+ TokenKey: "token-key+",
988+ TokenSecret: "token-secret+",
989+ }
990+ sig := MakePlaintextSignature(&mockToken)
991+ c.Assert(sig, Matches, `OAuth oauth_nonce="[a-zA-Z]+", oauth_timestamp="[0-9]+", oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="consumer-key%2B", oauth_token="token-key%2B", oauth_signature="consumer-secret%2B&token-secret%2B"`)
992+}
993+
994+func (s *OAuthTestSuite) TestQuote(c *C) {
995+ // see http://wiki.oauth.net/w/page/12238556/TestCases
996+ c.Check(quote("abcABC123"), Equals, "abcABC123")
997+ c.Check(quote("-._~"), Equals, "-._~")
998+ c.Check(quote("%"), Equals, "%25")
999+ c.Check(quote("+"), Equals, "%2B")
1000+ c.Check(quote("&=*"), Equals, "%26%3D%2A")
1001+ c.Check(quote("\u000A"), Equals, "%0A")
1002+ c.Check(quote("\u0020"), Equals, "%20")
1003+ c.Check(quote("\u007F"), Equals, "%7F")
1004+ c.Check(quote("\u0080"), Equals, "%C2%80")
1005+ c.Check(quote("\u3001"), Equals, "%E3%80%81")
1006+}
1007+
1008+func (s *OAuthTestSuite) TestNeedsEscape(c *C) {
1009+ for _, needed := range []byte{'?', '/', ':'} {
1010+ c.Check(needsEscape(needed), Equals, true)
1011+ }
1012+}
1013+
1014+func (s *OAuthTestSuite) TestNeedsNoEscape(c *C) {
1015+ for _, no := range []byte{'a', 'z', 'A', 'Z', '-', '.', '_', '~'} {
1016+ c.Check(needsEscape(no), Equals, false)
1017+ }
1018+}
1019+>>>>>>> MERGE-SOURCE
1020
1021=== modified file 'partition/bootloader_uboot.go'
1022--- partition/bootloader_uboot.go 2015-07-01 06:27:50 +0000
1023+++ partition/bootloader_uboot.go 2015-07-06 19:58:38 +0000
1024@@ -203,6 +203,110 @@
1025 return os.RemoveAll(bootloaderUbootStampFile)
1026 }
1027
1028+<<<<<<< TREE
1029+=======
1030+func (u *uboot) SyncBootFiles() (err error) {
1031+ srcDir := u.currentBootPath
1032+ destDir := u.otherBootPath
1033+
1034+ return helpers.RSyncWithDelete(srcDir, destDir)
1035+}
1036+
1037+func (u *uboot) HandleAssets() (err error) {
1038+ // check if we have anything, if there is no hardware yaml, there is nothing
1039+ // to process.
1040+ hardware, err := u.partition.hardwareSpec()
1041+ if err == ErrNoHardwareYaml {
1042+ return nil
1043+ } else if err != nil {
1044+ return err
1045+ }
1046+ // ensure to remove the file once we are done
1047+ defer os.Remove(u.partition.hardwareSpecFile)
1048+
1049+ // validate bootloader
1050+ if hardware.Bootloader != u.Name() {
1051+ return fmt.Errorf(
1052+ "bootloader is of type %s but hardware spec requires %s",
1053+ u.Name(),
1054+ hardware.Bootloader)
1055+ }
1056+
1057+ // validate partition layout
1058+ if u.partition.dualRootPartitions() && hardware.PartitionLayout != bootloaderSystemAB {
1059+ return fmt.Errorf("hardware spec requires dual root partitions")
1060+ }
1061+
1062+ // ensure we have the destdir
1063+ destDir := u.otherBootPath
1064+ if err := os.MkdirAll(destDir, dirMode); err != nil {
1065+ return err
1066+ }
1067+
1068+ // install kernel+initrd
1069+ for _, file := range []string{hardware.Kernel, hardware.Initrd} {
1070+
1071+ if file == "" {
1072+ continue
1073+ }
1074+
1075+ // expand path
1076+ path := path.Join(u.partition.cacheDir(), file)
1077+
1078+ if !helpers.FileExists(path) {
1079+ return fmt.Errorf("can not find file %s", path)
1080+ }
1081+
1082+ // ensure we remove the dir later
1083+ defer os.RemoveAll(filepath.Dir(path))
1084+
1085+ if err := runCommand("/bin/cp", path, destDir); err != nil {
1086+ return err
1087+ }
1088+ }
1089+
1090+ // TODO: look at the OEM package for dtb changes too once that is
1091+ // fully speced
1092+
1093+ // install .dtb files
1094+ dtbSrcDir := filepath.Join(u.partition.cacheDir(), hardware.DtbDir)
1095+ if helpers.FileExists(dtbSrcDir) {
1096+ // ensure we cleanup the source dir
1097+ defer os.RemoveAll(dtbSrcDir)
1098+
1099+ dtbDestDir := path.Join(destDir, "dtbs")
1100+ if err := os.MkdirAll(dtbDestDir, dirMode); err != nil {
1101+ return err
1102+ }
1103+
1104+ files, err := filepath.Glob(path.Join(dtbSrcDir, "*"))
1105+ if err != nil {
1106+ return err
1107+ }
1108+
1109+ for _, file := range files {
1110+ if err := runCommand("/bin/cp", file, dtbDestDir); err != nil {
1111+ return err
1112+ }
1113+ }
1114+ }
1115+
1116+ flashAssetsDir := u.partition.flashAssetsDir()
1117+
1118+ if helpers.FileExists(flashAssetsDir) {
1119+ // FIXME: we don't currently do anything with the
1120+ // MLO + uImage files since they are not specified in
1121+ // the hardware spec. So for now, just remove them.
1122+
1123+ if err := os.RemoveAll(flashAssetsDir); err != nil {
1124+ return err
1125+ }
1126+ }
1127+
1128+ return err
1129+}
1130+
1131+>>>>>>> MERGE-SOURCE
1132 // Write lines to file atomically. File does not have to preexist.
1133 // FIXME: put into utils package
1134 func atomicFileUpdateImpl(file string, lines []string) (err error) {
1135
1136=== modified file 'partition/bootloader_uboot_test.go'
1137--- partition/bootloader_uboot_test.go 2015-06-29 23:15:00 +0000
1138+++ partition/bootloader_uboot_test.go 2015-07-06 19:58:38 +0000
1139@@ -318,3 +318,40 @@
1140 c.Check(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, true)
1141 c.Check(strings.Contains(string(bytes), "snappy_ab=a"), Equals, true)
1142 }
1143+
1144+func (s *PartitionTestSuite) TestNoWriteNotNeeded(c *C) {
1145+ s.makeFakeUbootEnv(c)
1146+
1147+ atomiCall := false
1148+ atomicFileUpdate = func(a string, b []string) error { atomiCall = true; return atomicFileUpdateImpl(a, b) }
1149+
1150+ partition := New()
1151+ u := newUboot(partition)
1152+ c.Assert(u, NotNil)
1153+
1154+ c.Check(u.MarkCurrentBootSuccessful(), IsNil)
1155+ c.Assert(atomiCall, Equals, false)
1156+}
1157+
1158+func (s *PartitionTestSuite) TestWriteDueToMissingValues(c *C) {
1159+ s.makeFakeUbootEnv(c)
1160+
1161+ // this file needs specific data
1162+ c.Assert(ioutil.WriteFile(bootloaderUbootEnvFile, []byte(""), 0644), IsNil)
1163+
1164+ atomiCall := false
1165+ atomicFileUpdate = func(a string, b []string) error { atomiCall = true; return atomicFileUpdateImpl(a, b) }
1166+
1167+ partition := New()
1168+ u := newUboot(partition)
1169+ c.Assert(u, NotNil)
1170+
1171+ c.Check(u.MarkCurrentBootSuccessful(), IsNil)
1172+ c.Assert(atomiCall, Equals, true)
1173+
1174+ bytes, err := ioutil.ReadFile(bootloaderUbootEnvFile)
1175+ c.Assert(err, IsNil)
1176+ c.Check(strings.Contains(string(bytes), "snappy_mode=try"), Equals, false)
1177+ c.Check(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, true)
1178+ c.Check(strings.Contains(string(bytes), "snappy_ab=a"), Equals, true)
1179+}
1180
1181=== modified file 'partition/partition.go'
1182--- partition/partition.go 2015-07-01 14:48:33 +0000
1183+++ partition/partition.go 2015-07-06 19:58:38 +0000
1184@@ -583,6 +583,7 @@
1185 return errors.New("System is not dual root")
1186 }
1187
1188+<<<<<<< TREE
1189 bootloader, err := bootloader(p)
1190 if err != nil {
1191 return err
1192@@ -606,4 +607,23 @@
1193 }
1194
1195 return bootloader.BootDir()
1196+=======
1197+ bootloader, err := getBootloader(p)
1198+ if err != nil {
1199+ return err
1200+ }
1201+
1202+ // XXX: first toggle roofs and then handle assets? that seems
1203+ // wrong given that handleAssets may fails and we will
1204+ // knowingly boot into a broken system
1205+ err = p.RunWithOther(RW, func(otherRoot string) (err error) {
1206+ return bootloader.ToggleRootFS()
1207+ })
1208+
1209+ if err != nil {
1210+ return err
1211+ }
1212+
1213+ return bootloader.HandleAssets()
1214+>>>>>>> MERGE-SOURCE
1215 }
1216
1217=== modified file 'progress/progress.go'
1218=== modified file 'progress/progress_test.go'
1219=== modified file 'snappy/auth.go'
1220=== modified file 'snappy/auth_test.go'
1221=== modified file 'snappy/click.go'
1222--- snappy/click.go 2015-06-17 12:02:24 +0000
1223+++ snappy/click.go 2015-07-06 19:58:38 +0000
1224@@ -332,9 +332,15 @@
1225 AppArch string
1226 AppPath string
1227 Version string
1228+<<<<<<< TREE
1229 UdevAppName string
1230 Origin string
1231 Home string
1232+=======
1233+ UdevAppName string
1234+ Namespace string
1235+ Home string
1236+>>>>>>> MERGE-SOURCE
1237 Target string
1238 AaProfile string
1239 OldAppVars string
1240@@ -344,9 +350,15 @@
1241 AppArch: helpers.UbuntuArchitecture(),
1242 AppPath: pkgPath,
1243 Version: m.Version,
1244+<<<<<<< TREE
1245 UdevAppName: udevPartName,
1246 Origin: origin,
1247 Home: "$HOME",
1248+=======
1249+ UdevAppName: udevPartName,
1250+ Namespace: namespace,
1251+ Home: "$HOME",
1252+>>>>>>> MERGE-SOURCE
1253 Target: actualBinPath,
1254 AaProfile: aaProfile,
1255 }
1256@@ -736,6 +748,7 @@
1257
1258 func installClick(snapFile string, flags InstallFlags, inter progress.Meter, origin string) (name string, err error) {
1259 allowUnauthenticated := (flags & AllowUnauthenticated) != 0
1260+<<<<<<< TREE
1261 part, err := NewSnapPartFromSnapFile(snapFile, origin, allowUnauthenticated)
1262 if err != nil {
1263 return "", err
1264@@ -743,6 +756,251 @@
1265 defer part.deb.Close()
1266
1267 return part.Install(inter, flags)
1268+=======
1269+ if err := auditClick(snapFile, allowUnauthenticated); err != nil {
1270+ return "", err
1271+ // ?
1272+ //return SnapAuditError
1273+ }
1274+
1275+ d, err := clickdeb.Open(snapFile)
1276+ if err != nil {
1277+ return "", err
1278+ }
1279+ defer d.Close()
1280+
1281+ manifestData, err := d.ControlMember("manifest")
1282+ if err != nil {
1283+ log.Printf("Snap inspect failed: %s", snapFile)
1284+ return "", err
1285+ }
1286+
1287+ manifest, err := readClickManifest([]byte(manifestData))
1288+ if err != nil {
1289+ return "", err
1290+ }
1291+
1292+ yamlData, err := d.MetaMember("package.yaml")
1293+ if err != nil {
1294+ return "", err
1295+ }
1296+
1297+ m, err := parsePackageYamlData(yamlData)
1298+ if err != nil {
1299+ return "", err
1300+ }
1301+
1302+ if err := m.checkForPackageInstalled(namespace); err != nil {
1303+ return "", err
1304+ }
1305+
1306+ // verify we have a valid architecture
1307+ if !helpers.IsSupportedArchitecture(m.Architectures) {
1308+ return "", &ErrArchitectureNotSupported{m.Architectures}
1309+ }
1310+
1311+ if err := m.checkForNameClashes(); err != nil {
1312+ return "", err
1313+ }
1314+
1315+ if err := m.checkForFrameworks(); err != nil {
1316+ return "", err
1317+ }
1318+
1319+ targetDir := snapAppsDir
1320+ // the "oem" parts are special
1321+ if manifest.Type == SnapTypeOem {
1322+ targetDir = snapOemDir
1323+
1324+ // TODO do the following at a higher level once the store publishes snap types
1325+ // this is horrible
1326+ if allowOEM := (flags & AllowOEM) != 0; !allowOEM {
1327+ if currentOEM, err := getOem(); err == nil {
1328+ if currentOEM.Name != manifest.Name {
1329+ fmt.Println(currentOEM.Name, manifest.Name)
1330+ return "", ErrOEMPackageInstall
1331+ }
1332+ } else {
1333+ // there should always be an oem package now
1334+ return "", ErrOEMPackageInstall
1335+ }
1336+ }
1337+
1338+ if err := installOemHardwareUdevRules(m); err != nil {
1339+ return "", err
1340+ }
1341+ }
1342+
1343+ fullName := manifest.Name
1344+ // namespacing only applies to apps.
1345+ if manifest.Type != SnapTypeFramework && manifest.Type != SnapTypeOem {
1346+ fullName += "." + namespace
1347+ }
1348+ instDir := filepath.Join(targetDir, fullName, manifest.Version)
1349+ currentActiveDir, _ := filepath.EvalSymlinks(filepath.Join(instDir, "..", "current"))
1350+
1351+ if err := m.checkLicenseAgreement(inter, d, currentActiveDir); err != nil {
1352+ return "", err
1353+ }
1354+
1355+ dataDir := filepath.Join(snapDataDir, fullName, manifest.Version)
1356+
1357+ if err := helpers.EnsureDir(instDir, 0755); err != nil {
1358+ log.Printf("WARNING: Can not create %s", instDir)
1359+ }
1360+
1361+ // if anything goes wrong here we cleanup
1362+ defer func() {
1363+ if err != nil {
1364+ if e := os.RemoveAll(instDir); e != nil && !os.IsNotExist(e) {
1365+ log.Printf("Warning: failed to remove %s: %s", instDir, e)
1366+ }
1367+ }
1368+ }()
1369+
1370+ // we need to call the external helper so that we can reliable drop
1371+ // privs
1372+ if err := unpackWithDropPrivs(d, instDir); err != nil {
1373+ return "", err
1374+ }
1375+
1376+ // legacy, the hooks (e.g. apparmor) need this. Once we converted
1377+ // all hooks this can go away
1378+ clickMetaDir := path.Join(instDir, ".click", "info")
1379+ if err := os.MkdirAll(clickMetaDir, 0755); err != nil {
1380+ return "", err
1381+ }
1382+ if err := writeCompatManifestJSON(clickMetaDir, manifestData, namespace); err != nil {
1383+ return "", err
1384+ }
1385+
1386+ // write the hashes now
1387+ if err := writeHashesFile(d, instDir); err != nil {
1388+ return "", err
1389+ }
1390+
1391+ inhibitHooks := (flags & InhibitHooks) != 0
1392+
1393+ // deal with the data:
1394+ //
1395+ // if there was a previous version, stop it
1396+ // from being active so that it stops running and can no longer be
1397+ // started then copy the data
1398+ //
1399+ // otherwise just create a empty data dir
1400+ if currentActiveDir != "" {
1401+ oldManifest, err := readClickManifestFromClickDir(currentActiveDir)
1402+ if err != nil {
1403+ return "", err
1404+ }
1405+
1406+ // we need to stop making it active
1407+ err = unsetActiveClick(currentActiveDir, inhibitHooks, inter)
1408+ defer func() {
1409+ if err != nil {
1410+ if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
1411+ log.Printf("setting old version back to active failed: %v", cerr)
1412+ }
1413+ }
1414+ }()
1415+ if err != nil {
1416+ return "", err
1417+ }
1418+
1419+ err = copySnapData(fullName, oldManifest.Version, manifest.Version)
1420+ } else {
1421+ err = helpers.EnsureDir(dataDir, 0755)
1422+ }
1423+
1424+ defer func() {
1425+ if err != nil {
1426+ if cerr := removeSnapData(fullName, manifest.Version); cerr != nil {
1427+ log.Printf("when clenaning up data for %s %s: %v", manifest.Name, manifest.Version, cerr)
1428+ }
1429+ }
1430+ }()
1431+
1432+ if err != nil {
1433+ return "", err
1434+ }
1435+
1436+ // and finally make active
1437+ err = setActiveClick(instDir, inhibitHooks, inter)
1438+ defer func() {
1439+ if err != nil && currentActiveDir != "" {
1440+ if cerr := setActiveClick(currentActiveDir, inhibitHooks, inter); cerr != nil {
1441+ log.Printf("when setting old %s version back to active: %v", manifest.Name, cerr)
1442+ }
1443+ }
1444+ }()
1445+ if err != nil {
1446+ return "", err
1447+ }
1448+
1449+ // oh, one more thing: refresh the security bits
1450+ if !inhibitHooks {
1451+ part, err := NewSnapPartFromYaml(filepath.Join(instDir, "meta", "package.yaml"), namespace, m)
1452+ if err != nil {
1453+ return "", err
1454+ }
1455+
1456+ deps, err := part.Dependents()
1457+ if err != nil {
1458+ return "", err
1459+ }
1460+
1461+ sysd := systemd.New(globalRootDir, inter)
1462+ stopped := make(map[string]time.Duration)
1463+ defer func() {
1464+ if err != nil {
1465+ for serviceName := range stopped {
1466+ if e := sysd.Start(serviceName); e != nil {
1467+ inter.Notify(fmt.Sprintf("unable to restart %s with the old %s: %s", serviceName, part.Name(), e))
1468+ }
1469+ }
1470+ }
1471+ }()
1472+
1473+ for _, dep := range deps {
1474+ if !dep.IsActive() {
1475+ continue
1476+ }
1477+ for _, svc := range dep.Services() {
1478+ serviceName := filepath.Base(generateServiceFileName(dep.m, svc))
1479+ timeout := time.Duration(svc.StopTimeout)
1480+ if err = sysd.Stop(serviceName, timeout); err != nil {
1481+ inter.Notify(fmt.Sprintf("unable to stop %s; aborting install: %s", serviceName, err))
1482+ return "", err
1483+ }
1484+ stopped[serviceName] = timeout
1485+ }
1486+ }
1487+
1488+ if err := part.RefreshDependentsSecurity(currentActiveDir, inter); err != nil {
1489+ return "", err
1490+ }
1491+
1492+ started := make(map[string]time.Duration)
1493+ defer func() {
1494+ if err != nil {
1495+ for serviceName, timeout := range started {
1496+ if e := sysd.Stop(serviceName, timeout); e != nil {
1497+ inter.Notify(fmt.Sprintf("unable to stop %s with the old %s: %s", serviceName, part.Name(), e))
1498+ }
1499+ }
1500+ }
1501+ }()
1502+ for serviceName, timeout := range stopped {
1503+ if err = sysd.Start(serviceName); err != nil {
1504+ inter.Notify(fmt.Sprintf("unable to restart %s; aborting install: %s", serviceName, err))
1505+ return "", err
1506+ }
1507+ started[serviceName] = timeout
1508+ }
1509+ }
1510+
1511+ return manifest.Name, nil
1512+>>>>>>> MERGE-SOURCE
1513 }
1514
1515 // removeSnapData removes the data for the given version of the given snap
1516
1517=== modified file 'snappy/click_test.go'
1518=== modified file 'snappy/errors.go'
1519--- snappy/errors.go 2015-06-30 12:30:02 +0000
1520+++ snappy/errors.go 2015-07-06 19:58:38 +0000
1521@@ -138,13 +138,20 @@
1522
1523 // ErrInvalidPart is returned when something on the filesystem does not make sense
1524 ErrInvalidPart = errors.New("invalid package on system")
1525+<<<<<<< TREE
1526
1527 // ErrInvalidSeccompPolicy is returned when policy-version and policy-vender are not set together
1528 ErrInvalidSeccompPolicy = errors.New("policy-version and policy-vendor must be specified together")
1529 // ErrNoSeccompPolicy is returned when an expected seccomp policy is not provided.
1530 ErrNoSeccompPolicy = errors.New("no seccomp policy provided")
1531+=======
1532+
1533+ // ErrNoSeccompPolicy is returned when an expected seccomp policy is not provided.
1534+ ErrNoSeccompPolicy = errors.New("no seccomp policy provided")
1535+>>>>>>> MERGE-SOURCE
1536 )
1537
1538+<<<<<<< TREE
1539 // ErrDownload represents a download error
1540 type ErrDownload struct {
1541 code int
1542@@ -165,6 +172,18 @@
1543 return fmt.Sprintf("package's supported architectures (%s) is incompatible with this system (%s)", strings.Join(e.architectures, ", "), helpers.UbuntuArchitecture())
1544 }
1545
1546+=======
1547+// ErrArchitectureNotSupported is returned when trying to install a snappy package that
1548+// is not supported on the system
1549+type ErrArchitectureNotSupported struct {
1550+ architectures []string
1551+}
1552+
1553+func (e *ErrArchitectureNotSupported) Error() string {
1554+ return fmt.Sprintf("package's supported architectures (%s) is incompatible with this system (%s)", strings.Join(e.architectures, ", "), helpers.UbuntuArchitecture())
1555+}
1556+
1557+>>>>>>> MERGE-SOURCE
1558 // ErrInstallFailed is an error type for installation errors for snaps
1559 type ErrInstallFailed struct {
1560 snap string
1561@@ -184,7 +203,11 @@
1562 }
1563
1564 func (e *ErrHookFailed) Error() string {
1565+<<<<<<< TREE
1566 return fmt.Sprintf("hook command %v failed with exit status %d (output: %q)", e.cmd, e.exitCode, e.output)
1567+=======
1568+ return fmt.Sprintf("hook command %v failed with exit status %d (output: '%s')", e.cmd, e.exitCode, e.output)
1569+>>>>>>> MERGE-SOURCE
1570 }
1571
1572 // ErrDataCopyFailed is returned if copying the snap data fialed
1573
1574=== modified file 'snappy/security.go'
1575--- snappy/security.go 2015-06-24 17:05:21 +0000
1576+++ snappy/security.go 2015-07-06 19:58:38 +0000
1577@@ -151,11 +151,18 @@
1578 syscalls := []string{}
1579
1580 if sd.SecurityOverride != nil {
1581+<<<<<<< TREE
1582 if sd.SecurityOverride.Seccomp == "" {
1583 logger.Noticef("No seccomp policy found")
1584 return nil, ErrNoSeccompPolicy
1585 }
1586
1587+=======
1588+ if sd.SecurityOverride.Seccomp == "" {
1589+ return nil, ErrNoSeccompPolicy
1590+ }
1591+
1592+>>>>>>> MERGE-SOURCE
1593 fn := filepath.Join(baseDir, sd.SecurityOverride.Seccomp)
1594 var s securitySeccompOverride
1595 err := readSeccompOverride(fn, &s)
1596
1597=== modified file 'snappy/security_test.go'
1598=== modified file 'snappy/snapp.go'
1599--- snappy/snapp.go 2015-07-06 17:12:53 +0000
1600+++ snappy/snapp.go 2015-07-06 19:58:38 +0000
1601@@ -40,9 +40,13 @@
1602
1603 "launchpad.net/snappy/clickdeb"
1604 "launchpad.net/snappy/helpers"
1605+<<<<<<< TREE
1606 "launchpad.net/snappy/logger"
1607 "launchpad.net/snappy/oauth"
1608 "launchpad.net/snappy/pkg"
1609+=======
1610+ "launchpad.net/snappy/oauth"
1611+>>>>>>> MERGE-SOURCE
1612 "launchpad.net/snappy/policy"
1613 "launchpad.net/snappy/progress"
1614 "launchpad.net/snappy/release"
1615@@ -1866,6 +1870,7 @@
1616 // are required when calling a meta/hook/ script and that will override
1617 // any already existing SNAP_* variables in os.Environment()
1618 func makeSnapHookEnv(part *SnapPart) (env []string) {
1619+<<<<<<< TREE
1620 desc := struct {
1621 AppName string
1622 AppArch string
1623@@ -1880,6 +1885,22 @@
1624 part.Version(),
1625 QualifiedName(part),
1626 part.Origin(),
1627+=======
1628+ desc := struct {
1629+ AppName string
1630+ AppArch string
1631+ AppPath string
1632+ Version string
1633+ UdevAppName string
1634+ Namespace string
1635+ }{
1636+ part.Name(),
1637+ helpers.UbuntuArchitecture(),
1638+ part.basedir,
1639+ part.Version(),
1640+ Dirname(part),
1641+ part.Namespace(),
1642+>>>>>>> MERGE-SOURCE
1643 }
1644 snapEnv := helpers.MakeMapFromEnvList(helpers.GetBasicSnapEnvVars(desc))
1645
1646
1647=== modified file 'snappy/snapp_test.go'
1648--- snappy/snapp_test.go 2015-06-30 02:32:37 +0000
1649+++ snappy/snapp_test.go 2015-07-06 19:58:38 +0000
1650@@ -747,6 +747,7 @@
1651 c.Check(p.notified[0], Matches, "Waiting for .* stop.")
1652 }
1653
1654+<<<<<<< TREE
1655 func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
1656 const packageHello = `name: hello-app
1657 version: 1.10
1658@@ -766,6 +767,24 @@
1659 c.Assert(err.Error(), Equals, errorMsg)
1660 }
1661
1662+=======
1663+func (s *SnapTestSuite) TestErrorOnUnsupportedArchitecture(c *C) {
1664+ const packageHello = `name: hello-app
1665+version: 1.10
1666+vendor: Somebody
1667+icon: meta/hello.svg
1668+architectures:
1669+ - yadayada
1670+ - blahblah
1671+`
1672+
1673+ snapPkg := makeTestSnapPackage(c, packageHello)
1674+ _, err := installClick(snapPkg, 0, nil, testNamespace)
1675+ errorMsg := fmt.Sprintf("package's supported architectures (yadayada, blahblah) is incompatible with this system (%s)", helpers.UbuntuArchitecture())
1676+ c.Assert(err.Error(), Equals, errorMsg)
1677+}
1678+
1679+>>>>>>> MERGE-SOURCE
1680 func (s *SnapTestSuite) TestRemoteSnapErrors(c *C) {
1681 snap := RemoteSnapPart{}
1682
1683
1684=== modified file 'snappy/systemimage.go'
1685--- snappy/systemimage.go 2015-07-01 14:48:33 +0000
1686+++ snappy/systemimage.go 2015-07-06 19:58:38 +0000
1687@@ -191,10 +191,17 @@
1688
1689 // Ensure there is always a kernel + initrd to boot with, even
1690 // if the update does not provide new versions.
1691+<<<<<<< TREE
1692 if pb != nil {
1693 pb.Notify("Syncing boot files")
1694 }
1695 err = s.partition.SyncBootloaderFiles(bootAssetFilePaths())
1696+=======
1697+ if pb != nil {
1698+ pb.Notify("Syncing boot files")
1699+ }
1700+ err = s.partition.SyncBootloaderFiles()
1701+>>>>>>> MERGE-SOURCE
1702 if err != nil {
1703 return "", err
1704 }
1705
1706=== modified file 'snappy/systemimage_native.go'
1707=== modified file 'systemd/systemd.go'
1708--- systemd/systemd.go 2015-06-05 18:29:52 +0000
1709+++ systemd/systemd.go 2015-07-06 19:58:38 +0000
1710@@ -208,10 +208,17 @@
1711 FullPathPostStop string
1712 AppTriple string
1713 ServiceSystemdTarget string
1714+<<<<<<< TREE
1715 Origin string
1716 AppArch string
1717 Home string
1718 EnvVars string
1719+=======
1720+ Namespace string
1721+ AppArch string
1722+ Home string
1723+ EnvVars string
1724+>>>>>>> MERGE-SOURCE
1725 }{
1726 *desc,
1727 filepath.Join(desc.AppPath, desc.Start),
1728@@ -219,10 +226,17 @@
1729 filepath.Join(desc.AppPath, desc.PostStop),
1730 fmt.Sprintf("%s_%s_%s", desc.AppName, desc.ServiceName, desc.Version),
1731 servicesSystemdTarget,
1732+<<<<<<< TREE
1733 origin,
1734 helpers.UbuntuArchitecture(),
1735 "%h",
1736 "",
1737+=======
1738+ namespace,
1739+ helpers.UbuntuArchitecture(),
1740+ "%h",
1741+ "",
1742+>>>>>>> MERGE-SOURCE
1743 }
1744 allVars := helpers.GetBasicSnapEnvVars(wrapperData)
1745 allVars = append(allVars, helpers.GetUserSnapEnvVars(wrapperData)...)
1746
1747=== modified file 'systemd/systemd_test.go'
1748--- systemd/systemd_test.go 2015-06-05 18:29:52 +0000
1749+++ systemd/systemd_test.go 2015-07-06 19:58:38 +0000
1750@@ -26,9 +26,15 @@
1751 "testing"
1752 "time"
1753
1754+<<<<<<< TREE
1755 . "gopkg.in/check.v1"
1756
1757 "launchpad.net/snappy/helpers"
1758+=======
1759+ . "launchpad.net/gocheck"
1760+
1761+ "launchpad.net/snappy/helpers"
1762+>>>>>>> MERGE-SOURCE
1763 )
1764
1765 type testreporter struct {

Subscribers

People subscribed via source and target branches