Advertisement
Guest User

Untitled

a guest
Dec 13th, 2017
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.47 KB | None | 0 0
  1. #!/bin/bash
  2. # mer-sdk-chroot
  3.  
  4. # TODO
  5. #
  6. # Support a Mer clean setup (ie no .oscrc)
  7. # Support multiple shells (ie split setup/entry)
  8.  
  9. usage()
  10. {
  11. cat <<EOF
  12. usage: $0 [-u <user>] [-m <all|none|root|home>] [-r <SDK root path>] [<command> <args> ..]
  13. $0 -h
  14.  
  15. This is the Mer chroot SDK.
  16. For information see http://wiki.merproject.org/wiki/Platform_SDK
  17.  
  18. If command is not present,
  19. used to enter the SDK and begin working. The SDK bash shell is a
  20. login shell. See below for .profile handling
  21.  
  22. If command is present,
  23. used to execute an arbitrary command from within the SDK chroot
  24. environment. The environment variable MERSDK is set to allow
  25. SDK detection.
  26.  
  27. Options:
  28.  
  29. -u System user to link into SDK (not needed if using sudo)
  30. -m Devices to bind mount from host: none, all (default)
  31. root, home
  32. -r The root of the SDK to use - normally derived from the
  33. pathname of $0
  34. -h Show this help
  35.  
  36. Profile
  37.  
  38. Entering the SDK runs the user's normal .profile and any (SDK)
  39. system profile entries. It will not execute the host's system
  40. profile entries.
  41.  
  42. The environment variable MERSDK is set to allow .profile to
  43. detect the SDK.
  44.  
  45. If the user has a ~/.mersdk.profile then it is sourced after the
  46. normal .profile handling (this allows the common use case of
  47. setting a profile to be handled).
  48.  
  49. Hooks
  50.  
  51. If the user specified has a .mersdkrc in their $HOME, it will be
  52. sourced to allow hook functions to be defined. Hooks are run as
  53. root. No commands should be executed immediately.
  54.  
  55. These hooks are usually used to define symbolic links from any
  56. /parentroot/data type filesystems into the SDK root to setup
  57. system specific shared caches or filesystem layouts etc
  58.  
  59. EOF
  60. return 0
  61. }
  62.  
  63. MY_SSH_AUTH_SOCK=${SSH_AUTH_SOCK#/parentroot}
  64. [[ $MY_SSH_AUTH_SOCK ]] && MY_SSH_AUTH_SOCK="/parentroot$MY_SSH_AUTH_SOCK"
  65.  
  66. if [[ $EUID -ne 0 ]]; then
  67. exec sudo SSH_AGENT_PID=${SSH_AGENT_PID:-} SSH_AUTH_SOCK=${MY_SSH_AUTH_SOCK} $0 "$@"
  68. echo "$0 must be run as root and sudo failed; exiting"
  69. exit 1
  70. fi
  71.  
  72. if cmp -s /proc/$PPID/mountinfo /proc/self/mountinfo; then
  73. exec unshare -m -- "$0" "$@"
  74. echo "$0 must be run in private namespace and unshare failed; exiting"
  75. exit 1
  76. fi
  77.  
  78. # Make sure that mountpoints in the new namespace are really unshared from the
  79. # parental namespace. See unshare(1).
  80. # This prevents mounts in the sdk from appearing in the parent fs.
  81. mount --make-rslave /
  82.  
  83. # Use the SUDO value if present
  84. user=$SUDO_USER || true;
  85.  
  86. bind_mount_root="yes";
  87. bind_mount_home="yes";
  88.  
  89. while getopts "u:m:r:" opt; do
  90. case $opt in
  91. u ) user=$OPTARG;;
  92. m )
  93. case $OPTARG in
  94. all) ;;
  95. home)
  96. bind_mount_root="no";;
  97. root)
  98. bind_mount_home="no";;
  99. none)
  100. bind_mount_root="no";
  101. bind_mount_home="no";;
  102. *) echo "Only 'none', 'all' or 'home' are permitted for -m"
  103. usage
  104. exit 1;;
  105. esac ;;
  106. r ) sdkroot=$OPTARG;;
  107. h|\? ) usage
  108. exit 1;;
  109. : ) echo "Option -$OPTARG requires an argument." >&2
  110. usage
  111. exit 1;;
  112. * ) usage
  113. exit 1;;
  114. esac
  115. done
  116. shift $(($OPTIND - 1))
  117.  
  118. if [[ -z "${sdkroot}" ]] ; then
  119. sdkroot=$(dirname $(readlink -f $0))
  120. else
  121. sdkroot=$(readlink -f $sdkroot)
  122. fi
  123.  
  124. if [[ ! -f ${sdkroot}/etc/MerSDK ]] ; then
  125. echo "${sdkroot} does not look like a Mer SDK rootfs"
  126. echo "if you are sure it is, you may mark it by running"
  127. echo "echo 'MerSDK' | sudo tee ${sdkroot}/etc/MerSDK"
  128. exit 1
  129. fi
  130.  
  131. if ! [[ $(basename $(dirname $sdkroot)) == "sdks" ]]; then
  132. echo "Non-standard SDK installation layout - cannot determine location for "
  133. echo "SDK targets and toolings. Expected layout is:"
  134. echo ""
  135. echo " <path/to/SDKs...>/"
  136. echo " ├── sdks/"
  137. echo " │ ├── <sdk_1>/"
  138. echo " │ ├── <sdk_2>/"
  139. echo " │ └── .../"
  140. echo " ├── targets/"
  141. echo " │ ├── <targets_1>/"
  142. echo " │ ├── <targets_2>/"
  143. echo " │ └── .../"
  144. echo " └── toolings/"
  145. echo " ├── <tooling_1>/"
  146. echo " ├── <tooling_2>/"
  147. echo " └── .../"
  148. exit 1
  149. fi
  150.  
  151. targetsdir=$(readlink -f ${sdkroot}/../../targets)
  152. if [[ ! -d ${targetsdir} ]] ; then
  153. echo "SDK targets location '$targetsdir' does not exist - about to create it."
  154. read -p "Continue, abort? [c/a] (c)" reply
  155. if ! [[ $reply =~ ^[cC]?$ ]]; then
  156. echo "User aborted"
  157. exit 1
  158. fi
  159.  
  160. mkdir "$targetsdir" || exit
  161. fi
  162.  
  163. toolingsdir=$(readlink -f ${sdkroot}/../../toolings)
  164. if [[ ! -d ${toolingsdir} ]] ; then
  165. echo "SDK toolings location '$toolingsdir' does not exist - about to create it."
  166. read -p "Continue, abort? [c/a] (c)" reply
  167. if ! [[ $reply =~ ^[cC]?$ ]]; then
  168. echo "User aborted"
  169. exit 1
  170. fi
  171.  
  172. mkdir "$toolingsdir" || exit
  173. fi
  174.  
  175. if [[ -z $user ]] ; then
  176. echo "$0 expects to be run as root using sudo"
  177. echo "User could not be obtained from \$SUDO_USER, if running as root,"
  178. echo "please use -u <user>"
  179. echo
  180. usage
  181. exit 1
  182. fi
  183.  
  184. # From now on, exit if variables not set
  185. set -u
  186.  
  187. # Make sure normal users can use any dirs we make
  188. umask 022
  189.  
  190. ################################################################
  191. # Mount
  192. mount_bind() {
  193. if [[ ! -d ${sdkroot}$1 ]]; then
  194. echo "Directory $1 is missing in SDK root - please report this bug"
  195. mkdir -p ${sdkroot}$1
  196. fi
  197. mount --bind $1 ${sdkroot}$1
  198. }
  199. prepare_mountpoints() {
  200. # This prevents the following mount_bind to hang first time after reboot.
  201. # Bug in binfmt_misc pseudo-filesystem?
  202. ls /proc/sys/fs/binfmt_misc -a > /dev/null
  203.  
  204. echo "Mounting system directories..."
  205. mount_bind /proc
  206. mount_bind /proc/sys/fs/binfmt_misc
  207. mount_bind /sys
  208. mount_bind /dev
  209. mount_bind /dev/pts
  210. mount_bind /dev/shm
  211. mount_bind /var/lib/dbus
  212. mount_bind /var/run/dbus
  213.  
  214. echo "Mounting $targetsdir as /srv/mer/targets"
  215. mkdir -p ${sdkroot}/srv/mer/targets
  216. mount --rbind ${targetsdir} ${sdkroot}/srv/mer/targets/
  217.  
  218. echo "Mounting $toolingsdir as /srv/mer/toolings"
  219. mkdir -p ${sdkroot}/srv/mer/toolings
  220. mount --rbind ${toolingsdir} ${sdkroot}/srv/mer/toolings/
  221.  
  222. if [[ $bind_mount_root == "yes" ]] ; then
  223. echo "Mounting / as /parentroot"
  224. mkdir -p ${sdkroot}/parentroot
  225. mount --rbind / ${sdkroot}/parentroot/
  226. fi
  227.  
  228. mkdir -p ${sdkroot}/lib/modules/`uname -r`
  229. mount_bind /lib/modules/`uname -r`
  230.  
  231. }
  232.  
  233. # Replace 'shell' field in `getent passwd` output with /bin/bash if the shell
  234. # is not available in the chroot
  235. fix_shell() {
  236. local shell= other=
  237. while IFS=: read shell other; do
  238. if ! [[ -e ${sdkroot}${shell} ]]; then
  239. shell=/bin/bash
  240. fi
  241.  
  242. echo "$other:$shell"
  243. done <<<"$(awk -F: -v OFS=: '{print $7,$1,$2,$3,$4,$5,$6}')"
  244. }
  245.  
  246. prepare_user() {
  247. # remove mer user if present
  248. sed -i -e "/^mer:/d" ${sdkroot}/etc/passwd
  249. # getent is probably best for user data
  250. sed -i -e "/^${user}:/d" ${sdkroot}/etc/passwd
  251. getent passwd $user |fix_shell >> ${sdkroot}/etc/passwd
  252. group=$(getent passwd $user | cut -f4 -d:)
  253. sed -i -e "/^[^:]*:[^:]*:${group}:/d" ${sdkroot}/etc/group
  254. getent group $group >> ${sdkroot}/etc/group
  255. HOMEDIR=$(getent passwd $user | cut -f6 -d:)
  256.  
  257. install --owner $user --group $(id -gn $user) -d ${sdkroot}${HOMEDIR}
  258.  
  259. if [[ $bind_mount_home == "yes" ]] ; then
  260. echo "Mounting home directory: ${HOMEDIR}"
  261. mount --bind ${HOMEDIR} ${sdkroot}${HOMEDIR}
  262. # Now the sdk uses a private namespace, there's no need to
  263. # make it unbindable
  264. mount --make-shared ${sdkroot}${HOMEDIR}
  265. fi
  266. echo "$user ALL=NOPASSWD: ALL" > ${sdkroot}/etc/sudoers.d/$user
  267. chmod 0440 ${sdkroot}/etc/sudoers.d/$user
  268. }
  269.  
  270. prepare_etc() {
  271. # Symlink to parentroot to support dynamic resolv.conf on host
  272. rm -f ${sdkroot}/etc/resolv.conf
  273. resolv=$(readlink -fn /etc/resolv.conf) # some systems use symlinks to /var/run/...
  274. ln -s /parentroot/$resolv ${sdkroot}/etc/resolv.conf
  275.  
  276. # Fixup old SDKs with broken /etc/mtab since this won't be fixed
  277. # by any package updates
  278. if [[ ! -L ${sdkroot}/etc/mtab ]]; then
  279. echo "The /etc/mtab file in the SDK is not a symbolic link - forcing it to link to /proc/self/mounts to fix https://bugs.merproject.org/show_bug.cgi?id=385"
  280. rm -f ${sdkroot}/etc/mtab
  281. ln -s /proc/self/mounts ${sdkroot}/etc/mtab
  282. fi
  283.  
  284. }
  285.  
  286. ################
  287.  
  288. setup_user_hooks(){
  289. # Access any user hooks
  290. [[ -e $HOMEDIR/.mersdkrc ]] && . $HOMEDIR/.mersdkrc
  291. }
  292.  
  293. run_user_hook() {
  294. hook=$1
  295. [[ $(type -t $hook) == "function" ]] && {
  296. echo "User hook $hook"
  297. $hook
  298. }
  299. }
  300. ################
  301.  
  302.  
  303. ################################################################
  304.  
  305. retval=0
  306. cwd=$(pwd)
  307.  
  308. # For back compatibility abort on 'mount/umount' and warn on 'enter'
  309. if [[ $# == 1 ]]; then
  310. case $1 in
  311. mount|umount )
  312. cat <<EOF
  313. ERROR: the mer-sdk-chroot command no longer needs or supports 'mount/umount/enter'
  314. Just enter the SDK using:
  315. $0
  316.  
  317. SDK mount/umount is handled automatically and safely.
  318. EOF
  319. exit 1;;
  320. enter )
  321. cat <<EOF
  322. WARNING: sdk 'enter' is deprecated. Just enter the SDK using:
  323. $0
  324.  
  325. Entering the SDK as requested
  326. EOF
  327. shift;;
  328. esac
  329. fi
  330.  
  331. prepare_mountpoints # host / and data and /proc and similar
  332. prepare_user # in /etc/passwd
  333. setup_user_hooks # (after prepare so HOMEDIR is known)
  334. prepare_etc # resolv.conf and ssl certs
  335. run_user_hook mount_sdk
  336. run_user_hook enter_sdk
  337. trap 'rv=$?; run_user_hook leave_sdk; exit "$rv"' EXIT
  338.  
  339. if [[ ${1:-} == 'exec' ]]; then
  340. cat <<EOF
  341. WARN: sdk 'exec' is deprecated. Just execute SDK commands using:
  342. $0 <cmd> <args>
  343.  
  344. Executing commands as requested
  345. EOF
  346. shift # Remove the offending 'exec'
  347.  
  348. if ! [[ $1 ]]; then
  349. echo "You must supply a command to exec"
  350. usage
  351. exit 1
  352. fi
  353. fi
  354.  
  355. if [[ $# -gt 0 ]]; then
  356. cmd=("$@")
  357. else
  358. cmd=(bash --init-file /mer-bash-setup -i)
  359. echo "Entering chroot as $user"
  360. fi
  361.  
  362. setarch i386 chroot ${sdkroot} /bin/su -s /bin/bash -l $user -- -c "$(cat <<END
  363. [[ -d "$cwd" ]] && cd "$cwd"
  364. export SSH_AUTH_SOCK='${MY_SSH_AUTH_SOCK}'
  365. export SSH_AGENT_PID=${SSH_AGENT_PID:-}
  366. export MERSDK='$sdkroot'
  367.  
  368. exec $(printf "%q " "${cmd[@]}")
  369. END
  370. )"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement