vendor: update docker to e7b5f7dbe98c
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-19.03
parent
4eb544e319
commit
d8cd5f49cd
2
go.mod
2
go.mod
|
@ -17,7 +17,7 @@ require (
|
|||
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142 // indirect
|
||||
github.com/docker/cli v0.0.0-20190131223713-234462756460
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
|
||||
github.com/docker/docker v0.7.3-0.20180531152204-71cd53e4a197
|
||||
github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c
|
||||
github.com/docker/docker-credential-helpers v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.3.0
|
||||
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad // indirect
|
||||
|
|
5
go.sum
5
go.sum
|
@ -33,9 +33,10 @@ github.com/docker/cli v0.0.0-20190131223713-234462756460 h1:pil/Gt3dlnN7WIX+6uS3
|
|||
github.com/docker/cli v0.0.0-20190131223713-234462756460/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197 h1:raQhUHOMIAZAWHmo3hLEwoIy0aVkKb2uxZdWw/Up+HI=
|
||||
github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v0.7.3-0.20180531152204-71cd53e4a197 h1:xjQaPxUee5t0z4hTzMWDAJLQ5InCoNS5eMfRdyvG9/o=
|
||||
github.com/docker/docker v0.7.3-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c h1:rZ+3jNsgjvYgdZ0Nrd4Udrv8rneDbWBohAPuXsTsvGU=
|
||||
github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.0 h1:5bhDRLn1roGiNjz8IezRngHxMfoeaXGyr0BeMHq4rD8=
|
||||
github.com/docker/docker-credential-helpers v0.6.0/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/go-connections v0.3.0 h1:3lOnM9cSzgGwx8VfK/NGOW5fLQ0GjIlCkaktF+n1M6o=
|
||||
|
|
|
@ -201,6 +201,7 @@ Ben Severson <BenSeverson@users.noreply.github.com>
|
|||
Ben Toews <mastahyeti@gmail.com>
|
||||
Ben Wiklund <ben@daisyowl.com>
|
||||
Benjamin Atkin <ben@benatkin.com>
|
||||
Benjamin Baker <Benjamin.baker@utexas.edu>
|
||||
Benjamin Boudreau <boudreau.benjamin@gmail.com>
|
||||
Benjamin Yolken <yolken@stripe.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
|
@ -246,6 +247,7 @@ Brian Torres-Gil <brian@dralth.com>
|
|||
Brian Trump <btrump@yelp.com>
|
||||
Brice Jaglin <bjaglin@teads.tv>
|
||||
Briehan Lombaard <briehan.lombaard@gmail.com>
|
||||
Brielle Broder <bbroder@google.com>
|
||||
Bruno Bigras <bigras.bruno@gmail.com>
|
||||
Bruno Binet <bruno.binet@gmail.com>
|
||||
Bruno Gazzera <bgazzera@paginar.com>
|
||||
|
@ -325,9 +327,11 @@ Chris Swan <chris.swan@iee.org>
|
|||
Chris Telfer <ctelfer@docker.com>
|
||||
Chris Wahl <github@wahlnetwork.com>
|
||||
Chris Weyl <cweyl@alumni.drew.edu>
|
||||
Chris White <me@cwprogram.com>
|
||||
Christian Berendt <berendt@b1-systems.de>
|
||||
Christian Brauner <christian.brauner@ubuntu.com>
|
||||
Christian Böhme <developement@boehme3d.de>
|
||||
Christian Muehlhaeuser <muesli@gmail.com>
|
||||
Christian Persson <saser@live.se>
|
||||
Christian Rotzoll <ch.rotzoll@gmail.com>
|
||||
Christian Simon <simon@swine.de>
|
||||
|
@ -444,6 +448,7 @@ David Röthlisberger <david@rothlis.net>
|
|||
David Sheets <dsheets@docker.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
David Trott <github@davidtrott.com>
|
||||
David Wang <00107082@163.com>
|
||||
David Williamson <david.williamson@docker.com>
|
||||
David Xia <dxia@spotify.com>
|
||||
David Young <yangboh@cn.ibm.com>
|
||||
|
@ -451,6 +456,7 @@ Davide Ceretti <davide.ceretti@hogarthww.com>
|
|||
Dawn Chen <dawnchen@google.com>
|
||||
dbdd <wangtong2712@gmail.com>
|
||||
dcylabs <dcylabs@gmail.com>
|
||||
Debayan De <debayande@users.noreply.github.com>
|
||||
Deborah Gertrude Digges <deborah.gertrude.digges@gmail.com>
|
||||
deed02392 <georgehafiz@gmail.com>
|
||||
Deng Guangxing <dengguangxing@huawei.com>
|
||||
|
@ -503,6 +509,7 @@ Don Kjer <don.kjer@gmail.com>
|
|||
Don Spaulding <donspauldingii@gmail.com>
|
||||
Donald Huang <don.hcd@gmail.com>
|
||||
Dong Chen <dongluo.chen@docker.com>
|
||||
Donghwa Kim <shanytt@gmail.com>
|
||||
Donovan Jones <git@gamma.net.nz>
|
||||
Doron Podoleanu <doronp@il.ibm.com>
|
||||
Doug Davis <dug@us.ibm.com>
|
||||
|
@ -580,6 +587,7 @@ Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
|
|||
ezbercih <cem.ezberci@gmail.com>
|
||||
Ezra Silvera <ezra@il.ibm.com>
|
||||
Fabian Lauer <kontakt@softwareschmiede-saar.de>
|
||||
Fabian Raetz <fabian.raetz@gmail.com>
|
||||
Fabiano Rosas <farosas@br.ibm.com>
|
||||
Fabio Falci <fabiofalci@gmail.com>
|
||||
Fabio Kung <fabio.kung@gmail.com>
|
||||
|
@ -591,6 +599,7 @@ Faiz Khan <faizkhan00@gmail.com>
|
|||
falmp <chico.lopes@gmail.com>
|
||||
Fangming Fang <fangming.fang@arm.com>
|
||||
Fangyuan Gao <21551127@zju.edu.cn>
|
||||
fanjiyun <fan.jiyun@zte.com.cn>
|
||||
Fareed Dudhia <fareeddudhia@googlemail.com>
|
||||
Fathi Boudra <fathi.boudra@linaro.org>
|
||||
Federico Gimenez <fgimenez@coit.es>
|
||||
|
@ -621,6 +630,7 @@ Florin Patan <florinpatan@gmail.com>
|
|||
fonglh <fonglh@gmail.com>
|
||||
Foysal Iqbal <foysal.iqbal.fb@gmail.com>
|
||||
Francesc Campoy <campoy@google.com>
|
||||
Francesco Mari <mari.francesco@gmail.com>
|
||||
Francis Chuang <francis.chuang@boostport.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
|
@ -653,6 +663,7 @@ Gaël PORTAY <gael.portay@savoirfairelinux.com>
|
|||
Genki Takiuchi <genki@s21g.com>
|
||||
GennadySpb <lipenkov@gmail.com>
|
||||
Geoffrey Bachelet <grosfrais@gmail.com>
|
||||
Geon Kim <geon0250@gmail.com>
|
||||
George Kontridze <george@bugsnag.com>
|
||||
George MacRorie <gmacr31@gmail.com>
|
||||
George Xie <georgexsh@gmail.com>
|
||||
|
@ -676,6 +687,7 @@ Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
|
|||
Gosuke Miyashita <gosukenator@gmail.com>
|
||||
Gou Rao <gou@portworx.com>
|
||||
Govinda Fichtner <govinda.fichtner@googlemail.com>
|
||||
Grant Millar <grant@cylo.io>
|
||||
Grant Reaber <grant.reaber@gmail.com>
|
||||
Graydon Hoare <graydon@pobox.com>
|
||||
Greg Fausak <greg@tacodata.com>
|
||||
|
@ -694,6 +706,7 @@ Guruprasad <lgp171188@gmail.com>
|
|||
Gustav Sinder <gustav.sinder@gmail.com>
|
||||
gwx296173 <gaojing3@huawei.com>
|
||||
Günter Zöchbauer <guenter@gzoechbauer.com>
|
||||
haikuoliu <haikuo@amazon.com>
|
||||
Hakan Özler <hakan.ozler@kodcu.com>
|
||||
Hans Kristian Flaatten <hans@starefossen.com>
|
||||
Hans Rødtang <hansrodtang@gmail.com>
|
||||
|
@ -735,6 +748,7 @@ Ian Bishop <ianbishop@pace7.com>
|
|||
Ian Bull <irbull@gmail.com>
|
||||
Ian Calvert <ianjcalvert@gmail.com>
|
||||
Ian Campbell <ian.campbell@docker.com>
|
||||
Ian Chen <ianre657@gmail.com>
|
||||
Ian Lee <IanLee1521@gmail.com>
|
||||
Ian Main <imain@redhat.com>
|
||||
Ian Philpot <ian.philpot@microsoft.com>
|
||||
|
@ -755,6 +769,7 @@ Ingo Gottwald <in.gottwald@gmail.com>
|
|||
Isaac Dupree <antispam@idupree.com>
|
||||
Isabel Jimenez <contact.isabeljimenez@gmail.com>
|
||||
Isao Jonas <isao.jonas@gmail.com>
|
||||
Iskander Sharipov <quasilyte@gmail.com>
|
||||
Ivan Babrou <ibobrik@gmail.com>
|
||||
Ivan Fraixedes <ifcdev@gmail.com>
|
||||
Ivan Grcic <igrcic@gmail.com>
|
||||
|
@ -847,7 +862,7 @@ Jeroen Franse <jeroenfranse@gmail.com>
|
|||
Jeroen Jacobs <github@jeroenj.be>
|
||||
Jesse Dearing <jesse.dearing@gmail.com>
|
||||
Jesse Dubay <jesse@thefortytwo.net>
|
||||
Jessica Frazelle <jessfraz@google.com>
|
||||
Jessica Frazelle <acidburn@microsoft.com>
|
||||
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
||||
Jhon Honce <jhonce@redhat.com>
|
||||
Ji.Zhilong <zhilongji@gmail.com>
|
||||
|
@ -983,6 +998,7 @@ Karl Grzeszczak <karlgrz@gmail.com>
|
|||
Karol Duleba <mr.fuxi@gmail.com>
|
||||
Karthik Karanth <karanth.karthik@gmail.com>
|
||||
Karthik Nayak <Karthik.188@gmail.com>
|
||||
Kasper Fabæch Brandt <poizan@poizan.dk>
|
||||
Kate Heddleston <kate.heddleston@gmail.com>
|
||||
Katie McLaughlin <katie@glasnt.com>
|
||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||
|
@ -990,6 +1006,7 @@ Katrina Owen <katrina.owen@gmail.com>
|
|||
Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
|
||||
Kay Yan <kay.yan@daocloud.io>
|
||||
kayrus <kay.diam@gmail.com>
|
||||
Kazuhiro Sera <seratch@gmail.com>
|
||||
Ke Li <kel@splunk.com>
|
||||
Ke Xu <leonhartx.k@gmail.com>
|
||||
Kei Ohmura <ohmura.kei@gmail.com>
|
||||
|
@ -998,6 +1015,7 @@ Keli Hu <dev@keli.hu>
|
|||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Ken Herner <kherner@progress.com>
|
||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||
Ken Reese <krrgithub@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
Kenjiro Nakayama <nakayamakenjiro@gmail.com>
|
||||
Kent Johnson <kentoj@gmail.com>
|
||||
|
@ -1035,9 +1053,9 @@ Krasimir Georgiev <support@vip-consult.co.uk>
|
|||
Kris-Mikael Krister <krismikael@protonmail.com>
|
||||
Kristian Haugene <kristian.haugene@capgemini.com>
|
||||
Kristina Zabunova <triara.xiii@gmail.com>
|
||||
krrg <krrgithub@gmail.com>
|
||||
Kun Zhang <zkazure@gmail.com>
|
||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||
Kunal Tyagi <tyagi.kunal@live.com>
|
||||
Kyle Conroy <kyle.j.conroy@gmail.com>
|
||||
Kyle Linden <linden.kyle@gmail.com>
|
||||
kyu <leehk1227@gmail.com>
|
||||
|
@ -1060,6 +1078,7 @@ Leandro Siqueira <leandro.siqueira@gmail.com>
|
|||
Lee Chao <932819864@qq.com>
|
||||
Lee, Meng-Han <sunrisedm4@gmail.com>
|
||||
leeplay <hyeongkyu.lee@navercorp.com>
|
||||
Lei Gong <lgong@alauda.io>
|
||||
Lei Jitang <leijitang@huawei.com>
|
||||
Len Weincier <len@cloudafrica.net>
|
||||
Lennie <github@consolejunkie.net>
|
||||
|
@ -1095,6 +1114,7 @@ Lokesh Mandvekar <lsm5@fedoraproject.org>
|
|||
longliqiang88 <394564827@qq.com>
|
||||
Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
|
||||
Lorenzo Fontana <lo@linux.com>
|
||||
Lotus Fenn <fenn.lotus@gmail.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Luca Favatella <luca.favatella@erlang-solutions.com>
|
||||
Luca Marturana <lucamarturana@gmail.com>
|
||||
|
@ -1167,6 +1187,7 @@ Martijn van Oosterhout <kleptog@svana.org>
|
|||
Martin Honermeyer <maze@strahlungsfrei.de>
|
||||
Martin Kelly <martin@surround.io>
|
||||
Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
|
||||
Martin Muzatko <martin@happy-css.com>
|
||||
Martin Redmond <redmond.martin@gmail.com>
|
||||
Mary Anthony <mary.anthony@docker.com>
|
||||
Masahito Zembutsu <zembutsu@users.noreply.github.com>
|
||||
|
@ -1248,8 +1269,9 @@ Michal Wieczorek <wieczorek-michal@wp.pl>
|
|||
Michaël Pailloncy <mpapo.dev@gmail.com>
|
||||
Michał Czeraszkiewicz <czerasz@gmail.com>
|
||||
Michał Gryko <github@odkurzacz.org>
|
||||
Michiel@unhosted <michiel@unhosted.org>
|
||||
Mickaël FORTUNATO <morsi.morsicus@gmail.com>
|
||||
Michiel de Jong <michiel@unhosted.org>
|
||||
Mickaël Fortunato <morsi.morsicus@gmail.com>
|
||||
Mickaël Remars <mickael@remars.com>
|
||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||
Miguel Morales <mimoralea@gmail.com>
|
||||
Mihai Borobocea <MihaiBorob@gmail.com>
|
||||
|
@ -1337,6 +1359,7 @@ Nicolas Dudebout <nicolas.dudebout@gatech.edu>
|
|||
Nicolas Goy <kuon@goyman.com>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
Nicolas Sterchele <sterchele.nicolas@gmail.com>
|
||||
Nicolas V Castet <nvcastet@us.ibm.com>
|
||||
Nicolás Hock Isaza <nhocki@gmail.com>
|
||||
Nigel Poulton <nigelpoulton@hotmail.com>
|
||||
Nik Nyby <nikolas@gnu.org>
|
||||
|
@ -1452,6 +1475,7 @@ Prasanna Gautam <prasannagautam@gmail.com>
|
|||
Pratik Karki <prertik@outlook.com>
|
||||
Prayag Verma <prayag.verma@gmail.com>
|
||||
Priya Wadhwa <priyawadhwa@google.com>
|
||||
Projjol Banerji <probaner23@gmail.com>
|
||||
Przemek Hejman <przemyslaw.hejman@gmail.com>
|
||||
Pure White <daniel48@126.com>
|
||||
pysqz <randomq@126.com>
|
||||
|
@ -1546,6 +1570,7 @@ Rozhnov Alexandr <nox73@ya.ru>
|
|||
Rudolph Gottesheim <r.gottesheim@loot.at>
|
||||
Rui Lopes <rgl@ruilopes.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
Russ Magee <rmagee@gmail.com>
|
||||
Ryan Abrams <rdabrams@gmail.com>
|
||||
Ryan Anderson <anderson.ryanc@gmail.com>
|
||||
Ryan Aslett <github@mixologic.com>
|
||||
|
@ -1572,6 +1597,7 @@ Sachin Joshi <sachin_jayant_joshi@hotmail.com>
|
|||
Sagar Hani <sagarhani33@gmail.com>
|
||||
Sainath Grandhi <sainath.grandhi@intel.com>
|
||||
Sakeven Jiang <jc5930@sina.cn>
|
||||
Salahuddin Khan <salah@docker.com>
|
||||
Sally O'Malley <somalley@redhat.com>
|
||||
Sam Abed <sam.abed@gmail.com>
|
||||
Sam Alba <sam.alba@gmail.com>
|
||||
|
@ -1620,6 +1646,7 @@ Sergey Alekseev <sergey.alekseev.minsk@gmail.com>
|
|||
Sergey Evstifeev <sergey.evstifeev@gmail.com>
|
||||
Sergii Kabashniuk <skabashnyuk@codenvy.com>
|
||||
Serhat Gülçiçek <serhat25@gmail.com>
|
||||
SeungUkLee <lsy931106@gmail.com>
|
||||
Sevki Hasirci <s@sevki.org>
|
||||
Shane Canon <scanon@lbl.gov>
|
||||
Shane da Silva <shane@dasilva.io>
|
||||
|
@ -1714,10 +1741,11 @@ tang0th <tang0th@gmx.com>
|
|||
Tangi Colin <tangicolin@gmail.com>
|
||||
Tatsuki Sugiura <sugi@nemui.org>
|
||||
Tatsushi Inagaki <e29253@jp.ibm.com>
|
||||
Taylan Isikdemir <taylani@google.com>
|
||||
Taylor Jones <monitorjbl@gmail.com>
|
||||
tbonza <tylers.pile@gmail.com>
|
||||
Ted M. Young <tedyoung@gmail.com>
|
||||
Tehmasp Chaudhri <tehmasp@gmail.com>
|
||||
Tejaswini Duggaraju <naduggar@microsoft.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com>
|
||||
terryding77 <550147740@qq.com>
|
||||
tgic <farmer1992@gmail.com>
|
||||
|
@ -1811,6 +1839,7 @@ Tristan Carel <tristan@cogniteev.com>
|
|||
Troy Denton <trdenton@gmail.com>
|
||||
Tycho Andersen <tycho@docker.com>
|
||||
Tyler Brock <tyler.brock@gmail.com>
|
||||
Tyler Brown <tylers.pile@gmail.com>
|
||||
Tzu-Jung Lee <roylee17@gmail.com>
|
||||
uhayate <uhayate.gong@daocloud.io>
|
||||
Ulysse Carion <ulyssecarion@gmail.com>
|
||||
|
@ -1906,11 +1935,13 @@ XiaoBing Jiang <s7v7nislands@gmail.com>
|
|||
Xiaoxu Chen <chenxiaoxu14@otcaix.iscas.ac.cn>
|
||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||
xiekeyang <xiekeyang@huawei.com>
|
||||
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
|
||||
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
|
||||
Xinzi Zhou <imdreamrunner@gmail.com>
|
||||
Xiuming Chen <cc@cxm.cc>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
xuzhaokui <cynicholas@gmail.com>
|
||||
Yadnyawalkya Tale <ytale@redhat.com>
|
||||
Yahya <ya7yaz@gmail.com>
|
||||
YAMADA Tsuyoshi <tyamada@minimum2scp.org>
|
||||
Yamasaki Masahide <masahide.y@gmail.com>
|
||||
|
@ -1941,6 +1972,7 @@ Yu-Ju Hong <yjhong@google.com>
|
|||
Yuan Sun <sunyuan3@huawei.com>
|
||||
Yuanhong Peng <pengyuanhong@huawei.com>
|
||||
Yuhao Fang <fangyuhao@gmail.com>
|
||||
Yuichiro Kaneko <spiketeika@gmail.com>
|
||||
Yunxiang Huang <hyxqshk@vip.qq.com>
|
||||
Yurii Rashkovskii <yrashk@gmail.com>
|
||||
Yves Junqueira <yves.junqueira@gmail.com>
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2017 Docker, Inc.
|
||||
Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -244,6 +244,16 @@ func (n PidMode) Container() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// DeviceRequest represents a request for devices from a device driver.
|
||||
// Used by GPU device drivers.
|
||||
type DeviceRequest struct {
|
||||
Driver string // Name of device driver
|
||||
Count int // Number of devices to request (-1 = All)
|
||||
DeviceIDs []string // List of device IDs as recognizable by the device driver
|
||||
Capabilities [][]string // An OR list of AND lists of device capabilities (e.g. "gpu")
|
||||
Options map[string]string // Options to pass onto the device driver
|
||||
}
|
||||
|
||||
// DeviceMapping represents the device mapping between the host and the container.
|
||||
type DeviceMapping struct {
|
||||
PathOnHost string
|
||||
|
@ -327,13 +337,15 @@ type Resources struct {
|
|||
CpusetMems string // CpusetMems 0-2, 0,1
|
||||
Devices []DeviceMapping // List of devices to map inside the container
|
||||
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
||||
DeviceRequests []DeviceRequest // List of device requests for device drivers
|
||||
DiskQuota int64 // Disk limit (in bytes)
|
||||
KernelMemory int64 // Kernel memory limit (in bytes)
|
||||
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
|
||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
||||
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
||||
OomKillDisable *bool // Whether to disable OOM Killer or not
|
||||
PidsLimit int64 // Setting pids limit for a container
|
||||
PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change.
|
||||
Ulimits []*units.Ulimit // List of ulimits to be set in the container
|
||||
|
||||
// Applicable to Windows
|
||||
|
@ -369,6 +381,7 @@ type HostConfig struct {
|
|||
// Applicable to UNIX platforms
|
||||
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
||||
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
||||
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
|
||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||
|
@ -401,6 +414,12 @@ type HostConfig struct {
|
|||
// Mounts specs used by the container
|
||||
Mounts []mount.Mount `json:",omitempty"`
|
||||
|
||||
// MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths)
|
||||
MaskedPaths []string
|
||||
|
||||
// ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths)
|
||||
ReadonlyPaths []string
|
||||
|
||||
// Run a custom init inside the container, if null, use the daemon's configured settings
|
||||
Init *bool `json:",omitempty"`
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ const (
|
|||
// BindOptions defines options specific to mounts of type "bind".
|
||||
type BindOptions struct {
|
||||
Propagation Propagation `json:",omitempty"`
|
||||
NonRecursive bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
// VolumeOptions represents the options for a mount of type volume.
|
||||
|
|
|
@ -52,7 +52,7 @@ type (
|
|||
NoLchown bool
|
||||
UIDMaps []idtools.IDMap
|
||||
GIDMaps []idtools.IDMap
|
||||
ChownOpts *idtools.IDPair
|
||||
ChownOpts *idtools.Identity
|
||||
IncludeSourceDir bool
|
||||
// WhiteoutFormat is the expected on disk format for whiteout files.
|
||||
// This format will be converted to the standard format on pack
|
||||
|
@ -73,12 +73,12 @@ type (
|
|||
// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
|
||||
type Archiver struct {
|
||||
Untar func(io.Reader, string, *TarOptions) error
|
||||
IDMappingsVar *idtools.IDMappings
|
||||
IDMapping *idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// NewDefaultArchiver returns a new Archiver without any IDMappings
|
||||
// NewDefaultArchiver returns a new Archiver without any IdentityMapping
|
||||
func NewDefaultArchiver() *Archiver {
|
||||
return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}}
|
||||
return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
|
||||
}
|
||||
|
||||
// breakoutError is used to differentiate errors related to breaking out
|
||||
|
@ -127,6 +127,7 @@ func IsArchivePath(path string) bool {
|
|||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer rdr.Close()
|
||||
r := tar.NewReader(rdr)
|
||||
_, err = r.Next()
|
||||
return err == nil
|
||||
|
@ -366,11 +367,7 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
|
|||
hdr.AccessTime = time.Time{}
|
||||
hdr.ChangeTime = time.Time{}
|
||||
hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
|
||||
name, err = canonicalTarName(name, fi.IsDir())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tar: cannot canonicalize path: %v", err)
|
||||
}
|
||||
hdr.Name = name
|
||||
hdr.Name = canonicalTarName(name, fi.IsDir())
|
||||
if err := setHeaderForSpecialDevice(hdr, name, fi.Sys()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -424,8 +421,8 @@ type tarAppender struct {
|
|||
|
||||
// for hardlink mapping
|
||||
SeenFiles map[uint64]string
|
||||
IDMappings *idtools.IDMappings
|
||||
ChownOpts *idtools.IDPair
|
||||
IdentityMapping *idtools.IdentityMapping
|
||||
ChownOpts *idtools.Identity
|
||||
|
||||
// For packing and unpacking whiteout files in the
|
||||
// non standard format. The whiteout files defined
|
||||
|
@ -434,29 +431,26 @@ type tarAppender struct {
|
|||
WhiteoutConverter tarWhiteoutConverter
|
||||
}
|
||||
|
||||
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
|
||||
func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
|
||||
return &tarAppender{
|
||||
SeenFiles: make(map[uint64]string),
|
||||
TarWriter: tar.NewWriter(writer),
|
||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||
IDMappings: idMapping,
|
||||
IdentityMapping: idMapping,
|
||||
ChownOpts: chownOpts,
|
||||
}
|
||||
}
|
||||
|
||||
// canonicalTarName provides a platform-independent and consistent posix-style
|
||||
//path for files and directories to be archived regardless of the platform.
|
||||
func canonicalTarName(name string, isDir bool) (string, error) {
|
||||
name, err := CanonicalTarNameForPath(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
func canonicalTarName(name string, isDir bool) string {
|
||||
name = CanonicalTarNameForPath(name)
|
||||
|
||||
// suffix with '/' for directories
|
||||
if isDir && !strings.HasSuffix(name, "/") {
|
||||
name += "/"
|
||||
}
|
||||
return name, nil
|
||||
return name
|
||||
}
|
||||
|
||||
// addTarFile adds to the tar archive a file from `path` as `name`
|
||||
|
@ -508,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
//handle re-mapping container ID mappings back to host ID mappings before
|
||||
//writing tar headers/files. We skip whiteout files because they were written
|
||||
//by the kernel and already have proper ownership relative to the host
|
||||
if !isOverlayWhiteout &&
|
||||
!strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) &&
|
||||
!ta.IDMappings.Empty() {
|
||||
if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
|
||||
fileIDPair, err := getFileUIDGID(fi.Sys())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair)
|
||||
hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -578,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
|
||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
|
||||
// hdr.Mode is in linux format, which we can use for sycalls,
|
||||
// but for os.Foo() calls we need the mode converted to os.FileMode,
|
||||
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
|
||||
|
@ -658,7 +650,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
// Lchown is not supported on Windows.
|
||||
if Lchown && runtime.GOOS != "windows" {
|
||||
if chownOpts == nil {
|
||||
chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
|
||||
chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
|
||||
}
|
||||
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
|
||||
return err
|
||||
|
@ -668,11 +660,13 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||
var errors []string
|
||||
for key, value := range hdr.Xattrs {
|
||||
if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
|
||||
if err == syscall.ENOTSUP {
|
||||
if err == syscall.ENOTSUP || err == syscall.EPERM {
|
||||
// We ignore errors here because not all graphdrivers support
|
||||
// xattrs *cough* old versions of AUFS *cough*. However only
|
||||
// ENOTSUP should be emitted in that case, otherwise we still
|
||||
// bail.
|
||||
// EPERM occurs if modifying xattrs is not allowed. This can
|
||||
// happen when running in userns with restrictions (ChromeOS).
|
||||
errors = append(errors, err.Error())
|
||||
continue
|
||||
}
|
||||
|
@ -751,7 +745,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
compressWriter,
|
||||
options.ChownOpts,
|
||||
)
|
||||
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
|
||||
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat, options.InUserNS)
|
||||
|
||||
defer func() {
|
||||
// Make sure to check the error on Close.
|
||||
|
@ -907,9 +901,9 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
|
|||
defer pools.BufioReader32KPool.Put(trBuf)
|
||||
|
||||
var dirs []*tar.Header
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMappings.RootPair()
|
||||
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMapping.RootPair()
|
||||
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat, options.InUserNS)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
loop:
|
||||
|
@ -987,7 +981,7 @@ loop:
|
|||
}
|
||||
trBuf.Reset(tr)
|
||||
|
||||
if err := remapIDs(idMappings, hdr); err != nil {
|
||||
if err := remapIDs(idMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1074,8 +1068,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
|||
}
|
||||
defer archive.Close()
|
||||
options := &TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
@ -1088,8 +1082,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
|||
}
|
||||
defer archive.Close()
|
||||
options := &TarOptions{
|
||||
UIDMaps: archiver.IDMappingsVar.UIDs(),
|
||||
GIDMaps: archiver.IDMappingsVar.GIDs(),
|
||||
UIDMaps: archiver.IDMapping.UIDs(),
|
||||
GIDMaps: archiver.IDMapping.GIDs(),
|
||||
}
|
||||
return archiver.Untar(archive, dst, options)
|
||||
}
|
||||
|
@ -1110,7 +1104,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
|||
// if this Archiver is set up with ID mapping we need to create
|
||||
// the new destination directory with the remapped root UID/GID pair
|
||||
// as owner
|
||||
rootIDs := archiver.IDMappingsVar.RootPair()
|
||||
rootIDs := archiver.IDMapping.RootPair()
|
||||
// Create dst, copy src's content into it
|
||||
logrus.Debugf("Creating dest directory: %s", dst)
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
||||
|
@ -1170,7 +1164,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
hdr.Name = filepath.Base(dst)
|
||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
||||
|
||||
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
|
||||
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1198,13 +1192,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// IDMappings returns the IDMappings of the archiver.
|
||||
func (archiver *Archiver) IDMappings() *idtools.IDMappings {
|
||||
return archiver.IDMappingsVar
|
||||
// IdentityMapping returns the IdentityMapping of the archiver.
|
||||
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
|
||||
return archiver.IDMapping
|
||||
}
|
||||
|
||||
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
||||
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
||||
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
|
||||
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
||||
hdr.Uid, hdr.Gid = ids.UID, ids.GID
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,22 +2,29 @@ package archive // import "github.com/docker/docker/pkg/archive"
|
|||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/continuity/fs"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
|
||||
func getWhiteoutConverter(format WhiteoutFormat, inUserNS bool) tarWhiteoutConverter {
|
||||
if format == OverlayWhiteoutFormat {
|
||||
return overlayWhiteoutConverter{}
|
||||
return overlayWhiteoutConverter{inUserNS: inUserNS}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type overlayWhiteoutConverter struct{}
|
||||
type overlayWhiteoutConverter struct {
|
||||
inUserNS bool
|
||||
}
|
||||
|
||||
func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
|
||||
// convert whiteouts to AUFS format
|
||||
|
@ -61,13 +68,22 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
|
|||
return
|
||||
}
|
||||
|
||||
func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
|
||||
func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
|
||||
base := filepath.Base(path)
|
||||
dir := filepath.Dir(path)
|
||||
|
||||
// if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
|
||||
if base == WhiteoutOpaqueDir {
|
||||
err := unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0)
|
||||
if err != nil {
|
||||
if c.inUserNS {
|
||||
if err = replaceDirWithOverlayOpaque(dir); err != nil {
|
||||
return false, errors.Wrapf(err, "replaceDirWithOverlayOpaque(%q) failed", dir)
|
||||
}
|
||||
} else {
|
||||
return false, errors.Wrapf(err, "setxattr(%q, trusted.overlay.opaque=y)", dir)
|
||||
}
|
||||
}
|
||||
// don't write the file itself
|
||||
return false, err
|
||||
}
|
||||
|
@ -78,7 +94,19 @@ func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool,
|
|||
originalPath := filepath.Join(dir, originalBase)
|
||||
|
||||
if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil {
|
||||
return false, err
|
||||
if c.inUserNS {
|
||||
// Ubuntu and a few distros support overlayfs in userns.
|
||||
//
|
||||
// Although we can't call mknod directly in userns (at least on bionic kernel 4.15),
|
||||
// we can still create 0,0 char device using mknodChar0Overlay().
|
||||
//
|
||||
// NOTE: we don't need this hack for the containerd snapshotter+unpack model.
|
||||
if err := mknodChar0Overlay(originalPath); err != nil {
|
||||
return false, errors.Wrapf(err, "failed to mknodChar0UserNS(%q)", originalPath)
|
||||
}
|
||||
} else {
|
||||
return false, errors.Wrapf(err, "failed to mknod(%q, S_IFCHR, 0)", originalPath)
|
||||
}
|
||||
}
|
||||
if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
|
||||
return false, err
|
||||
|
@ -90,3 +118,144 @@ func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool,
|
|||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// mknodChar0Overlay creates 0,0 char device by mounting overlayfs and unlinking.
|
||||
// This function can be used for creating 0,0 char device in userns on Ubuntu.
|
||||
//
|
||||
// Steps:
|
||||
// * Mkdir lower,upper,merged,work
|
||||
// * Create lower/dummy
|
||||
// * Mount overlayfs
|
||||
// * Unlink merged/dummy
|
||||
// * Unmount overlayfs
|
||||
// * Make sure a 0,0 char device is created as upper/dummy
|
||||
// * Rename upper/dummy to cleansedOriginalPath
|
||||
func mknodChar0Overlay(cleansedOriginalPath string) error {
|
||||
dir := filepath.Dir(cleansedOriginalPath)
|
||||
tmp, err := ioutil.TempDir(dir, "mc0o")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create a tmp directory under %s", dir)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
lower := filepath.Join(tmp, "l")
|
||||
upper := filepath.Join(tmp, "u")
|
||||
work := filepath.Join(tmp, "w")
|
||||
merged := filepath.Join(tmp, "m")
|
||||
for _, s := range []string{lower, upper, work, merged} {
|
||||
if err := os.MkdirAll(s, 0700); err != nil {
|
||||
return errors.Wrapf(err, "failed to mkdir %s", s)
|
||||
}
|
||||
}
|
||||
dummyBase := "d"
|
||||
lowerDummy := filepath.Join(lower, dummyBase)
|
||||
if err := ioutil.WriteFile(lowerDummy, []byte{}, 0600); err != nil {
|
||||
return errors.Wrapf(err, "failed to create a dummy lower file %s", lowerDummy)
|
||||
}
|
||||
mOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work)
|
||||
// docker/pkg/mount.Mount() requires procfs to be mounted. So we use syscall.Mount() directly instead.
|
||||
if err := syscall.Mount("overlay", merged, "overlay", uintptr(0), mOpts); err != nil {
|
||||
return errors.Wrapf(err, "failed to mount overlay (%s) on %s", mOpts, merged)
|
||||
}
|
||||
mergedDummy := filepath.Join(merged, dummyBase)
|
||||
if err := os.Remove(mergedDummy); err != nil {
|
||||
syscall.Unmount(merged, 0)
|
||||
return errors.Wrapf(err, "failed to unlink %s", mergedDummy)
|
||||
}
|
||||
if err := syscall.Unmount(merged, 0); err != nil {
|
||||
return errors.Wrapf(err, "failed to unmount %s", merged)
|
||||
}
|
||||
upperDummy := filepath.Join(upper, dummyBase)
|
||||
if err := isChar0(upperDummy); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(upperDummy, cleansedOriginalPath); err != nil {
|
||||
return errors.Wrapf(err, "failed to rename %s to %s", upperDummy, cleansedOriginalPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isChar0(path string) error {
|
||||
osStat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat %s", path)
|
||||
}
|
||||
st, ok := osStat.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return errors.Errorf("got unsupported stat for %s", path)
|
||||
}
|
||||
if os.FileMode(st.Mode)&syscall.S_IFMT != syscall.S_IFCHR {
|
||||
return errors.Errorf("%s is not a character device, got mode=%d", path, st.Mode)
|
||||
}
|
||||
if st.Rdev != 0 {
|
||||
return errors.Errorf("%s is not a 0,0 character device, got Rdev=%d", path, st.Rdev)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// replaceDirWithOverlayOpaque replaces path with a new directory with trusted.overlay.opaque
|
||||
// xattr. The contents of the directory are preserved.
|
||||
func replaceDirWithOverlayOpaque(path string) error {
|
||||
if path == "/" {
|
||||
return errors.New("replaceDirWithOverlayOpaque: path must not be \"/\"")
|
||||
}
|
||||
dir := filepath.Dir(path)
|
||||
tmp, err := ioutil.TempDir(dir, "rdwoo")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create a tmp directory under %s", dir)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
// newPath is a new empty directory crafted with trusted.overlay.opaque xattr.
|
||||
// we copy the content of path into newPath, remove path, and rename newPath to path.
|
||||
newPath, err := createDirWithOverlayOpaque(tmp)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "createDirWithOverlayOpaque(%q) failed", tmp)
|
||||
}
|
||||
if err := fs.CopyDir(newPath, path); err != nil {
|
||||
return errors.Wrapf(err, "CopyDir(%q, %q) failed", newPath, path)
|
||||
}
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(newPath, path)
|
||||
}
|
||||
|
||||
// createDirWithOverlayOpaque creates a directory with trusted.overlay.opaque xattr,
|
||||
// without calling setxattr, so as to allow creating opaque dir in userns on Ubuntu.
|
||||
func createDirWithOverlayOpaque(tmp string) (string, error) {
|
||||
lower := filepath.Join(tmp, "l")
|
||||
upper := filepath.Join(tmp, "u")
|
||||
work := filepath.Join(tmp, "w")
|
||||
merged := filepath.Join(tmp, "m")
|
||||
for _, s := range []string{lower, upper, work, merged} {
|
||||
if err := os.MkdirAll(s, 0700); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to mkdir %s", s)
|
||||
}
|
||||
}
|
||||
dummyBase := "d"
|
||||
lowerDummy := filepath.Join(lower, dummyBase)
|
||||
if err := os.MkdirAll(lowerDummy, 0700); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to create a dummy lower directory %s", lowerDummy)
|
||||
}
|
||||
mOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work)
|
||||
// docker/pkg/mount.Mount() requires procfs to be mounted. So we use syscall.Mount() directly instead.
|
||||
if err := syscall.Mount("overlay", merged, "overlay", uintptr(0), mOpts); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to mount overlay (%s) on %s", mOpts, merged)
|
||||
}
|
||||
mergedDummy := filepath.Join(merged, dummyBase)
|
||||
if err := os.Remove(mergedDummy); err != nil {
|
||||
syscall.Unmount(merged, 0)
|
||||
return "", errors.Wrapf(err, "failed to rmdir %s", mergedDummy)
|
||||
}
|
||||
// upperDummy becomes a 0,0-char device file here
|
||||
if err := os.Mkdir(mergedDummy, 0700); err != nil {
|
||||
syscall.Unmount(merged, 0)
|
||||
return "", errors.Wrapf(err, "failed to mkdir %s", mergedDummy)
|
||||
}
|
||||
// upperDummy becomes a directory with trusted.overlay.opaque xattr
|
||||
// (but can't be verified in userns)
|
||||
if err := syscall.Unmount(merged, 0); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to unmount %s", merged)
|
||||
}
|
||||
upperDummy := filepath.Join(upper, dummyBase)
|
||||
return upperDummy, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
|
||||
func getWhiteoutConverter(format WhiteoutFormat, inUserNS bool) tarWhiteoutConverter {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ func getWalkRoot(srcPath string, include string) string {
|
|||
// CanonicalTarNameForPath returns platform-specific filepath
|
||||
// to canonical posix-style path for tar archival. p is relative
|
||||
// path.
|
||||
func CanonicalTarNameForPath(p string) (string, error) {
|
||||
return p, nil // already unix-style
|
||||
func CanonicalTarNameForPath(p string) string {
|
||||
return p // already unix-style
|
||||
}
|
||||
|
||||
// chmodTarEntry is used to adjust the file permissions used in tar header based
|
||||
|
@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
||||
s, ok := stat.(*syscall.Stat_t)
|
||||
|
||||
if !ok {
|
||||
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||
return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||
}
|
||||
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||
return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||
}
|
||||
|
||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
|
||||
|
|
|
@ -2,10 +2,8 @@ package archive // import "github.com/docker/docker/pkg/archive"
|
|||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/longpath"
|
||||
|
@ -26,16 +24,8 @@ func getWalkRoot(srcPath string, include string) string {
|
|||
// CanonicalTarNameForPath returns platform-specific filepath
|
||||
// to canonical posix-style path for tar archival. p is relative
|
||||
// path.
|
||||
func CanonicalTarNameForPath(p string) (string, error) {
|
||||
// windows: convert windows style relative path with backslashes
|
||||
// into forward slashes. Since windows does not allow '/' or '\'
|
||||
// in file names, it is mostly safe to replace however we must
|
||||
// check just in case
|
||||
if strings.Contains(p, "/") {
|
||||
return "", fmt.Errorf("Windows path contains forward slash: %s", p)
|
||||
}
|
||||
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
|
||||
|
||||
func CanonicalTarNameForPath(p string) string {
|
||||
return filepath.ToSlash(p)
|
||||
}
|
||||
|
||||
// chmodTarEntry is used to adjust the file permissions used in tar header based
|
||||
|
@ -71,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
||||
// no notion of file ownership mapping yet on Windows
|
||||
return idtools.IDPair{UID: 0, GID: 0}, nil
|
||||
return idtools.Identity{UID: 0, GID: 0}, nil
|
||||
}
|
||||
|
|
|
@ -63,12 +63,16 @@ func (c changesByPath) Less(i, j int) bool { return c[i].Path < c[j].Path }
|
|||
func (c changesByPath) Len() int { return len(c) }
|
||||
func (c changesByPath) Swap(i, j int) { c[j], c[i] = c[i], c[j] }
|
||||
|
||||
// Gnu tar and the go tar writer don't have sub-second mtime
|
||||
// precision, which is problematic when we apply changes via tar
|
||||
// files, we handle this by comparing for exact times, *or* same
|
||||
// Gnu tar doesn't have sub-second mtime precision. The go tar
|
||||
// writer (1.10+) does when using PAX format, but we round times to seconds
|
||||
// to ensure archives have the same hashes for backwards compatibility.
|
||||
// See https://github.com/moby/moby/pull/35739/commits/fb170206ba12752214630b269a40ac7be6115ed4.
|
||||
//
|
||||
// Non-sub-second is problematic when we apply changes via tar
|
||||
// files. We handle this by comparing for exact times, *or* same
|
||||
// second count and either a or b having exactly 0 nanoseconds
|
||||
func sameFsTime(a, b time.Time) bool {
|
||||
return a == b ||
|
||||
return a.Equal(b) ||
|
||||
(a.Unix() == b.Unix() &&
|
||||
(a.Nanosecond() == 0 || b.Nanosecond() == 0))
|
||||
}
|
||||
|
|
|
@ -284,30 +284,3 @@ func clen(n []byte) int {
|
|||
}
|
||||
return len(n)
|
||||
}
|
||||
|
||||
// OverlayChanges walks the path rw and determines changes for the files in the path,
|
||||
// with respect to the parent layers
|
||||
func OverlayChanges(layers []string, rw string) ([]Change, error) {
|
||||
return changes(layers, rw, overlayDeletedFile, nil)
|
||||
}
|
||||
|
||||
func overlayDeletedFile(root, path string, fi os.FileInfo) (string, error) {
|
||||
if fi.Mode()&os.ModeCharDevice != 0 {
|
||||
s := fi.Sys().(*syscall.Stat_t)
|
||||
if unix.Major(uint64(s.Rdev)) == 0 && unix.Minor(uint64(s.Rdev)) == 0 { // nolint: unconvert
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
if fi.Mode()&os.ModeDir != 0 {
|
||||
opaque, err := system.Lgetxattr(filepath.Join(root, path), "trusted.overlay.opaque")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(opaque) == 1 && opaque[0] == 'y' {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,13 @@ func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
|||
oldStat.UID() != newStat.UID() ||
|
||||
oldStat.GID() != newStat.GID() ||
|
||||
oldStat.Rdev() != newStat.Rdev() ||
|
||||
// Don't look at size for dirs, its not a good measure of change
|
||||
// Don't look at size or modification time for dirs, its not a good
|
||||
// measure of change. See https://github.com/moby/moby/issues/9874
|
||||
// for a description of the issue with modification time, and
|
||||
// https://github.com/moby/moby/pull/11422 for the change.
|
||||
// (Note that in the Windows implementation of this function,
|
||||
// modification time IS taken as a change). See
|
||||
// https://github.com/moby/moby/pull/37982 for more information.
|
||||
(oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR &&
|
||||
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
|
||||
return true
|
||||
|
|
|
@ -7,9 +7,13 @@ import (
|
|||
)
|
||||
|
||||
func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool {
|
||||
// Note there is slight difference between the Linux and Windows
|
||||
// implementations here. Due to https://github.com/moby/moby/issues/9874,
|
||||
// and the fix at https://github.com/moby/moby/pull/11422, Linux does not
|
||||
// consider a change to the directory time as a change. Windows on NTFS
|
||||
// does. See https://github.com/moby/moby/pull/37982 for more information.
|
||||
|
||||
// Don't look at size for dirs, its not a good measure of change
|
||||
if oldStat.Mtim() != newStat.Mtim() ||
|
||||
if !sameFsTime(oldStat.Mtim(), newStat.Mtim()) ||
|
||||
oldStat.Mode() != newStat.Mode() ||
|
||||
oldStat.Size() != newStat.Size() && !oldStat.Mode().IsDir() {
|
||||
return true
|
||||
|
|
|
@ -336,6 +336,14 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
|
|||
return
|
||||
}
|
||||
|
||||
// srcContent tar stream, as served by TarWithOptions(), is
|
||||
// definitely in PAX format, but tar.Next() mistakenly guesses it
|
||||
// as USTAR, which creates a problem: if the newBase is >100
|
||||
// characters long, WriteHeader() returns an error like
|
||||
// "archive/tar: cannot encode header: Format specifies USTAR; and USTAR cannot encode Name=...".
|
||||
//
|
||||
// To fix, set the format to PAX here. See docker/for-linux issue #484.
|
||||
hdr.Format = tar.FormatPAX
|
||||
hdr.Name = strings.Replace(hdr.Name, oldBase, newBase, 1)
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
hdr.Linkname = strings.Replace(hdr.Linkname, oldBase, newBase, 1)
|
||||
|
|
|
@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
if options.ExcludePatterns == nil {
|
||||
options.ExcludePatterns = []string{}
|
||||
}
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
|
||||
aufsTempdir := ""
|
||||
aufsHardlinks := make(map[string]*tar.Header)
|
||||
|
@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
|||
srcData = tmpFile
|
||||
}
|
||||
|
||||
if err := remapIDs(idMappings, srcHdr); err != nil {
|
||||
if err := remapIDs(idMapping, srcHdr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
@ -240,17 +240,21 @@ func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decomp
|
|||
dest = filepath.Clean(dest)
|
||||
|
||||
// We need to be able to set any perms
|
||||
if runtime.GOOS != "windows" {
|
||||
oldmask, err := system.Umask(0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform
|
||||
defer system.Umask(oldmask)
|
||||
}
|
||||
|
||||
if decompress {
|
||||
layer, err = DecompressStream(layer)
|
||||
decompLayer, err := DecompressStream(layer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer decompLayer.Close()
|
||||
layer = decompLayer
|
||||
}
|
||||
return UnpackLayer(dest, layer, options)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
)
|
||||
|
||||
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
|
||||
func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
|
||||
if idMappings == nil {
|
||||
idMappings = &idtools.IDMappings{}
|
||||
func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
|
||||
if idMapping == nil {
|
||||
idMapping = &idtools.IdentityMapping{}
|
||||
}
|
||||
return &archive.Archiver{
|
||||
Untar: Untar,
|
||||
IDMappingsVar: idMappings,
|
||||
IDMapping: idMapping,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
|
|||
options.ExcludePatterns = []string{}
|
||||
}
|
||||
|
||||
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMappings.RootPair()
|
||||
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||
rootIDs := idMapping.RootPair()
|
||||
|
||||
dest = filepath.Clean(dest)
|
||||
if _, err := os.Stat(dest); os.IsNotExist(err) {
|
||||
|
|
|
@ -106,7 +106,7 @@ func (pm *PatternMatcher) Patterns() []*Pattern {
|
|||
return pm.patterns
|
||||
}
|
||||
|
||||
// Pattern defines a single regexp used used to filter file paths.
|
||||
// Pattern defines a single regexp used to filter file paths.
|
||||
type Pattern struct {
|
||||
cleanedPattern string
|
||||
dirs []string
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package homedir // import "github.com/docker/docker/pkg/homedir"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
)
|
||||
|
@ -19,3 +22,88 @@ func GetStatic() (string, error) {
|
|||
}
|
||||
return usr.Home, nil
|
||||
}
|
||||
|
||||
// GetRuntimeDir returns XDG_RUNTIME_DIR.
|
||||
// XDG_RUNTIME_DIR is typically configured via pam_systemd.
|
||||
// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set.
|
||||
//
|
||||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
func GetRuntimeDir() (string, error) {
|
||||
if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" {
|
||||
return xdgRuntimeDir, nil
|
||||
}
|
||||
return "", errors.New("could not get XDG_RUNTIME_DIR")
|
||||
}
|
||||
|
||||
// StickRuntimeDirContents sets the sticky bit on files that are under
|
||||
// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system.
|
||||
//
|
||||
// StickyRuntimeDir returns slice of sticked files.
|
||||
// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set.
|
||||
//
|
||||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
func StickRuntimeDirContents(files []string) ([]string, error) {
|
||||
runtimeDir, err := GetRuntimeDir()
|
||||
if err != nil {
|
||||
// ignore error if runtimeDir is empty
|
||||
return nil, nil
|
||||
}
|
||||
runtimeDir, err = filepath.Abs(runtimeDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var sticked []string
|
||||
for _, f := range files {
|
||||
f, err = filepath.Abs(f)
|
||||
if err != nil {
|
||||
return sticked, err
|
||||
}
|
||||
if strings.HasPrefix(f, runtimeDir+"/") {
|
||||
if err = stick(f); err != nil {
|
||||
return sticked, err
|
||||
}
|
||||
sticked = append(sticked, f)
|
||||
}
|
||||
}
|
||||
return sticked, nil
|
||||
}
|
||||
|
||||
func stick(f string) error {
|
||||
st, err := os.Stat(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := st.Mode()
|
||||
m |= os.ModeSticky
|
||||
return os.Chmod(f, m)
|
||||
}
|
||||
|
||||
// GetDataHome returns XDG_DATA_HOME.
|
||||
// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
|
||||
//
|
||||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
func GetDataHome() (string, error) {
|
||||
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
|
||||
return xdgDataHome, nil
|
||||
}
|
||||
home := os.Getenv("HOME")
|
||||
if home == "" {
|
||||
return "", errors.New("could not get either XDG_DATA_HOME or HOME")
|
||||
}
|
||||
return filepath.Join(home, ".local", "share"), nil
|
||||
}
|
||||
|
||||
// GetConfigHome returns XDG_CONFIG_HOME.
|
||||
// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
|
||||
//
|
||||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
func GetConfigHome() (string, error) {
|
||||
if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
|
||||
return xdgConfigHome, nil
|
||||
}
|
||||
home := os.Getenv("HOME")
|
||||
if home == "" {
|
||||
return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
|
||||
}
|
||||
return filepath.Join(home, ".config"), nil
|
||||
}
|
||||
|
|
|
@ -11,3 +11,23 @@ import (
|
|||
func GetStatic() (string, error) {
|
||||
return "", errors.New("homedir.GetStatic() is not supported on this system")
|
||||
}
|
||||
|
||||
// GetRuntimeDir is unsupported on non-linux system.
|
||||
func GetRuntimeDir() (string, error) {
|
||||
return "", errors.New("homedir.GetRuntimeDir() is not supported on this system")
|
||||
}
|
||||
|
||||
// StickRuntimeDirContents is unsupported on non-linux system.
|
||||
func StickRuntimeDirContents(files []string) ([]string, error) {
|
||||
return nil, errors.New("homedir.StickRuntimeDirContents() is not supported on this system")
|
||||
}
|
||||
|
||||
// GetDataHome is unsupported on non-linux system.
|
||||
func GetDataHome() (string, error) {
|
||||
return "", errors.New("homedir.GetDataHome() is not supported on this system")
|
||||
}
|
||||
|
||||
// GetConfigHome is unsupported on non-linux system.
|
||||
func GetConfigHome() (string, error) {
|
||||
return "", errors.New("homedir.GetConfigHome() is not supported on this system")
|
||||
}
|
||||
|
|
|
@ -37,23 +37,23 @@ const (
|
|||
// MkdirAllAndChown creates a directory (include any along the path) and then modifies
|
||||
// ownership to the requested uid/gid. If the directory already exists, this
|
||||
// function will still change ownership to the requested uid/gid pair.
|
||||
func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, true, true)
|
||||
func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, true)
|
||||
}
|
||||
|
||||
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
|
||||
// If the directory already exists, this function still changes ownership.
|
||||
// Note that unlike os.Mkdir(), this function does not return IsExist error
|
||||
// in case path already exists.
|
||||
func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, false, true)
|
||||
func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, false, true)
|
||||
}
|
||||
|
||||
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
|
||||
// ownership ONLY of newly created directories to the requested uid/gid. If the
|
||||
// directories along the path exist, no change of ownership will be performed
|
||||
func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error {
|
||||
return mkdirAs(path, mode, owner.UID, owner.GID, true, false)
|
||||
func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, false)
|
||||
}
|
||||
|
||||
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
||||
|
@ -102,22 +102,23 @@ func toHost(contID int, idMap []IDMap) (int, error) {
|
|||
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
|
||||
}
|
||||
|
||||
// IDPair is a UID and GID pair
|
||||
type IDPair struct {
|
||||
// Identity is either a UID and GID pair or a SID (but not both)
|
||||
type Identity struct {
|
||||
UID int
|
||||
GID int
|
||||
SID string
|
||||
}
|
||||
|
||||
// IDMappings contains a mappings of UIDs and GIDs
|
||||
type IDMappings struct {
|
||||
// IdentityMapping contains a mappings of UIDs and GIDs
|
||||
type IdentityMapping struct {
|
||||
uids []IDMap
|
||||
gids []IDMap
|
||||
}
|
||||
|
||||
// NewIDMappings takes a requested user and group name and
|
||||
// NewIdentityMapping takes a requested user and group name and
|
||||
// using the data from /etc/sub{uid,gid} ranges, creates the
|
||||
// proper uid and gid remapping ranges for that user/group pair
|
||||
func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
||||
func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
|
||||
subuidRanges, err := parseSubuid(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
|||
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
|
||||
}
|
||||
|
||||
return &IDMappings{
|
||||
return &IdentityMapping{
|
||||
uids: createIDMap(subuidRanges),
|
||||
gids: createIDMap(subgidRanges),
|
||||
}, nil
|
||||
|
@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
|||
|
||||
// NewIDMappingsFromMaps creates a new mapping from two slices
|
||||
// Deprecated: this is a temporary shim while transitioning to IDMapping
|
||||
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings {
|
||||
return &IDMappings{uids: uids, gids: gids}
|
||||
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
|
||||
return &IdentityMapping{uids: uids, gids: gids}
|
||||
}
|
||||
|
||||
// RootPair returns a uid and gid pair for the root user. The error is ignored
|
||||
// because a root user always exists, and the defaults are correct when the uid
|
||||
// and gid maps are empty.
|
||||
func (i *IDMappings) RootPair() IDPair {
|
||||
func (i *IdentityMapping) RootPair() Identity {
|
||||
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
|
||||
return IDPair{UID: uid, GID: gid}
|
||||
return Identity{UID: uid, GID: gid}
|
||||
}
|
||||
|
||||
// ToHost returns the host UID and GID for the container uid, gid.
|
||||
// Remapping is only performed if the ids aren't already the remapped root ids
|
||||
func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
||||
func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
|
||||
var err error
|
||||
target := i.RootPair()
|
||||
|
||||
|
@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
|||
}
|
||||
|
||||
// ToContainer returns the container UID and GID for the host uid and gid
|
||||
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
||||
func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
|
||||
uid, err := toContainer(pair.UID, i.uids)
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
|
@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
|||
}
|
||||
|
||||
// Empty returns true if there are no id mappings
|
||||
func (i *IDMappings) Empty() bool {
|
||||
func (i *IdentityMapping) Empty() bool {
|
||||
return len(i.uids) == 0 && len(i.gids) == 0
|
||||
}
|
||||
|
||||
// UIDs return the UID mapping
|
||||
// TODO: remove this once everything has been refactored to use pairs
|
||||
func (i *IDMappings) UIDs() []IDMap {
|
||||
func (i *IdentityMapping) UIDs() []IDMap {
|
||||
return i.uids
|
||||
}
|
||||
|
||||
// GIDs return the UID mapping
|
||||
// TODO: remove this once everything has been refactored to use pairs
|
||||
func (i *IDMappings) GIDs() []IDMap {
|
||||
func (i *IdentityMapping) GIDs() []IDMap {
|
||||
return i.gids
|
||||
}
|
||||
|
||||
|
|
|
@ -21,11 +21,12 @@ var (
|
|||
getentCmd string
|
||||
)
|
||||
|
||||
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
||||
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
||||
// make an array containing the original path asked for, plus (for mkAll == true)
|
||||
// all path components leading up to the complete path that don't exist before we MkdirAll
|
||||
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
|
||||
// chown the full directory path if it exists
|
||||
|
||||
var paths []string
|
||||
|
||||
stat, err := system.Stat(path)
|
||||
|
@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
}
|
||||
|
||||
// short-circuit--we were called with an existing directory and chown was requested
|
||||
return lazyChown(path, ownerUID, ownerGID, stat)
|
||||
return lazyChown(path, owner.UID, owner.GID, stat)
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
|
@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
// even if it existed, we will chown the requested path + any subpaths that
|
||||
// didn't exist when we called MkdirAll
|
||||
for _, pathComponent := range paths {
|
||||
if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil {
|
||||
if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
|
||||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||
// if that uid, gid pair has access (execute bit) to the directory
|
||||
func CanAccess(path string, pair IDPair) bool {
|
||||
func CanAccess(path string, pair Identity) bool {
|
||||
statInfo, err := system.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
|
|
|
@ -6,9 +6,11 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// Platforms such as Windows do not support the UID/GID concept. So make this
|
||||
// just a wrapper around system.MkdirAll.
|
||||
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
||||
// This is currently a wrapper around MkdirAll, however, since currently
|
||||
// permissions aren't set through this path, the identity isn't utilized.
|
||||
// Ownership is handled elsewhere, but in the future could be support here
|
||||
// too.
|
||||
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
||||
if err := system.MkdirAll(path, mode, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
|||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||
// if that uid, gid pair has access (execute bit) to the directory
|
||||
// Windows does not require/support this function, so always return true
|
||||
func CanAccess(path string, pair IDPair) bool {
|
||||
func CanAccess(path string, identity Identity) bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -135,15 +135,3 @@ func parseOptions(options string) (int, string) {
|
|||
}
|
||||
return flag, strings.Join(data, ",")
|
||||
}
|
||||
|
||||
// ParseTmpfsOptions parse fstab type mount options into flags and data
|
||||
func ParseTmpfsOptions(options string) (int, string, error) {
|
||||
flags, data := parseOptions(options)
|
||||
for _, o := range strings.Split(data, ",") {
|
||||
opt := strings.SplitN(o, "=", 2)
|
||||
if !validFlags[opt[0]] {
|
||||
return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt)
|
||||
}
|
||||
}
|
||||
return flags, data, nil
|
||||
}
|
||||
|
|
|
@ -2,12 +2,46 @@ package mount // import "github.com/docker/docker/pkg/mount"
|
|||
|
||||
import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// mountError records an error from mount or unmount operation
|
||||
type mountError struct {
|
||||
op string
|
||||
source, target string
|
||||
flags uintptr
|
||||
data string
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *mountError) Error() string {
|
||||
out := e.op + " "
|
||||
|
||||
if e.source != "" {
|
||||
out += e.source + ":" + e.target
|
||||
} else {
|
||||
out += e.target
|
||||
}
|
||||
|
||||
if e.flags != uintptr(0) {
|
||||
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
|
||||
}
|
||||
if e.data != "" {
|
||||
out += ", data: " + e.data
|
||||
}
|
||||
|
||||
out += ": " + e.err.Error()
|
||||
return out
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error
|
||||
func (e *mountError) Cause() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// FilterFunc is a type defining a callback function
|
||||
// to filter out unwanted entries. It takes a pointer
|
||||
// to an Info struct (not fully populated, currently
|
||||
|
@ -89,12 +123,7 @@ func ForceMount(device, target, mType, options string) error {
|
|||
// Unmount lazily unmounts a filesystem on supported platforms, otherwise
|
||||
// does a normal unmount.
|
||||
func Unmount(target string) error {
|
||||
err := unmount(target, mntDetach)
|
||||
if err == syscall.EINVAL {
|
||||
// ignore "not mounted" error
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
return unmount(target, mntDetach)
|
||||
}
|
||||
|
||||
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
|
||||
|
@ -114,25 +143,14 @@ func RecursiveUnmount(target string) error {
|
|||
logrus.Debugf("Trying to unmount %s", m.Mountpoint)
|
||||
err = unmount(m.Mountpoint, mntDetach)
|
||||
if err != nil {
|
||||
// If the error is EINVAL either this whole package is wrong (invalid flags passed to unmount(2)) or this is
|
||||
// not a mountpoint (which is ok in this case).
|
||||
// Meanwhile calling `Mounted()` is very expensive.
|
||||
//
|
||||
// We've purposefully used `syscall.EINVAL` here instead of `unix.EINVAL` to avoid platform branching
|
||||
// Since `EINVAL` is defined for both Windows and Linux in the `syscall` package (and other platforms),
|
||||
// this is nicer than defining a custom value that we can refer to in each platform file.
|
||||
if err == syscall.EINVAL {
|
||||
continue
|
||||
}
|
||||
if i == len(mounts)-1 {
|
||||
if i == len(mounts)-1 { // last mount
|
||||
if mounted, e := Mounted(m.Mountpoint); e != nil || mounted {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem
|
||||
logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Unmounted %s", m.Mountpoint)
|
||||
|
|
|
@ -11,11 +11,9 @@ package mount // import "github.com/docker/docker/pkg/mount"
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func allocateIOVecs(options []string) []C.struct_iovec {
|
||||
|
@ -49,12 +47,13 @@ func mount(device, target, mType string, flag uintptr, data string) error {
|
|||
}
|
||||
|
||||
if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
|
||||
reason := C.GoString(C.strerror(*C.__error()))
|
||||
return fmt.Errorf("Failed to call nmount: %s", reason)
|
||||
return &mountError{
|
||||
op: "mount",
|
||||
source: device,
|
||||
target: target,
|
||||
flags: flag,
|
||||
err: syscall.Errno(errno),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
return unix.Unmount(target, flag)
|
||||
}
|
||||
|
|
|
@ -33,25 +33,41 @@ func mount(device, target, mType string, flags uintptr, data string) error {
|
|||
// Initial call applying all non-propagation flags for mount
|
||||
// or remount with changed data
|
||||
if err := unix.Mount(device, target, mType, oflags, data); err != nil {
|
||||
return err
|
||||
return &mountError{
|
||||
op: "mount",
|
||||
source: device,
|
||||
target: target,
|
||||
flags: oflags,
|
||||
data: data,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if flags&ptypes != 0 {
|
||||
// Change the propagation type.
|
||||
if err := unix.Mount("", target, "", flags&pflags, ""); err != nil {
|
||||
return err
|
||||
return &mountError{
|
||||
op: "remount",
|
||||
target: target,
|
||||
flags: flags & pflags,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if oflags&broflags == broflags {
|
||||
// Remount the bind to apply read only.
|
||||
return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "")
|
||||
if err := unix.Mount("", target, "", oflags|unix.MS_REMOUNT, ""); err != nil {
|
||||
return &mountError{
|
||||
op: "remount-ro",
|
||||
target: target,
|
||||
flags: oflags | unix.MS_REMOUNT,
|
||||
err: err,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
return unix.Unmount(target, flag)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,3 @@ package mount // import "github.com/docker/docker/pkg/mount"
|
|||
func mount(device, target, mType string, flag uintptr, data string) error {
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
panic("Not implemented")
|
||||
}
|
||||
|
|
|
@ -48,18 +48,22 @@ func MakeRUnbindable(mountPoint string) error {
|
|||
return ensureMountedAs(mountPoint, "runbindable")
|
||||
}
|
||||
|
||||
func ensureMountedAs(mountPoint, options string) error {
|
||||
mounted, err := Mounted(mountPoint)
|
||||
// MakeMount ensures that the file or directory given is a mount point,
|
||||
// bind mounting it to itself it case it is not.
|
||||
func MakeMount(mnt string) error {
|
||||
mounted, err := Mounted(mnt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if mounted {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !mounted {
|
||||
if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil {
|
||||
return err
|
||||
return Mount(mnt, mnt, "none", "bind")
|
||||
}
|
||||
}
|
||||
if _, err = Mounted(mountPoint); err != nil {
|
||||
|
||||
func ensureMountedAs(mountPoint, options string) error {
|
||||
if err := MakeMount(mountPoint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// +build !windows
|
||||
|
||||
package mount // import "github.com/docker/docker/pkg/mount"
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func unmount(target string, flags int) error {
|
||||
err := unix.Unmount(target, flags)
|
||||
if err == nil || err == unix.EINVAL {
|
||||
// Ignore "not mounted" error here. Note the same error
|
||||
// can be returned if flags are invalid, so this code
|
||||
// assumes that the flags value is always correct.
|
||||
return nil
|
||||
}
|
||||
|
||||
return &mountError{
|
||||
op: "umount",
|
||||
target: target,
|
||||
flags: uintptr(flags),
|
||||
err: err,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// +build windows
|
||||
|
||||
package mount // import "github.com/docker/docker/pkg/mount"
|
||||
|
||||
func unmount(target string, flag int) error {
|
||||
panic("Not implemented")
|
||||
}
|
|
@ -6,6 +6,10 @@ import (
|
|||
"os/exec"
|
||||
)
|
||||
|
||||
func Self() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Command is unsupported on operating systems apart from Linux, Windows, and Darwin.
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return nil
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !mips,!mipsle,!mips64,!mips64le
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// +build linux
|
||||
// +build mips mipsle mips64 mips64le
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
sigrtmin = 34
|
||||
sigrtmax = 127
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CLD": unix.SIGCLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"POLL": unix.SIGPOLL,
|
||||
"PROF": unix.SIGPROF,
|
||||
"PWR": unix.SIGPWR,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"SIGEMT": unix.SIGEMT,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
"RTMIN": sigrtmin,
|
||||
"RTMIN+1": sigrtmin + 1,
|
||||
"RTMIN+2": sigrtmin + 2,
|
||||
"RTMIN+3": sigrtmin + 3,
|
||||
"RTMIN+4": sigrtmin + 4,
|
||||
"RTMIN+5": sigrtmin + 5,
|
||||
"RTMIN+6": sigrtmin + 6,
|
||||
"RTMIN+7": sigrtmin + 7,
|
||||
"RTMIN+8": sigrtmin + 8,
|
||||
"RTMIN+9": sigrtmin + 9,
|
||||
"RTMIN+10": sigrtmin + 10,
|
||||
"RTMIN+11": sigrtmin + 11,
|
||||
"RTMIN+12": sigrtmin + 12,
|
||||
"RTMIN+13": sigrtmin + 13,
|
||||
"RTMIN+14": sigrtmin + 14,
|
||||
"RTMIN+15": sigrtmin + 15,
|
||||
"RTMAX-14": sigrtmax - 14,
|
||||
"RTMAX-13": sigrtmax - 13,
|
||||
"RTMAX-12": sigrtmax - 12,
|
||||
"RTMAX-11": sigrtmax - 11,
|
||||
"RTMAX-10": sigrtmax - 10,
|
||||
"RTMAX-9": sigrtmax - 9,
|
||||
"RTMAX-8": sigrtmax - 8,
|
||||
"RTMAX-7": sigrtmax - 7,
|
||||
"RTMAX-6": sigrtmax - 6,
|
||||
"RTMAX-5": sigrtmax - 5,
|
||||
"RTMAX-4": sigrtmax - 4,
|
||||
"RTMAX-3": sigrtmax - 3,
|
||||
"RTMAX-2": sigrtmax - 2,
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
|
@ -1,69 +1,32 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ValidatePlatform determines if a platform structure is valid.
|
||||
// TODO This is a temporary function - can be replaced by parsing from
|
||||
// https://github.com/containerd/containerd/pull/1403/files at a later date.
|
||||
// @jhowardmsft
|
||||
func ValidatePlatform(platform *specs.Platform) error {
|
||||
platform.Architecture = strings.ToLower(platform.Architecture)
|
||||
platform.OS = strings.ToLower(platform.OS)
|
||||
// Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do
|
||||
// not support anything except operating system.
|
||||
if platform.Architecture != "" {
|
||||
return fmt.Errorf("invalid platform architecture %q", platform.Architecture)
|
||||
}
|
||||
if platform.OS != "" {
|
||||
if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) {
|
||||
return fmt.Errorf("invalid platform os %q", platform.OS)
|
||||
}
|
||||
}
|
||||
if len(platform.OSFeatures) != 0 {
|
||||
return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures)
|
||||
}
|
||||
if platform.OSVersion != "" {
|
||||
return fmt.Errorf("invalid platform osversion %q", platform.OSVersion)
|
||||
}
|
||||
if platform.Variant != "" {
|
||||
return fmt.Errorf("invalid platform variant %q", platform.Variant)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParsePlatform parses a platform string in the format os[/arch[/variant]
|
||||
// into an OCI image-spec platform structure.
|
||||
// TODO This is a temporary function - can be replaced by parsing from
|
||||
// https://github.com/containerd/containerd/pull/1403/files at a later date.
|
||||
// @jhowardmsft
|
||||
func ParsePlatform(in string) *specs.Platform {
|
||||
p := &specs.Platform{}
|
||||
elements := strings.SplitN(strings.ToLower(in), "/", 3)
|
||||
if len(elements) == 3 {
|
||||
p.Variant = elements[2]
|
||||
}
|
||||
if len(elements) >= 2 {
|
||||
p.Architecture = elements[1]
|
||||
}
|
||||
if len(elements) >= 1 {
|
||||
p.OS = elements[0]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// IsOSSupported determines if an operating system is supported by the host
|
||||
func IsOSSupported(os string) bool {
|
||||
if runtime.GOOS == os {
|
||||
if strings.EqualFold(runtime.GOOS, os) {
|
||||
return true
|
||||
}
|
||||
if LCOWSupported() && os == "linux" {
|
||||
if LCOWSupported() && strings.EqualFold(os, "linux") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidatePlatform determines if a platform structure is valid.
|
||||
// TODO This is a temporary windows-only function, should be replaced by
|
||||
// comparison of worker capabilities
|
||||
func ValidatePlatform(platform specs.Platform) error {
|
||||
if runtime.GOOS == "windows" {
|
||||
if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) {
|
||||
return errors.Errorf("unsupported os %s", platform.OS)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -13,7 +14,7 @@ import (
|
|||
func Lstat(path string) (*StatT, error) {
|
||||
s := &syscall.Stat_t{}
|
||||
if err := syscall.Lstat(path, s); err != nil {
|
||||
return nil, err
|
||||
return nil, &os.PathError{Op: "Lstat", Path: path, Err: err}
|
||||
}
|
||||
return fromStatT(s)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// +build !windows
|
||||
|
||||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
// GetLongPathName converts Windows short pathnames to full pathnames.
|
||||
// For example C:\Users\ADMIN~1 --> C:\Users\Administrator.
|
||||
// It is a no-op on non-Windows platforms
|
||||
func GetLongPathName(path string) (string, error) {
|
||||
return path, nil
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
import "syscall"
|
||||
|
||||
// GetLongPathName converts Windows short pathnames to full pathnames.
|
||||
// For example C:\Users\ADMIN~1 --> C:\Users\Administrator.
|
||||
// It is a no-op on non-Windows platforms
|
||||
func GetLongPathName(path string) (string, error) {
|
||||
// See https://groups.google.com/forum/#!topic/golang-dev/1tufzkruoTg
|
||||
p := syscall.StringToUTF16(path)
|
||||
b := p // GetLongPathName says we can reuse buffer
|
||||
n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n > uint32(len(b)) {
|
||||
b = make([]uint16, n)
|
||||
_, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return syscall.UTF16ToString(b), nil
|
||||
}
|
|
@ -34,7 +34,7 @@ func EnsureRemoveAll(dir string) error {
|
|||
for {
|
||||
err := os.RemoveAll(dir)
|
||||
if err == nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
pe, ok := err.(*os.PathError)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -59,7 +60,7 @@ func (s StatT) IsDir() bool {
|
|||
func Stat(path string) (*StatT, error) {
|
||||
s := &syscall.Stat_t{}
|
||||
if err := syscall.Stat(path, s); err != nil {
|
||||
return nil, err
|
||||
return nil, &os.PathError{Op: "Stat", Path: path, Err: err}
|
||||
}
|
||||
return fromStatT(s)
|
||||
}
|
||||
|
|
|
@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system"
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
OWNER_SECURITY_INFORMATION = 0x00000001
|
||||
GROUP_SECURITY_INFORMATION = 0x00000002
|
||||
DACL_SECURITY_INFORMATION = 0x00000004
|
||||
SACL_SECURITY_INFORMATION = 0x00000008
|
||||
LABEL_SECURITY_INFORMATION = 0x00000010
|
||||
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
|
||||
SCOPE_SECURITY_INFORMATION = 0x00000040
|
||||
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
|
||||
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
|
||||
BACKUP_SECURITY_INFORMATION = 0x00010000
|
||||
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
|
||||
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
|
||||
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
|
||||
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
|
||||
)
|
||||
|
||||
const (
|
||||
SE_UNKNOWN_OBJECT_TYPE = iota
|
||||
SE_FILE_OBJECT
|
||||
SE_SERVICE
|
||||
SE_PRINTER
|
||||
SE_REGISTRY_KEY
|
||||
SE_LMSHARE
|
||||
SE_KERNEL_OBJECT
|
||||
SE_WINDOW_OBJECT
|
||||
SE_DS_OBJECT
|
||||
SE_DS_OBJECT_ALL
|
||||
SE_PROVIDER_DEFINED_OBJECT
|
||||
SE_WMIGUID_OBJECT
|
||||
SE_REGISTRY_WOW64_32KEY
|
||||
)
|
||||
|
||||
const (
|
||||
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
|
||||
)
|
||||
|
||||
const (
|
||||
ContainerAdministratorSidString = "S-1-5-93-2-1"
|
||||
ContainerUserSidString = "S-1-5-93-2-2"
|
||||
)
|
||||
|
||||
var (
|
||||
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
||||
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
|
||||
procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
|
||||
procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
|
||||
)
|
||||
|
||||
// OSVersion is a wrapper for Windows version information
|
||||
|
@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
|
|||
// APIs.
|
||||
return ntuserApiset.Load() == nil
|
||||
}
|
||||
|
||||
func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
|
||||
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
|
||||
if r0 != 0 {
|
||||
result = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
result = syscall.Errno(e1)
|
||||
} else {
|
||||
result = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ github.com/docker/cli/cli/config/types
|
|||
# github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
|
||||
github.com/docker/distribution/reference
|
||||
github.com/docker/distribution/digestset
|
||||
# github.com/docker/docker v0.7.3-0.20180531152204-71cd53e4a197
|
||||
# github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c
|
||||
github.com/docker/docker/pkg/locker
|
||||
github.com/docker/docker/pkg/reexec
|
||||
github.com/docker/docker/builder/dockerignore
|
||||
|
|
Loading…
Reference in New Issue