mount.c 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini mount implementation for busybox
  4. *
  5. * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
  6. * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  7. * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10. */
  11. // Design notes: There is no spec for mount. Remind me to write one.
  12. //
  13. // mount_main() calls singlemount() which calls mount_it_now().
  14. //
  15. // mount_main() can loop through /etc/fstab for mount -a
  16. // singlemount() can loop through /etc/filesystems for fstype detection.
  17. // mount_it_now() does the actual mount.
  18. //
  19. //config:config MOUNT
  20. //config: bool "mount (23 kb)"
  21. //config: default y
  22. //config: help
  23. //config: All files and filesystems in Unix are arranged into one big directory
  24. //config: tree. The 'mount' utility is used to graft a filesystem onto a
  25. //config: particular part of the tree. A filesystem can either live on a block
  26. //config: device, or it can be accessible over the network, as is the case with
  27. //config: NFS filesystems.
  28. //config:
  29. //config:config FEATURE_MOUNT_FAKE
  30. //config: bool "Support -f (fake mount)"
  31. //config: default y
  32. //config: depends on MOUNT
  33. //config: help
  34. //config: Enable support for faking a file system mount.
  35. //config:
  36. //config:config FEATURE_MOUNT_VERBOSE
  37. //config: bool "Support -v (verbose)"
  38. //config: default y
  39. //config: depends on MOUNT
  40. //config: help
  41. //config: Enable multi-level -v[vv...] verbose messages. Useful if you
  42. //config: debug mount problems and want to see what is exactly passed
  43. //config: to the kernel.
  44. //config:
  45. //config:config FEATURE_MOUNT_HELPERS
  46. //config: bool "Support mount helpers"
  47. //config: default n
  48. //config: depends on MOUNT
  49. //config: help
  50. //config: Enable mounting of virtual file systems via external helpers.
  51. //config: E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call
  52. //config: "obexfs -b00.11.22.33.44.55 /mnt"
  53. //config: Also "mount -t sometype [-o opts] fs /mnt" will try
  54. //config: "sometype [-o opts] fs /mnt" if simple mount syscall fails.
  55. //config: The idea is to use such virtual filesystems in /etc/fstab.
  56. //config:
  57. //config:config FEATURE_MOUNT_LABEL
  58. //config: bool "Support specifying devices by label or UUID"
  59. //config: default y
  60. //config: depends on MOUNT
  61. //config: select VOLUMEID
  62. //config: help
  63. //config: This allows for specifying a device by label or uuid, rather than by
  64. //config: name. This feature utilizes the same functionality as blkid/findfs.
  65. //config:
  66. //config:config FEATURE_MOUNT_NFS
  67. //config: bool "Support mounting NFS file systems on Linux < 2.6.23"
  68. //config: default n
  69. //config: depends on MOUNT
  70. //config: select FEATURE_SYSLOG
  71. //config: help
  72. //config: Enable mounting of NFS file systems on Linux kernels prior
  73. //config: to version 2.6.23. Note that in this case mounting of NFS
  74. //config: over IPv6 will not be possible.
  75. //config:
  76. //config: Note that this option links in RPC support from libc,
  77. //config: which is rather large (~10 kbytes on uclibc).
  78. //config:
  79. //config:config FEATURE_MOUNT_CIFS
  80. //config: bool "Support mounting CIFS/SMB file systems"
  81. //config: default y
  82. //config: depends on MOUNT
  83. //config: help
  84. //config: Enable support for samba mounts.
  85. //config:
  86. //config:config FEATURE_MOUNT_FLAGS
  87. //config: depends on MOUNT
  88. //config: bool "Support lots of -o flags"
  89. //config: default y
  90. //config: help
  91. //config: Without this, mount only supports ro/rw/remount. With this, it
  92. //config: supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
  93. //config: noatime, diratime, nodiratime, loud, bind, move, shared, slave,
  94. //config: private, unbindable, rshared, rslave, rprivate, and runbindable.
  95. //config:
  96. //config:config FEATURE_MOUNT_FSTAB
  97. //config: depends on MOUNT
  98. //config: bool "Support /etc/fstab and -a (mount all)"
  99. //config: default y
  100. //config: help
  101. //config: Support mount all and looking for files in /etc/fstab.
  102. //config:
  103. //config:config FEATURE_MOUNT_OTHERTAB
  104. //config: depends on FEATURE_MOUNT_FSTAB
  105. //config: bool "Support -T <alt_fstab>"
  106. //config: default y
  107. //config: help
  108. //config: Support mount -T (specifying an alternate fstab)
  109. /* On full-blown systems, requires suid for user mounts.
  110. * But it's not unthinkable to have it available in non-suid flavor on some systems,
  111. * for viewing mount table.
  112. * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */
  113. //applet:IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP)))
  114. //kbuild:lib-$(CONFIG_MOUNT) += mount.o
  115. //usage:#define mount_trivial_usage
  116. //usage: "[OPTIONS] [-o OPT] DEVICE NODE"
  117. //usage:#define mount_full_usage "\n\n"
  118. //usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n"
  119. //usage: "\n -a Mount all filesystems in fstab"
  120. //usage: IF_FEATURE_MOUNT_FAKE(
  121. //usage: IF_FEATURE_MTAB_SUPPORT(
  122. //usage: "\n -f Update /etc/mtab, but don't mount"
  123. //usage: )
  124. //usage: IF_NOT_FEATURE_MTAB_SUPPORT(
  125. //usage: "\n -f Dry run"
  126. //usage: )
  127. //usage: )
  128. //usage: IF_FEATURE_MOUNT_HELPERS(
  129. //usage: "\n -i Don't run mount helper"
  130. //usage: )
  131. //usage: IF_FEATURE_MTAB_SUPPORT(
  132. //usage: "\n -n Don't update /etc/mtab"
  133. //usage: )
  134. //usage: IF_FEATURE_MOUNT_VERBOSE(
  135. //usage: "\n -v Verbose"
  136. //usage: )
  137. ////usage: "\n -s Sloppy (ignored)"
  138. //usage: "\n -r Read-only mount"
  139. ////usage: "\n -w Read-write mount (default)"
  140. //usage: "\n -t FSTYPE[,...] Filesystem type(s)"
  141. //usage: IF_FEATURE_MOUNT_OTHERTAB(
  142. //usage: "\n -T FILE Read FILE instead of /etc/fstab"
  143. //usage: )
  144. //usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
  145. //usage: "\n-o OPT:"
  146. //usage: IF_FEATURE_MOUNT_LOOP(
  147. //usage: "\n loop Ignored (loop devices are autodetected)"
  148. //usage: )
  149. //usage: IF_FEATURE_MOUNT_FLAGS(
  150. //usage: "\n [a]sync Writes are [a]synchronous"
  151. //usage: "\n [no]atime Disable/enable updates to inode access times"
  152. //usage: "\n [no]diratime Disable/enable atime updates to directories"
  153. //usage: "\n [no]relatime Disable/enable atime updates relative to modification time"
  154. //usage: "\n [no]dev (Dis)allow use of special device files"
  155. //usage: "\n [no]exec (Dis)allow use of executable files"
  156. //usage: "\n [no]suid (Dis)allow set-user-id-root programs"
  157. //usage: "\n [r]shared Convert [recursively] to a shared subtree"
  158. //usage: "\n [r]slave Convert [recursively] to a slave subtree"
  159. //usage: "\n [r]private Convert [recursively] to a private subtree"
  160. //usage: "\n [un]bindable Make mount point [un]able to be bind mounted"
  161. //usage: "\n [r]bind Bind a file or directory [recursively] to another location"
  162. //usage: "\n move Relocate an existing mount point"
  163. //usage: )
  164. //usage: "\n remount Remount a mounted filesystem, changing flags"
  165. //usage: "\n ro Same as -r"
  166. //usage: "\n"
  167. //usage: "\nThere are filesystem-specific -o flags."
  168. //usage:
  169. //usage:#define mount_example_usage
  170. //usage: "$ mount\n"
  171. //usage: "/dev/hda3 on / type minix (rw)\n"
  172. //usage: "proc on /proc type proc (rw)\n"
  173. //usage: "devpts on /dev/pts type devpts (rw)\n"
  174. //usage: "$ mount /dev/fd0 /mnt -t msdos -o ro\n"
  175. //usage: "$ mount /tmp/diskimage /opt -t ext2 -o loop\n"
  176. //usage: "$ mount cd_image.iso mydir\n"
  177. //usage:#define mount_notes_usage
  178. //usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
  179. #include <mntent.h>
  180. #if ENABLE_FEATURE_SYSLOG
  181. #include <syslog.h>
  182. #endif
  183. #include <sys/mount.h>
  184. // Grab more as needed from util-linux's mount/mount_constants.h
  185. #ifndef MS_DIRSYNC
  186. # define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
  187. #endif
  188. #ifndef MS_NOSYMFOLLOW
  189. # define MS_NOSYMFOLLOW (1 << 8)
  190. #endif
  191. #ifndef MS_BIND
  192. # define MS_BIND (1 << 12)
  193. #endif
  194. #ifndef MS_MOVE
  195. # define MS_MOVE (1 << 13)
  196. #endif
  197. #ifndef MS_RECURSIVE
  198. # define MS_RECURSIVE (1 << 14)
  199. #endif
  200. #ifndef MS_SILENT
  201. # define MS_SILENT (1 << 15)
  202. #endif
  203. // The shared subtree stuff, which went in around 2.6.15
  204. #ifndef MS_UNBINDABLE
  205. # define MS_UNBINDABLE (1 << 17)
  206. #endif
  207. #ifndef MS_PRIVATE
  208. # define MS_PRIVATE (1 << 18)
  209. #endif
  210. #ifndef MS_SLAVE
  211. # define MS_SLAVE (1 << 19)
  212. #endif
  213. #ifndef MS_SHARED
  214. # define MS_SHARED (1 << 20)
  215. #endif
  216. #ifndef MS_RELATIME
  217. # define MS_RELATIME (1 << 21)
  218. #endif
  219. #ifndef MS_STRICTATIME
  220. # define MS_STRICTATIME (1 << 24)
  221. #endif
  222. #ifndef MS_LAZYTIME
  223. # define MS_LAZYTIME (1 << 25)
  224. #endif
  225. /* Any ~MS_FOO value has this bit set: */
  226. #define BB_MS_INVERTED_VALUE (1u << 31)
  227. #include "libbb.h"
  228. #include "common_bufsiz.h"
  229. #if ENABLE_FEATURE_MOUNT_LABEL
  230. # include "volume_id.h"
  231. #else
  232. # define resolve_mount_spec(fsname) ((void)0)
  233. #endif
  234. // Needed for nfs support only
  235. #include <sys/utsname.h>
  236. #undef TRUE
  237. #undef FALSE
  238. #if ENABLE_FEATURE_MOUNT_NFS
  239. /* This is just a warning of a common mistake. Possibly this should be a
  240. * uclibc faq entry rather than in busybox... */
  241. # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
  242. # warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
  243. /* not #error, since user may be using e.g. libtirpc instead.
  244. * This might work:
  245. * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc"
  246. * CONFIG_EXTRA_LDLIBS="tirpc"
  247. */
  248. # endif
  249. # include <rpc/rpc.h>
  250. # include <rpc/pmap_prot.h>
  251. # include <rpc/pmap_clnt.h>
  252. #endif
  253. #if defined(__dietlibc__)
  254. // 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
  255. // dietlibc-0.30 does not have implementation of getmntent_r()
  256. static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
  257. char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
  258. {
  259. struct mntent* ment = getmntent(stream);
  260. return memcpy(result, ment, sizeof(*ment));
  261. }
  262. #endif
  263. // Not real flags, but we want to be able to check for this.
  264. enum {
  265. MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP,
  266. MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP,
  267. MOUNT_NOAUTO = (1 << 29),
  268. MOUNT_SWAP = (1 << 30),
  269. MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP
  270. };
  271. #define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:")
  272. enum {
  273. OPT_o = (1 << 0),
  274. OPT_t = (1 << 1),
  275. OPT_r = (1 << 2),
  276. OPT_w = (1 << 3),
  277. OPT_a = (1 << 4),
  278. OPT_n = (1 << 5),
  279. OPT_f = (1 << 6),
  280. OPT_v = (1 << 7),
  281. OPT_s = (1 << 8),
  282. OPT_i = (1 << 9),
  283. OPT_O = (1 << 10),
  284. OPT_T = (1 << 11),
  285. };
  286. #if ENABLE_FEATURE_MTAB_SUPPORT
  287. #define USE_MTAB (!(option_mask32 & OPT_n))
  288. #else
  289. #define USE_MTAB 0
  290. #endif
  291. #if ENABLE_FEATURE_MOUNT_FAKE
  292. #define FAKE_IT (option_mask32 & OPT_f)
  293. #else
  294. #define FAKE_IT 0
  295. #endif
  296. #if ENABLE_FEATURE_MOUNT_HELPERS
  297. #define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
  298. #else
  299. #define HELPERS_ALLOWED 0
  300. #endif
  301. // TODO: more "user" flag compatibility.
  302. // "user" option (from mount manpage):
  303. // Only the user that mounted a filesystem can unmount it again.
  304. // If any user should be able to unmount, then use users instead of user
  305. // in the fstab line. The owner option is similar to the user option,
  306. // with the restriction that the user must be the owner of the special file.
  307. // This may be useful e.g. for /dev/fd if a login script makes
  308. // the console user owner of this device.
  309. // Standard mount options (from -o options or --options),
  310. // with corresponding flags
  311. static const int32_t mount_options[] ALIGN4 = {
  312. // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
  313. IF_FEATURE_MOUNT_LOOP(
  314. /* "loop" */ 0,
  315. )
  316. IF_FEATURE_MOUNT_FSTAB(
  317. /* "defaults" */ 0,
  318. /* "quiet" 0 - do not filter out, vfat wants to see it */
  319. /* "noauto" */ MOUNT_NOAUTO,
  320. /* "sw" */ MOUNT_SWAP,
  321. /* "swap" */ MOUNT_SWAP,
  322. IF_DESKTOP(/* "user" */ MOUNT_USERS,)
  323. IF_DESKTOP(/* "users" */ MOUNT_USERS,)
  324. IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,)
  325. /* "_netdev" */ 0,
  326. IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */
  327. )
  328. IF_FEATURE_MOUNT_FLAGS(
  329. // vfs flags
  330. /* "nosuid" */ MS_NOSUID,
  331. /* "suid" */ ~MS_NOSUID,
  332. /* "dev" */ ~MS_NODEV,
  333. /* "nodev" */ MS_NODEV,
  334. /* "exec" */ ~MS_NOEXEC,
  335. /* "noexec" */ MS_NOEXEC,
  336. /* "sync" */ MS_SYNCHRONOUS,
  337. /* "dirsync" */ MS_DIRSYNC,
  338. /* "async" */ ~MS_SYNCHRONOUS,
  339. /* "atime" */ ~MS_NOATIME,
  340. /* "noatime" */ MS_NOATIME,
  341. /* "diratime" */ ~MS_NODIRATIME,
  342. /* "nodiratime" */ MS_NODIRATIME,
  343. /* "relatime" */ MS_RELATIME,
  344. /* "norelatime" */ ~MS_RELATIME,
  345. /* "strictatime" */ MS_STRICTATIME,
  346. /* "nostrictatime"*/ ~MS_STRICTATIME,
  347. /* "lazytime" */ MS_LAZYTIME,
  348. /* "nolazytime" */ ~MS_LAZYTIME,
  349. /* "nosymfollow" */ MS_NOSYMFOLLOW,
  350. /* "mand" */ MS_MANDLOCK,
  351. /* "nomand" */ ~MS_MANDLOCK,
  352. /* "loud" */ ~MS_SILENT,
  353. // action flags
  354. /* "rbind" */ MS_BIND|MS_RECURSIVE,
  355. /* "bind" */ MS_BIND,
  356. /* "move" */ MS_MOVE,
  357. /* "shared" */ MS_SHARED,
  358. /* "slave" */ MS_SLAVE,
  359. /* "private" */ MS_PRIVATE,
  360. /* "unbindable" */ MS_UNBINDABLE,
  361. /* "rshared" */ MS_SHARED|MS_RECURSIVE,
  362. /* "rslave" */ MS_SLAVE|MS_RECURSIVE,
  363. /* "rprivate" */ MS_PRIVATE|MS_RECURSIVE,
  364. /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
  365. )
  366. // Always understood.
  367. /* "ro" */ MS_RDONLY, // vfs flag
  368. /* "rw" */ ~MS_RDONLY, // vfs flag
  369. /* "remount" */ MS_REMOUNT // action flag
  370. };
  371. static const char mount_option_str[] ALIGN1 =
  372. IF_FEATURE_MOUNT_LOOP(
  373. "loop\0"
  374. )
  375. IF_FEATURE_MOUNT_FSTAB(
  376. "defaults\0"
  377. // "quiet\0" - do not filter out, vfat wants to see it
  378. "noauto\0"
  379. "sw\0"
  380. "swap\0"
  381. IF_DESKTOP("user\0")
  382. IF_DESKTOP("users\0")
  383. IF_DESKTOP("nofail\0")
  384. "_netdev\0"
  385. IF_DESKTOP("comment=\0") /* systemd uses this in fstab */
  386. )
  387. IF_FEATURE_MOUNT_FLAGS(
  388. // vfs flags
  389. "nosuid" "\0"
  390. "suid" "\0"
  391. "dev" "\0"
  392. "nodev" "\0"
  393. "exec" "\0"
  394. "noexec" "\0"
  395. "sync" "\0"
  396. "dirsync" "\0"
  397. "async" "\0"
  398. "atime" "\0"
  399. "noatime" "\0"
  400. "diratime" "\0"
  401. "nodiratime" "\0"
  402. "relatime" "\0"
  403. "norelatime" "\0"
  404. "strictatime" "\0"
  405. "nostrictatime""\0"
  406. "lazytime" "\0"
  407. "nolazytime" "\0"
  408. "nosymfollow" "\0"
  409. "mand" "\0"
  410. "nomand" "\0"
  411. "loud" "\0"
  412. // action flags
  413. "rbind\0"
  414. "bind\0"
  415. "move\0"
  416. "make-shared\0"
  417. "make-slave\0"
  418. "make-private\0"
  419. "make-unbindable\0"
  420. "make-rshared\0"
  421. "make-rslave\0"
  422. "make-rprivate\0"
  423. "make-runbindable\0"
  424. )
  425. // Always understood.
  426. "ro\0" // vfs flag
  427. "rw\0" // vfs flag
  428. "remount\0" // action flag
  429. ;
  430. struct globals {
  431. #if ENABLE_FEATURE_MOUNT_NFS
  432. smalluint nfs_mount_version;
  433. #endif
  434. #if ENABLE_FEATURE_MOUNT_VERBOSE
  435. unsigned verbose;
  436. #endif
  437. llist_t *fslist;
  438. char getmntent_buf[1];
  439. } FIX_ALIASING;
  440. enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
  441. #define G (*(struct globals*)bb_common_bufsiz1)
  442. #define nfs_mount_version (G.nfs_mount_version)
  443. #if ENABLE_FEATURE_MOUNT_VERBOSE
  444. #define verbose (G.verbose )
  445. #else
  446. #define verbose 0
  447. #endif
  448. #define fslist (G.fslist )
  449. #define getmntent_buf (G.getmntent_buf )
  450. #define INIT_G() do { setup_common_bufsiz(); } while (0)
  451. #if ENABLE_FEATURE_MTAB_SUPPORT
  452. /*
  453. * update_mtab_entry_on_move() is used to update entry in case of mount --move.
  454. * we are looking for existing entries mnt_dir which is equal to mnt_fsname of
  455. * input mntent and replace it by new one.
  456. */
  457. static void FAST_FUNC update_mtab_entry_on_move(const struct mntent *mp)
  458. {
  459. struct mntent *entries, *m;
  460. int i, count;
  461. FILE *mountTable;
  462. mountTable = setmntent(bb_path_mtab_file, "r");
  463. if (!mountTable) {
  464. bb_simple_perror_msg(bb_path_mtab_file);
  465. return;
  466. }
  467. entries = NULL;
  468. count = 0;
  469. while ((m = getmntent(mountTable)) != NULL) {
  470. entries = xrealloc_vector(entries, 3, count);
  471. entries[count].mnt_fsname = xstrdup(m->mnt_fsname);
  472. entries[count].mnt_dir = xstrdup(m->mnt_dir);
  473. entries[count].mnt_type = xstrdup(m->mnt_type);
  474. entries[count].mnt_opts = xstrdup(m->mnt_opts);
  475. entries[count].mnt_freq = m->mnt_freq;
  476. entries[count].mnt_passno = m->mnt_passno;
  477. count++;
  478. }
  479. endmntent(mountTable);
  480. mountTable = setmntent(bb_path_mtab_file, "w");
  481. if (mountTable) {
  482. for (i = 0; i < count; i++) {
  483. if (strcmp(entries[i].mnt_dir, mp->mnt_fsname) != 0)
  484. addmntent(mountTable, &entries[i]);
  485. else
  486. addmntent(mountTable, mp);
  487. }
  488. endmntent(mountTable);
  489. } else if (errno != EROFS)
  490. bb_simple_perror_msg(bb_path_mtab_file);
  491. if (ENABLE_FEATURE_CLEAN_UP) {
  492. for (i = 0; i < count; i++) {
  493. free(entries[i].mnt_fsname);
  494. free(entries[i].mnt_dir);
  495. free(entries[i].mnt_type);
  496. free(entries[i].mnt_opts);
  497. }
  498. free(entries);
  499. }
  500. }
  501. #endif
  502. #if ENABLE_FEATURE_MOUNT_VERBOSE
  503. static int verbose_mount(const char *source, const char *target,
  504. const char *filesystemtype,
  505. unsigned long mountflags, const void *data)
  506. {
  507. int rc;
  508. errno = 0;
  509. rc = mount(source, target, filesystemtype, mountflags, data);
  510. if (verbose >= 2)
  511. bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
  512. source, target, filesystemtype,
  513. mountflags, (char*)data, rc);
  514. return rc;
  515. }
  516. #else
  517. #define verbose_mount(...) mount(__VA_ARGS__)
  518. #endif
  519. // Append mount options to string
  520. static void append_mount_options(char **oldopts, const char *newopts)
  521. {
  522. if (*oldopts && **oldopts) {
  523. // Do not insert options which are already there
  524. while (newopts[0]) {
  525. char *p;
  526. int len;
  527. len = strchrnul(newopts, ',') - newopts;
  528. p = *oldopts;
  529. while (1) {
  530. if (!strncmp(p, newopts, len)
  531. && (p[len] == ',' || p[len] == '\0'))
  532. goto skip;
  533. p = strchr(p,',');
  534. if (!p) break;
  535. p++;
  536. }
  537. p = xasprintf("%s,%.*s", *oldopts, len, newopts);
  538. free(*oldopts);
  539. *oldopts = p;
  540. skip:
  541. newopts += len;
  542. while (*newopts == ',') newopts++;
  543. }
  544. } else {
  545. if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
  546. *oldopts = xstrdup(newopts);
  547. }
  548. }
  549. // Use the mount_options list to parse options into flags.
  550. // Also update list of unrecognized options if unrecognized != NULL
  551. static unsigned long parse_mount_options(char *options, char **unrecognized, uint32_t *opt)
  552. {
  553. unsigned long flags = MS_SILENT;
  554. // Loop through options
  555. for (;;) {
  556. unsigned i;
  557. char *comma = strchr(options, ',');
  558. const char *option_str = mount_option_str;
  559. if (comma) *comma = '\0';
  560. // FIXME: use hasmntopt()
  561. // Find this option in mount_options
  562. for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
  563. unsigned opt_len = strlen(option_str);
  564. if (strncasecmp(option_str, options, opt_len) == 0
  565. && (options[opt_len] == '\0'
  566. /* or is it "comment=" thingy in fstab? */
  567. IF_FEATURE_MOUNT_FSTAB(IF_DESKTOP( || option_str[opt_len-1] == '=' ))
  568. )
  569. ) {
  570. unsigned long fl = mount_options[i];
  571. if (fl & BB_MS_INVERTED_VALUE)
  572. flags &= fl;
  573. else
  574. flags |= fl;
  575. /* If we see "-o rw" on command line, it's the same as -w:
  576. * "do not try to fall back to RO mounts"
  577. */
  578. if (fl == ~MS_RDONLY && opt)
  579. (*opt) |= OPT_w;
  580. goto found;
  581. }
  582. option_str += opt_len + 1;
  583. }
  584. // We did not recognize this option.
  585. // If "unrecognized" is not NULL, append option there.
  586. // Note that we should not append *empty* option -
  587. // in this case we want to pass NULL, not "", to "data"
  588. // parameter of mount(2) syscall.
  589. // This is crucial for filesystems that don't accept
  590. // any arbitrary mount options, like cgroup fs:
  591. // "mount -t cgroup none /mnt"
  592. if (options[0] && unrecognized) {
  593. // Add it to strflags, to pass on to kernel
  594. char *p = *unrecognized;
  595. unsigned len = p ? strlen(p) : 0;
  596. *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
  597. // Comma separated if it's not the first one
  598. if (len) p[len++] = ',';
  599. strcpy(p + len, options);
  600. }
  601. found:
  602. if (!comma)
  603. break;
  604. // Advance to next option
  605. *comma = ',';
  606. options = ++comma;
  607. }
  608. return flags;
  609. }
  610. // Return a list of all block device backed filesystems
  611. static llist_t *get_block_backed_filesystems(void)
  612. {
  613. static const char filesystems[2][sizeof("/proc/filesystems")] ALIGN1 = {
  614. "/etc/filesystems",
  615. "/proc/filesystems",
  616. };
  617. char *fs, *buf;
  618. llist_t *list = NULL;
  619. int i;
  620. FILE *f;
  621. for (i = 0; i < 2; i++) {
  622. f = fopen_for_read(filesystems[i]);
  623. if (!f) continue;
  624. while ((buf = xmalloc_fgetline(f)) != NULL) {
  625. if (is_prefixed_with(buf, "nodev") && isspace(buf[5]))
  626. goto next;
  627. fs = skip_whitespace(buf);
  628. if (*fs == '#' || *fs == '*' || !*fs)
  629. goto next;
  630. llist_add_to_end(&list, xstrdup(fs));
  631. next:
  632. free(buf);
  633. }
  634. if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
  635. }
  636. return list;
  637. }
  638. #if ENABLE_FEATURE_CLEAN_UP
  639. static void delete_block_backed_filesystems(void)
  640. {
  641. llist_free(fslist, free);
  642. }
  643. #else
  644. void delete_block_backed_filesystems(void);
  645. #endif
  646. // Perform actual mount of specific filesystem at specific location.
  647. // NB: mp->xxx fields may be trashed on exit
  648. static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filteropts)
  649. {
  650. int rc = 0;
  651. vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS;
  652. if (FAKE_IT) {
  653. if (verbose >= 2)
  654. bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
  655. mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
  656. vfsflags, filteropts);
  657. goto mtab;
  658. }
  659. // Mount, with fallback to read-only if necessary.
  660. for (;;) {
  661. errno = 0;
  662. rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
  663. vfsflags, filteropts);
  664. if (rc == 0)
  665. goto mtab; // success
  666. // mount failed, try helper program
  667. // mount.<mnt_type>
  668. if (HELPERS_ALLOWED && mp->mnt_type) {
  669. char *args[8];
  670. int errno_save = errno;
  671. args[0] = xasprintf("mount.%s", mp->mnt_type);
  672. rc = 1;
  673. if (FAKE_IT)
  674. args[rc++] = (char *)"-f";
  675. if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
  676. args[rc++] = (char *)"-n";
  677. args[rc++] = mp->mnt_fsname;
  678. args[rc++] = mp->mnt_dir;
  679. if (filteropts) {
  680. args[rc++] = (char *)"-o";
  681. args[rc++] = filteropts;
  682. }
  683. args[rc] = NULL;
  684. rc = spawn_and_wait(args);
  685. free(args[0]);
  686. if (rc == 0)
  687. goto mtab; // success
  688. errno = errno_save;
  689. }
  690. // Should we retry read-only mount?
  691. if (vfsflags & MS_RDONLY)
  692. break; // no, already was tried
  693. if (option_mask32 & OPT_w)
  694. break; // no, "mount -w" never falls back to RO
  695. if (errno != EACCES && errno != EROFS)
  696. break; // no, error isn't hinting that RO may work
  697. if (!(vfsflags & MS_SILENT))
  698. bb_error_msg("%s is write-protected, mounting read-only",
  699. mp->mnt_fsname);
  700. vfsflags |= MS_RDONLY;
  701. }
  702. // Abort entirely if permission denied.
  703. if (rc && errno == EPERM)
  704. bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root);
  705. // If the mount was successful, and we're maintaining an old-style
  706. // mtab file by hand, add the new entry to it now.
  707. mtab:
  708. if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
  709. char *fsname;
  710. FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
  711. const char *option_str = mount_option_str;
  712. int i;
  713. if (!mountTable) {
  714. bb_simple_perror_msg(bb_path_mtab_file);
  715. goto ret;
  716. }
  717. // Add vfs string flags
  718. for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
  719. if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
  720. append_mount_options(&(mp->mnt_opts), option_str);
  721. option_str += strlen(option_str) + 1;
  722. }
  723. // Remove trailing / (if any) from directory we mounted on
  724. i = strlen(mp->mnt_dir) - 1;
  725. while (i > 0 && mp->mnt_dir[i] == '/')
  726. mp->mnt_dir[i--] = '\0';
  727. // Convert to canonical pathnames as needed
  728. mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
  729. fsname = NULL;
  730. if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
  731. mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
  732. mp->mnt_type = (char*)"bind";
  733. }
  734. mp->mnt_freq = mp->mnt_passno = 0;
  735. // Write and close
  736. #if ENABLE_FEATURE_MTAB_SUPPORT
  737. if (vfsflags & MS_MOVE)
  738. update_mtab_entry_on_move(mp);
  739. else
  740. #endif
  741. addmntent(mountTable, mp);
  742. endmntent(mountTable);
  743. if (ENABLE_FEATURE_CLEAN_UP) {
  744. free(mp->mnt_dir);
  745. free(fsname);
  746. }
  747. }
  748. ret:
  749. return rc;
  750. }
  751. #if ENABLE_FEATURE_MOUNT_NFS
  752. /*
  753. * Linux NFS mount
  754. * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  755. *
  756. * Licensed under GPLv2, see file LICENSE in this source tree.
  757. *
  758. * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  759. * numbers to be specified on the command line.
  760. *
  761. * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
  762. * Omit the call to connect() for Linux version 1.3.11 or later.
  763. *
  764. * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
  765. * Implemented the "bg", "fg" and "retry" mount options for NFS.
  766. *
  767. * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
  768. * - added Native Language Support
  769. *
  770. * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
  771. * plus NFSv3 stuff.
  772. */
  773. #define MOUNTPORT 635
  774. #define MNTPATHLEN 1024
  775. #define MNTNAMLEN 255
  776. #define FHSIZE 32
  777. #define FHSIZE3 64
  778. typedef char fhandle[FHSIZE];
  779. typedef struct {
  780. unsigned int fhandle3_len;
  781. char *fhandle3_val;
  782. } fhandle3;
  783. enum mountstat3 {
  784. MNT_OK = 0,
  785. MNT3ERR_PERM = 1,
  786. MNT3ERR_NOENT = 2,
  787. MNT3ERR_IO = 5,
  788. MNT3ERR_ACCES = 13,
  789. MNT3ERR_NOTDIR = 20,
  790. MNT3ERR_INVAL = 22,
  791. MNT3ERR_NAMETOOLONG = 63,
  792. MNT3ERR_NOTSUPP = 10004,
  793. MNT3ERR_SERVERFAULT = 10006,
  794. };
  795. typedef enum mountstat3 mountstat3;
  796. struct fhstatus {
  797. unsigned int fhs_status;
  798. union {
  799. fhandle fhs_fhandle;
  800. } fhstatus_u;
  801. };
  802. typedef struct fhstatus fhstatus;
  803. struct mountres3_ok {
  804. fhandle3 fhandle;
  805. struct {
  806. unsigned int auth_flavours_len;
  807. char *auth_flavours_val;
  808. } auth_flavours;
  809. };
  810. typedef struct mountres3_ok mountres3_ok;
  811. struct mountres3 {
  812. mountstat3 fhs_status;
  813. union {
  814. mountres3_ok mountinfo;
  815. } mountres3_u;
  816. };
  817. typedef struct mountres3 mountres3;
  818. typedef char *dirpath;
  819. typedef char *name;
  820. typedef struct mountbody *mountlist;
  821. struct mountbody {
  822. name ml_hostname;
  823. dirpath ml_directory;
  824. mountlist ml_next;
  825. };
  826. typedef struct mountbody mountbody;
  827. typedef struct groupnode *groups;
  828. struct groupnode {
  829. name gr_name;
  830. groups gr_next;
  831. };
  832. typedef struct groupnode groupnode;
  833. typedef struct exportnode *exports;
  834. struct exportnode {
  835. dirpath ex_dir;
  836. groups ex_groups;
  837. exports ex_next;
  838. };
  839. typedef struct exportnode exportnode;
  840. struct ppathcnf {
  841. int pc_link_max;
  842. short pc_max_canon;
  843. short pc_max_input;
  844. short pc_name_max;
  845. short pc_path_max;
  846. short pc_pipe_buf;
  847. uint8_t pc_vdisable;
  848. char pc_xxx;
  849. short pc_mask[2];
  850. };
  851. typedef struct ppathcnf ppathcnf;
  852. #define MOUNTPROG 100005
  853. #define MOUNTVERS 1
  854. #define MOUNTPROC_NULL 0
  855. #define MOUNTPROC_MNT 1
  856. #define MOUNTPROC_DUMP 2
  857. #define MOUNTPROC_UMNT 3
  858. #define MOUNTPROC_UMNTALL 4
  859. #define MOUNTPROC_EXPORT 5
  860. #define MOUNTPROC_EXPORTALL 6
  861. #define MOUNTVERS_POSIX 2
  862. #define MOUNTPROC_PATHCONF 7
  863. #define MOUNT_V3 3
  864. #define MOUNTPROC3_NULL 0
  865. #define MOUNTPROC3_MNT 1
  866. #define MOUNTPROC3_DUMP 2
  867. #define MOUNTPROC3_UMNT 3
  868. #define MOUNTPROC3_UMNTALL 4
  869. #define MOUNTPROC3_EXPORT 5
  870. enum {
  871. #ifndef NFS_FHSIZE
  872. NFS_FHSIZE = 32,
  873. #endif
  874. #ifndef NFS_PORT
  875. NFS_PORT = 2049
  876. #endif
  877. };
  878. /*
  879. * We want to be able to compile mount on old kernels in such a way
  880. * that the binary will work well on more recent kernels.
  881. * Thus, if necessary we teach nfsmount.c the structure of new fields
  882. * that will come later.
  883. *
  884. * Moreover, the new kernel includes conflict with glibc includes
  885. * so it is easiest to ignore the kernel altogether (at compile time).
  886. */
  887. struct nfs2_fh {
  888. char data[32];
  889. };
  890. struct nfs3_fh {
  891. unsigned short size;
  892. unsigned char data[64];
  893. };
  894. struct nfs_mount_data {
  895. int version; /* 1 */
  896. int fd; /* 1 */
  897. struct nfs2_fh old_root; /* 1 */
  898. int flags; /* 1 */
  899. int rsize; /* 1 */
  900. int wsize; /* 1 */
  901. int timeo; /* 1 */
  902. int retrans; /* 1 */
  903. int acregmin; /* 1 */
  904. int acregmax; /* 1 */
  905. int acdirmin; /* 1 */
  906. int acdirmax; /* 1 */
  907. struct sockaddr_in addr; /* 1 */
  908. char hostname[256]; /* 1 */
  909. int namlen; /* 2 */
  910. unsigned int bsize; /* 3 */
  911. struct nfs3_fh root; /* 4 */
  912. };
  913. /* bits in the flags field */
  914. enum {
  915. NFS_MOUNT_SOFT = 0x0001, /* 1 */
  916. NFS_MOUNT_INTR = 0x0002, /* 1 */
  917. NFS_MOUNT_SECURE = 0x0004, /* 1 */
  918. NFS_MOUNT_POSIX = 0x0008, /* 1 */
  919. NFS_MOUNT_NOCTO = 0x0010, /* 1 */
  920. NFS_MOUNT_NOAC = 0x0020, /* 1 */
  921. NFS_MOUNT_TCP = 0x0040, /* 2 */
  922. NFS_MOUNT_VER3 = 0x0080, /* 3 */
  923. NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
  924. NFS_MOUNT_NONLM = 0x0200, /* 3 */
  925. NFS_MOUNT_NOACL = 0x0800, /* 4 */
  926. NFS_MOUNT_NORDIRPLUS = 0x4000
  927. };
  928. /*
  929. * We need to translate between nfs status return values and
  930. * the local errno values which may not be the same.
  931. *
  932. * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
  933. * "after #include <errno.h> the symbol errno is reserved for any use,
  934. * it cannot even be used as a struct tag or field name".
  935. */
  936. #ifndef EDQUOT
  937. # define EDQUOT ENOSPC
  938. #endif
  939. /* Convert each NFSERR_BLAH into EBLAH */
  940. static const uint8_t nfs_err_stat[] ALIGN1 = {
  941. 1, 2, 5, 6, 13, 17,
  942. 19, 20, 21, 22, 27, 28,
  943. 30, 63, 66, 69, 70, 71
  944. };
  945. #if ( \
  946. EPERM | ENOENT | EIO | ENXIO | EACCES| EEXIST | \
  947. ENODEV| ENOTDIR | EISDIR | EINVAL| EFBIG | ENOSPC | \
  948. EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
  949. typedef uint8_t nfs_err_type;
  950. #else
  951. typedef uint16_t nfs_err_type;
  952. #endif
  953. static const nfs_err_type nfs_err_errnum[] ALIGN2 = {
  954. EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST,
  955. ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC,
  956. EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
  957. };
  958. static char *nfs_strerror(int status)
  959. {
  960. int i;
  961. for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
  962. if (nfs_err_stat[i] == status)
  963. return strerror(nfs_err_errnum[i]);
  964. }
  965. return xasprintf("unknown nfs status return value: %d", status);
  966. }
  967. static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
  968. {
  969. return xdr_opaque(xdrs, objp, FHSIZE);
  970. }
  971. static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
  972. {
  973. if (!xdr_u_int(xdrs, &objp->fhs_status))
  974. return FALSE;
  975. if (objp->fhs_status == 0)
  976. return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
  977. return TRUE;
  978. }
  979. static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
  980. {
  981. return xdr_string(xdrs, objp, MNTPATHLEN);
  982. }
  983. static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
  984. {
  985. return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
  986. (unsigned int *) &objp->fhandle3_len,
  987. FHSIZE3);
  988. }
  989. static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
  990. {
  991. if (!xdr_fhandle3(xdrs, &objp->fhandle))
  992. return FALSE;
  993. return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
  994. &(objp->auth_flavours.auth_flavours_len),
  995. ~0,
  996. sizeof(int),
  997. (xdrproc_t) xdr_int);
  998. }
  999. static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
  1000. {
  1001. return xdr_enum(xdrs, (enum_t *) objp);
  1002. }
  1003. static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
  1004. {
  1005. if (!xdr_mountstat3(xdrs, &objp->fhs_status))
  1006. return FALSE;
  1007. if (objp->fhs_status == MNT_OK)
  1008. return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
  1009. return TRUE;
  1010. }
  1011. #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
  1012. /*
  1013. * Unfortunately, the kernel prints annoying console messages
  1014. * in case of an unexpected nfs mount version (instead of
  1015. * just returning some error). Therefore we'll have to try
  1016. * and figure out what version the kernel expects.
  1017. *
  1018. * Variables:
  1019. * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
  1020. * NFS_MOUNT_VERSION: these nfsmount sources at compile time
  1021. * nfs_mount_version: version this source and running kernel can handle
  1022. */
  1023. static void
  1024. find_kernel_nfs_mount_version(void)
  1025. {
  1026. int kernel_version;
  1027. if (nfs_mount_version)
  1028. return;
  1029. nfs_mount_version = 4; /* default */
  1030. kernel_version = get_linux_version_code();
  1031. if (kernel_version) {
  1032. if (kernel_version < KERNEL_VERSION(2,2,18))
  1033. nfs_mount_version = 3;
  1034. /* else v4 since 2.3.99pre4 */
  1035. }
  1036. }
  1037. static void
  1038. get_mountport(struct pmap *pm_mnt,
  1039. struct sockaddr_in *server_addr,
  1040. long unsigned prog,
  1041. long unsigned version,
  1042. long unsigned proto,
  1043. long unsigned port)
  1044. {
  1045. struct pmaplist *pmap;
  1046. server_addr->sin_port = PMAPPORT;
  1047. /* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
  1048. * I understand it like "IPv6 for this is not 100% ready" */
  1049. pmap = pmap_getmaps(server_addr);
  1050. if (version > MAX_NFSPROT)
  1051. version = MAX_NFSPROT;
  1052. if (!prog)
  1053. prog = MOUNTPROG;
  1054. pm_mnt->pm_prog = prog;
  1055. pm_mnt->pm_vers = version;
  1056. pm_mnt->pm_prot = proto;
  1057. pm_mnt->pm_port = port;
  1058. while (pmap) {
  1059. if (pmap->pml_map.pm_prog != prog)
  1060. goto next;
  1061. if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
  1062. goto next;
  1063. if (version > 2 && pmap->pml_map.pm_vers != version)
  1064. goto next;
  1065. if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
  1066. goto next;
  1067. if (pmap->pml_map.pm_vers > MAX_NFSPROT
  1068. || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
  1069. || (port && pmap->pml_map.pm_port != port)
  1070. ) {
  1071. goto next;
  1072. }
  1073. memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
  1074. next:
  1075. pmap = pmap->pml_next;
  1076. }
  1077. if (!pm_mnt->pm_vers)
  1078. pm_mnt->pm_vers = MOUNTVERS;
  1079. if (!pm_mnt->pm_port)
  1080. pm_mnt->pm_port = MOUNTPORT;
  1081. if (!pm_mnt->pm_prot)
  1082. pm_mnt->pm_prot = IPPROTO_TCP;
  1083. }
  1084. #if BB_MMU
  1085. static int daemonize(void)
  1086. {
  1087. int pid = fork();
  1088. if (pid < 0) /* error */
  1089. return -errno;
  1090. if (pid > 0) /* parent */
  1091. return 0;
  1092. /* child */
  1093. close(0);
  1094. xopen(bb_dev_null, O_RDWR);
  1095. xdup2(0, 1);
  1096. xdup2(0, 2);
  1097. setsid();
  1098. openlog(applet_name, LOG_PID, LOG_DAEMON);
  1099. logmode = LOGMODE_SYSLOG;
  1100. return 1;
  1101. }
  1102. #else
  1103. static inline int daemonize(void)
  1104. {
  1105. return -ENOSYS;
  1106. }
  1107. #endif
  1108. /* TODO */
  1109. static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
  1110. {
  1111. return 0;
  1112. }
  1113. /* RPC strerror analogs are terminally idiotic:
  1114. * *mandatory* prefix and \n at end.
  1115. * This hopefully helps. Usage:
  1116. * error_msg_rpc(clnt_*error*(" ")) */
  1117. static void error_msg_rpc(const char *msg)
  1118. {
  1119. int len;
  1120. while (msg[0] == ' ' || msg[0] == ':') msg++;
  1121. len = strlen(msg);
  1122. while (len && msg[len-1] == '\n') len--;
  1123. bb_error_msg("%.*s", len, msg);
  1124. }
  1125. /* NB: mp->xxx fields may be trashed on exit */
  1126. static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
  1127. {
  1128. CLIENT *mclient;
  1129. char *hostname;
  1130. char *pathname;
  1131. char *mounthost;
  1132. /* prior to 2.6.23, kernel took NFS options in a form of this struct
  1133. * only. 2.6.23+ looks at data->version, and if it's not 1..6,
  1134. * then data pointer is interpreted as a string. */
  1135. struct nfs_mount_data data;
  1136. char *opt;
  1137. char *tokstate;
  1138. struct hostent *hp;
  1139. struct sockaddr_in server_addr;
  1140. struct sockaddr_in mount_server_addr;
  1141. int msock, fsock;
  1142. union {
  1143. struct fhstatus nfsv2;
  1144. struct mountres3 nfsv3;
  1145. } status;
  1146. int daemonized;
  1147. char *s;
  1148. int port;
  1149. int mountport;
  1150. int proto;
  1151. #if BB_MMU
  1152. smallint bg = 0;
  1153. #else
  1154. enum { bg = 0 };
  1155. #endif
  1156. int retry;
  1157. int mountprog;
  1158. int mountvers;
  1159. int nfsprog;
  1160. int nfsvers;
  1161. int retval;
  1162. /* these all are one-bit really. gcc 4.3.1 likes this combination: */
  1163. smallint tcp;
  1164. smallint soft;
  1165. int intr;
  1166. int posix;
  1167. int nocto;
  1168. int noac;
  1169. int nordirplus;
  1170. int nolock;
  1171. int noacl;
  1172. find_kernel_nfs_mount_version();
  1173. daemonized = 0;
  1174. mounthost = NULL;
  1175. retval = ETIMEDOUT;
  1176. msock = fsock = -1;
  1177. mclient = NULL;
  1178. /* NB: hostname, mounthost, filteropts must be free()d prior to return */
  1179. filteropts = xstrdup(filteropts); /* going to trash it later... */
  1180. hostname = xstrdup(mp->mnt_fsname);
  1181. /* mount_main() guarantees that ':' is there */
  1182. s = strchr(hostname, ':');
  1183. pathname = s + 1;
  1184. *s = '\0';
  1185. /* Ignore all but first hostname in replicated mounts
  1186. * until they can be fully supported. (mack@sgi.com) */
  1187. s = strchr(hostname, ',');
  1188. if (s) {
  1189. *s = '\0';
  1190. bb_simple_error_msg("warning: multiple hostnames not supported");
  1191. }
  1192. server_addr.sin_family = AF_INET;
  1193. if (!inet_aton(hostname, &server_addr.sin_addr)) {
  1194. hp = gethostbyname(hostname);
  1195. if (hp == NULL) {
  1196. bb_simple_herror_msg(hostname);
  1197. goto fail;
  1198. }
  1199. if (hp->h_length != (int)sizeof(struct in_addr)) {
  1200. bb_simple_error_msg_and_die("only IPv4 is supported");
  1201. }
  1202. memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
  1203. }
  1204. memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
  1205. /* add IP address to mtab options for use when unmounting */
  1206. if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
  1207. mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
  1208. } else {
  1209. char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
  1210. mp->mnt_opts[0] ? "," : "",
  1211. inet_ntoa(server_addr.sin_addr));
  1212. free(mp->mnt_opts);
  1213. mp->mnt_opts = tmp;
  1214. }
  1215. /* Set default options.
  1216. * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
  1217. * let the kernel decide.
  1218. * timeo is filled in after we know whether it'll be TCP or UDP. */
  1219. memset(&data, 0, sizeof(data));
  1220. data.retrans = 3;
  1221. data.acregmin = 3;
  1222. data.acregmax = 60;
  1223. data.acdirmin = 30;
  1224. data.acdirmax = 60;
  1225. data.namlen = NAME_MAX;
  1226. soft = 0;
  1227. intr = 0;
  1228. posix = 0;
  1229. nocto = 0;
  1230. nolock = 0;
  1231. noac = 0;
  1232. nordirplus = 0;
  1233. noacl = 0;
  1234. retry = 10000; /* 10000 minutes ~ 1 week */
  1235. tcp = 1; /* nfs-utils uses tcp per default */
  1236. mountprog = MOUNTPROG;
  1237. mountvers = 0;
  1238. port = 0;
  1239. mountport = 0;
  1240. nfsprog = 100003;
  1241. nfsvers = 0;
  1242. /* parse options */
  1243. if (filteropts) for (opt = strtok_r(filteropts, ",", &tokstate); opt; opt = strtok_r(NULL, ",", &tokstate)) {
  1244. char *opteq = strchr(opt, '=');
  1245. if (opteq) {
  1246. int val, idx;
  1247. static const char options[] ALIGN1 =
  1248. /* 0 */ "rsize\0"
  1249. /* 1 */ "wsize\0"
  1250. /* 2 */ "timeo\0"
  1251. /* 3 */ "retrans\0"
  1252. /* 4 */ "acregmin\0"
  1253. /* 5 */ "acregmax\0"
  1254. /* 6 */ "acdirmin\0"
  1255. /* 7 */ "acdirmax\0"
  1256. /* 8 */ "actimeo\0"
  1257. /* 9 */ "retry\0"
  1258. /* 10 */ "port\0"
  1259. /* 11 */ "mountport\0"
  1260. /* 12 */ "mounthost\0"
  1261. /* 13 */ "mountprog\0"
  1262. /* 14 */ "mountvers\0"
  1263. /* 15 */ "nfsprog\0"
  1264. /* 16 */ "nfsvers\0"
  1265. /* 17 */ "vers\0"
  1266. /* 18 */ "proto\0"
  1267. /* 19 */ "namlen\0"
  1268. /* 20 */ "addr\0";
  1269. *opteq++ = '\0';
  1270. idx = index_in_strings(options, opt);
  1271. switch (idx) {
  1272. case 12: // "mounthost"
  1273. mounthost = xstrndup(opteq,
  1274. strcspn(opteq, " \t\n\r,"));
  1275. continue;
  1276. case 18: // "proto"
  1277. if (is_prefixed_with(opteq, "tcp"))
  1278. tcp = 1;
  1279. else if (is_prefixed_with(opteq, "udp"))
  1280. tcp = 0;
  1281. else
  1282. bb_simple_error_msg("warning: unrecognized proto= option");
  1283. continue;
  1284. case 20: // "addr" - ignore
  1285. continue;
  1286. case -1: // unknown
  1287. if (vfsflags & MS_REMOUNT)
  1288. continue;
  1289. }
  1290. val = xatoi_positive(opteq);
  1291. switch (idx) {
  1292. case 0: // "rsize"
  1293. data.rsize = val;
  1294. continue;
  1295. case 1: // "wsize"
  1296. data.wsize = val;
  1297. continue;
  1298. case 2: // "timeo"
  1299. data.timeo = val;
  1300. continue;
  1301. case 3: // "retrans"
  1302. data.retrans = val;
  1303. continue;
  1304. case 4: // "acregmin"
  1305. data.acregmin = val;
  1306. continue;
  1307. case 5: // "acregmax"
  1308. data.acregmax = val;
  1309. continue;
  1310. case 6: // "acdirmin"
  1311. data.acdirmin = val;
  1312. continue;
  1313. case 7: // "acdirmax"
  1314. data.acdirmax = val;
  1315. continue;
  1316. case 8: // "actimeo"
  1317. data.acregmin = val;
  1318. data.acregmax = val;
  1319. data.acdirmin = val;
  1320. data.acdirmax = val;
  1321. continue;
  1322. case 9: // "retry"
  1323. retry = val;
  1324. continue;
  1325. case 10: // "port"
  1326. port = val;
  1327. continue;
  1328. case 11: // "mountport"
  1329. mountport = val;
  1330. continue;
  1331. case 13: // "mountprog"
  1332. mountprog = val;
  1333. continue;
  1334. case 14: // "mountvers"
  1335. mountvers = val;
  1336. continue;
  1337. case 15: // "nfsprog"
  1338. nfsprog = val;
  1339. continue;
  1340. case 16: // "nfsvers"
  1341. case 17: // "vers"
  1342. nfsvers = val;
  1343. continue;
  1344. case 19: // "namlen"
  1345. //if (nfs_mount_version >= 2)
  1346. data.namlen = val;
  1347. //else
  1348. // bb_error_msg("warning: option namlen is not supported\n");
  1349. continue;
  1350. default:
  1351. bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
  1352. goto fail;
  1353. }
  1354. }
  1355. else { /* not of the form opt=val */
  1356. static const char options[] ALIGN1 =
  1357. "bg\0"
  1358. "fg\0"
  1359. "soft\0"
  1360. "hard\0"
  1361. "intr\0"
  1362. "posix\0"
  1363. "cto\0"
  1364. "ac\0"
  1365. "tcp\0"
  1366. "udp\0"
  1367. "lock\0"
  1368. "rdirplus\0"
  1369. "acl\0";
  1370. int val = 1;
  1371. if (is_prefixed_with(opt, "no")) {
  1372. val = 0;
  1373. opt += 2;
  1374. }
  1375. switch (index_in_strings(options, opt)) {
  1376. case 0: // "bg"
  1377. #if BB_MMU
  1378. bg = val;
  1379. #endif
  1380. break;
  1381. case 1: // "fg"
  1382. #if BB_MMU
  1383. bg = !val;
  1384. #endif
  1385. break;
  1386. case 2: // "soft"
  1387. soft = val;
  1388. break;
  1389. case 3: // "hard"
  1390. soft = !val;
  1391. break;
  1392. case 4: // "intr"
  1393. intr = val;
  1394. break;
  1395. case 5: // "posix"
  1396. posix = val;
  1397. break;
  1398. case 6: // "cto"
  1399. nocto = !val;
  1400. break;
  1401. case 7: // "ac"
  1402. noac = !val;
  1403. break;
  1404. case 8: // "tcp"
  1405. tcp = val;
  1406. break;
  1407. case 9: // "udp"
  1408. tcp = !val;
  1409. break;
  1410. case 10: // "lock"
  1411. if (nfs_mount_version >= 3)
  1412. nolock = !val;
  1413. else
  1414. bb_simple_error_msg("warning: option nolock is not supported");
  1415. break;
  1416. case 11: //rdirplus
  1417. nordirplus = !val;
  1418. break;
  1419. case 12: // acl
  1420. noacl = !val;
  1421. break;
  1422. default:
  1423. bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
  1424. goto fail;
  1425. }
  1426. }
  1427. }
  1428. proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
  1429. data.flags = (soft ? NFS_MOUNT_SOFT : 0)
  1430. | (intr ? NFS_MOUNT_INTR : 0)
  1431. | (posix ? NFS_MOUNT_POSIX : 0)
  1432. | (nocto ? NFS_MOUNT_NOCTO : 0)
  1433. | (noac ? NFS_MOUNT_NOAC : 0)
  1434. | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
  1435. | (noacl ? NFS_MOUNT_NOACL : 0);
  1436. if (nfs_mount_version >= 2)
  1437. data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
  1438. if (nfs_mount_version >= 3)
  1439. data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
  1440. if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
  1441. bb_error_msg("NFSv%d not supported", nfsvers);
  1442. goto fail;
  1443. }
  1444. if (nfsvers && !mountvers)
  1445. mountvers = (nfsvers < 3) ? 1 : nfsvers;
  1446. if (nfsvers && nfsvers < mountvers) {
  1447. mountvers = nfsvers;
  1448. }
  1449. /* Adjust options if none specified */
  1450. if (!data.timeo)
  1451. data.timeo = tcp ? 70 : 7;
  1452. data.version = nfs_mount_version;
  1453. if (vfsflags & MS_REMOUNT)
  1454. goto do_mount;
  1455. /*
  1456. * If the previous mount operation on the same host was
  1457. * backgrounded, and the "bg" for this mount is also set,
  1458. * give up immediately, to avoid the initial timeout.
  1459. */
  1460. if (bg && we_saw_this_host_before(hostname)) {
  1461. daemonized = daemonize();
  1462. if (daemonized <= 0) { /* parent or error */
  1463. retval = -daemonized;
  1464. goto ret;
  1465. }
  1466. }
  1467. /* Create mount daemon client */
  1468. /* See if the nfs host = mount host. */
  1469. if (mounthost) {
  1470. if (mounthost[0] >= '0' && mounthost[0] <= '9') {
  1471. mount_server_addr.sin_family = AF_INET;
  1472. mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
  1473. } else {
  1474. hp = gethostbyname(mounthost);
  1475. if (hp == NULL) {
  1476. bb_simple_herror_msg(mounthost);
  1477. goto fail;
  1478. }
  1479. if (hp->h_length != (int)sizeof(struct in_addr)) {
  1480. bb_simple_error_msg_and_die("only IPv4 is supported");
  1481. }
  1482. mount_server_addr.sin_family = AF_INET;
  1483. memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
  1484. }
  1485. }
  1486. /*
  1487. * The following loop implements the mount retries. When the mount
  1488. * times out, and the "bg" option is set, we background ourself
  1489. * and continue trying.
  1490. *
  1491. * The case where the mount point is not present and the "bg"
  1492. * option is set, is treated as a timeout. This is done to
  1493. * support nested mounts.
  1494. *
  1495. * The "retry" count specified by the user is the number of
  1496. * minutes to retry before giving up.
  1497. */
  1498. {
  1499. struct timeval total_timeout;
  1500. struct timeval retry_timeout;
  1501. struct pmap pm_mnt;
  1502. time_t t;
  1503. time_t prevt;
  1504. time_t timeout;
  1505. retry_timeout.tv_sec = 3;
  1506. retry_timeout.tv_usec = 0;
  1507. total_timeout.tv_sec = 20;
  1508. total_timeout.tv_usec = 0;
  1509. /* FIXME: use monotonic()? */
  1510. timeout = time(NULL) + 60 * retry;
  1511. prevt = 0;
  1512. t = 30;
  1513. retry:
  1514. /* Be careful not to use too many CPU cycles */
  1515. if (t - prevt < 30)
  1516. sleep(30);
  1517. get_mountport(&pm_mnt, &mount_server_addr,
  1518. mountprog,
  1519. mountvers,
  1520. proto,
  1521. mountport);
  1522. nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
  1523. /* contact the mount daemon via TCP */
  1524. mount_server_addr.sin_port = htons(pm_mnt.pm_port);
  1525. msock = RPC_ANYSOCK;
  1526. switch (pm_mnt.pm_prot) {
  1527. case IPPROTO_UDP:
  1528. mclient = clntudp_create(&mount_server_addr,
  1529. pm_mnt.pm_prog,
  1530. pm_mnt.pm_vers,
  1531. retry_timeout,
  1532. &msock);
  1533. if (mclient)
  1534. break;
  1535. mount_server_addr.sin_port = htons(pm_mnt.pm_port);
  1536. msock = RPC_ANYSOCK;
  1537. case IPPROTO_TCP:
  1538. mclient = clnttcp_create(&mount_server_addr,
  1539. pm_mnt.pm_prog,
  1540. pm_mnt.pm_vers,
  1541. &msock, 0, 0);
  1542. break;
  1543. default:
  1544. mclient = NULL;
  1545. }
  1546. if (!mclient) {
  1547. if (!daemonized && prevt == 0)
  1548. error_msg_rpc(clnt_spcreateerror(" "));
  1549. } else {
  1550. enum clnt_stat clnt_stat;
  1551. /* Try to mount hostname:pathname */
  1552. mclient->cl_auth = authunix_create_default();
  1553. /* Make pointers in xdr_mountres3 NULL so
  1554. * that xdr_array allocates memory for us
  1555. */
  1556. memset(&status, 0, sizeof(status));
  1557. if (pm_mnt.pm_vers == 3)
  1558. clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
  1559. (xdrproc_t) xdr_dirpath,
  1560. (caddr_t) &pathname,
  1561. (xdrproc_t) xdr_mountres3,
  1562. (caddr_t) &status,
  1563. total_timeout);
  1564. else
  1565. clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
  1566. (xdrproc_t) xdr_dirpath,
  1567. (caddr_t) &pathname,
  1568. (xdrproc_t) xdr_fhstatus,
  1569. (caddr_t) &status,
  1570. total_timeout);
  1571. if (clnt_stat == RPC_SUCCESS)
  1572. goto prepare_kernel_data; /* we're done */
  1573. if (errno != ECONNREFUSED) {
  1574. error_msg_rpc(clnt_sperror(mclient, " "));
  1575. goto fail; /* don't retry */
  1576. }
  1577. /* Connection refused */
  1578. if (!daemonized && prevt == 0) /* print just once */
  1579. error_msg_rpc(clnt_sperror(mclient, " "));
  1580. auth_destroy(mclient->cl_auth);
  1581. clnt_destroy(mclient);
  1582. mclient = NULL;
  1583. close(msock);
  1584. msock = -1;
  1585. }
  1586. /* Timeout. We are going to retry... maybe */
  1587. if (!bg)
  1588. goto fail;
  1589. if (!daemonized) {
  1590. daemonized = daemonize();
  1591. if (daemonized <= 0) { /* parent or error */
  1592. retval = -daemonized;
  1593. goto ret;
  1594. }
  1595. }
  1596. prevt = t;
  1597. t = time(NULL);
  1598. if (t >= timeout)
  1599. /* TODO error message */
  1600. goto fail;
  1601. goto retry;
  1602. }
  1603. prepare_kernel_data:
  1604. if (nfsvers == 2) {
  1605. if (status.nfsv2.fhs_status != 0) {
  1606. bb_error_msg("%s:%s failed, reason given by server: %s",
  1607. hostname, pathname,
  1608. nfs_strerror(status.nfsv2.fhs_status));
  1609. goto fail;
  1610. }
  1611. memcpy(data.root.data,
  1612. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  1613. NFS_FHSIZE);
  1614. data.root.size = NFS_FHSIZE;
  1615. memcpy(data.old_root.data,
  1616. (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
  1617. NFS_FHSIZE);
  1618. } else {
  1619. fhandle3 *my_fhandle;
  1620. if (status.nfsv3.fhs_status != 0) {
  1621. bb_error_msg("%s:%s failed, reason given by server: %s",
  1622. hostname, pathname,
  1623. nfs_strerror(status.nfsv3.fhs_status));
  1624. goto fail;
  1625. }
  1626. my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
  1627. memset(data.old_root.data, 0, NFS_FHSIZE);
  1628. memset(&data.root, 0, sizeof(data.root));
  1629. data.root.size = my_fhandle->fhandle3_len;
  1630. memcpy(data.root.data,
  1631. (char *) my_fhandle->fhandle3_val,
  1632. my_fhandle->fhandle3_len);
  1633. data.flags |= NFS_MOUNT_VER3;
  1634. }
  1635. /* Create nfs socket for kernel */
  1636. if (tcp) {
  1637. if (nfs_mount_version < 3) {
  1638. bb_simple_error_msg("NFS over TCP is not supported");
  1639. goto fail;
  1640. }
  1641. fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  1642. } else
  1643. fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  1644. if (fsock < 0) {
  1645. bb_simple_perror_msg("nfs socket");
  1646. goto fail;
  1647. }
  1648. if (bindresvport(fsock, 0) < 0) {
  1649. bb_simple_perror_msg("nfs bindresvport");
  1650. goto fail;
  1651. }
  1652. if (port == 0) {
  1653. server_addr.sin_port = PMAPPORT;
  1654. port = pmap_getport(&server_addr, nfsprog, nfsvers,
  1655. tcp ? IPPROTO_TCP : IPPROTO_UDP);
  1656. if (port == 0)
  1657. port = NFS_PORT;
  1658. }
  1659. server_addr.sin_port = htons(port);
  1660. /* Prepare data structure for kernel */
  1661. data.fd = fsock;
  1662. memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
  1663. strncpy(data.hostname, hostname, sizeof(data.hostname));
  1664. /* Clean up */
  1665. auth_destroy(mclient->cl_auth);
  1666. clnt_destroy(mclient);
  1667. close(msock);
  1668. msock = -1;
  1669. if (bg) {
  1670. /* We must wait until mount directory is available */
  1671. struct stat statbuf;
  1672. int delay = 1;
  1673. while (stat(mp->mnt_dir, &statbuf) == -1) {
  1674. if (!daemonized) {
  1675. daemonized = daemonize();
  1676. if (daemonized <= 0) { /* parent or error */
  1677. /* FIXME: parent doesn't close fsock - ??! */
  1678. retval = -daemonized;
  1679. goto ret;
  1680. }
  1681. }
  1682. sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
  1683. delay *= 2;
  1684. if (delay > 30)
  1685. delay = 30;
  1686. }
  1687. }
  1688. /* Perform actual mount */
  1689. do_mount:
  1690. retval = mount_it_now(mp, vfsflags, (char*)&data);
  1691. goto ret;
  1692. /* Abort */
  1693. fail:
  1694. if (msock >= 0) {
  1695. if (mclient) {
  1696. auth_destroy(mclient->cl_auth);
  1697. clnt_destroy(mclient);
  1698. }
  1699. close(msock);
  1700. }
  1701. if (fsock >= 0)
  1702. close(fsock);
  1703. ret:
  1704. free(hostname);
  1705. free(mounthost);
  1706. free(filteropts);
  1707. return retval;
  1708. }
  1709. #else // !ENABLE_FEATURE_MOUNT_NFS
  1710. /* Linux 2.6.23+ supports nfs mounts with options passed as a string.
  1711. * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
  1712. * (However, note that then you lose any chances that NFS over IPv6 would work).
  1713. */
  1714. static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
  1715. {
  1716. len_and_sockaddr *lsa;
  1717. char *opts;
  1718. char *end;
  1719. char *dotted;
  1720. int ret;
  1721. # if ENABLE_FEATURE_IPV6
  1722. end = strchr(mp->mnt_fsname, ']');
  1723. if (end && end[1] == ':')
  1724. end++;
  1725. else
  1726. # endif
  1727. /* mount_main() guarantees that ':' is there */
  1728. end = strchr(mp->mnt_fsname, ':');
  1729. *end = '\0';
  1730. lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
  1731. *end = ':';
  1732. dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
  1733. if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
  1734. opts = xasprintf("%s%saddr=%s",
  1735. filteropts ? filteropts : "",
  1736. filteropts ? "," : "",
  1737. dotted
  1738. );
  1739. if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
  1740. ret = mount_it_now(mp, vfsflags, opts);
  1741. if (ENABLE_FEATURE_CLEAN_UP) free(opts);
  1742. return ret;
  1743. }
  1744. #endif // !ENABLE_FEATURE_MOUNT_NFS
  1745. // Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option
  1746. // and return NUM.
  1747. // Return 0 if not found.
  1748. // All instances must be parsed and removed (for example, since kernel 5.4
  1749. // squashfs: Unknown parameter 'sizelimit'
  1750. // will result if loopback mount option "sizelimit=NNN" is not removed
  1751. // and squashfs sees it in option string).
  1752. static unsigned long long cut_out_ull_opt(char *opts, const char *name_eq)
  1753. {
  1754. unsigned long long ret = 0;
  1755. if (!opts) // allow NULL opts (simplifies callers' work)
  1756. return ret;
  1757. for (;;) {
  1758. char *end;
  1759. char *opt;
  1760. // Find comma-delimited "NAME="
  1761. for (;;) {
  1762. opt = strstr(opts, name_eq);
  1763. if (!opt)
  1764. return ret;
  1765. if (opt == opts)
  1766. break; // found it (it's first opt)
  1767. if (opt[-1] == ',') {
  1768. opts = opt - 1;
  1769. break; // found it (it's not a first opt)
  1770. }
  1771. // False positive like "VNAME=", we are at "N".
  1772. // - skip it, loop back to searching
  1773. opts = opt + 1;
  1774. }
  1775. ret = bb_strtoull(opt + strlen(name_eq), &end, 0);
  1776. if (errno && errno != EINVAL) {
  1777. err:
  1778. bb_error_msg_and_die("bad option '%s'", opt);
  1779. }
  1780. if (*end == '\0') {
  1781. // It is "[,]NAME=NUM\0" - truncate it and return
  1782. *opts = '\0';
  1783. return ret;
  1784. }
  1785. if (*end != ',')
  1786. goto err;
  1787. // We are at trailing comma
  1788. // Remove "NAME=NUM," and loop back to check for duplicate opts
  1789. overlapping_strcpy(opt, end + 1);
  1790. }
  1791. }
  1792. // Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
  1793. // type detection. Returns 0 for success, nonzero for failure.
  1794. // NB: mp->xxx fields may be trashed on exit
  1795. static int singlemount(struct mntent *mp, int ignore_busy)
  1796. {
  1797. int loopfd = -1;
  1798. int rc = -1;
  1799. unsigned long vfsflags;
  1800. char *loopFile = NULL, *filteropts = NULL;
  1801. llist_t *fl = NULL;
  1802. struct stat st;
  1803. errno = 0;
  1804. vfsflags = parse_mount_options(mp->mnt_opts, &filteropts, NULL);
  1805. // Treat fstype "auto" as unspecified
  1806. if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
  1807. mp->mnt_type = NULL;
  1808. // Might this be a virtual filesystem?
  1809. if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
  1810. char *args[35];
  1811. char *s;
  1812. int n;
  1813. // fsname: "cmd#arg1#arg2..."
  1814. // WARNING: allows execution of arbitrary commands!
  1815. // Try "mount 'sh#-c#sh' bogus_dir".
  1816. // It is safe ONLY because non-root
  1817. // cannot use two-argument mount command
  1818. // and using one-argument "mount 'sh#-c#sh'" doesn't work:
  1819. // "mount: can't find sh#-c#sh in /etc/fstab"
  1820. // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
  1821. s = mp->mnt_fsname;
  1822. n = 0;
  1823. args[n++] = s;
  1824. while (*s && n < 35 - 2) {
  1825. if (*s++ == '#' && *s != '#') {
  1826. s[-1] = '\0';
  1827. args[n++] = s;
  1828. }
  1829. }
  1830. args[n++] = mp->mnt_dir;
  1831. args[n] = NULL;
  1832. rc = spawn_and_wait(args);
  1833. goto report_error;
  1834. }
  1835. // Might this be an CIFS filesystem?
  1836. if (ENABLE_FEATURE_MOUNT_CIFS
  1837. && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
  1838. && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
  1839. && mp->mnt_fsname[0] == mp->mnt_fsname[1]
  1840. ) {
  1841. int len;
  1842. char c;
  1843. char *hostname, *share;
  1844. len_and_sockaddr *lsa;
  1845. // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]"
  1846. hostname = mp->mnt_fsname + 2;
  1847. len = strcspn(hostname, "/\\");
  1848. share = hostname + len + 1;
  1849. if (len == 0 // 3rd char is a [back]slash (IOW: empty hostname)
  1850. || share[-1] == '\0' // no [back]slash after hostname
  1851. || share[0] == '\0' // empty share name
  1852. ) {
  1853. goto report_error;
  1854. }
  1855. c = share[-1];
  1856. share[-1] = '\0';
  1857. len = strcspn(share, "/\\");
  1858. // "unc=\\hostname\share" option is mandatory
  1859. // after CIFS option parsing was rewritten in Linux 3.4.
  1860. // Must use backslashes.
  1861. // If /dir1/dir2 is present, also add "prefixpath=dir1/dir2"
  1862. {
  1863. char *unc = xasprintf(
  1864. share[len] != '\0' /* "/dir1/dir2" exists? */
  1865. ? "unc=\\\\%s\\%.*s,prefixpath=%s"
  1866. : "unc=\\\\%s\\%.*s",
  1867. hostname,
  1868. len, share,
  1869. share + len + 1 /* "dir1/dir2" */
  1870. );
  1871. parse_mount_options(unc, &filteropts, NULL);
  1872. if (ENABLE_FEATURE_CLEAN_UP) free(unc);
  1873. }
  1874. lsa = host2sockaddr(hostname, 0);
  1875. share[-1] = c;
  1876. if (!lsa)
  1877. goto report_error;
  1878. // If there is no "ip=..." option yet
  1879. if (!is_prefixed_with(filteropts, ",ip="+1)
  1880. && !strstr(filteropts, ",ip=")
  1881. ) {
  1882. char *dotted, *ip;
  1883. // Insert "ip=..." option into options
  1884. dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
  1885. if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
  1886. ip = xasprintf("ip=%s", dotted);
  1887. if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
  1888. // Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be
  1889. // handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()).
  1890. // Currently, glibc does not support that (has no NI_NUMERICSCOPE),
  1891. // musl apparently does. This results in "ip=numericIPv6%iface_name"
  1892. // (instead of _numeric_ iface_id) with glibc.
  1893. // This probably should be fixed in glibc, not here.
  1894. // The workaround is to manually specify correct "ip=ADDR%n" option.
  1895. parse_mount_options(ip, &filteropts, NULL);
  1896. if (ENABLE_FEATURE_CLEAN_UP) free(ip);
  1897. }
  1898. mp->mnt_type = (char*)"cifs";
  1899. rc = mount_it_now(mp, vfsflags, filteropts);
  1900. goto report_error;
  1901. }
  1902. // Might this be an NFS filesystem?
  1903. if (!(vfsflags & (MS_BIND | MS_MOVE))
  1904. && (!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
  1905. ) {
  1906. char *colon = strchr(mp->mnt_fsname, ':');
  1907. if (colon // looks like "hostname:..."
  1908. && strchrnul(mp->mnt_fsname, '/') > colon // "hostname:" has no slashes
  1909. ) {
  1910. if (!mp->mnt_type)
  1911. mp->mnt_type = (char*)"nfs";
  1912. rc = nfsmount(mp, vfsflags, filteropts);
  1913. goto report_error;
  1914. }
  1915. }
  1916. // Look at the file. (Not found isn't a failure for remount, or for
  1917. // a synthetic filesystem like proc or sysfs.)
  1918. // (We use stat, not lstat, in order to allow
  1919. // mount symlink_to_file_or_blkdev dir)
  1920. if (!stat(mp->mnt_fsname, &st)
  1921. && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
  1922. ) {
  1923. // Do we need to allocate a loopback device for it?
  1924. if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
  1925. unsigned long long offset;
  1926. unsigned long long sizelimit;
  1927. loopFile = bb_simplify_path(mp->mnt_fsname);
  1928. mp->mnt_fsname = NULL; // will receive malloced loop dev name
  1929. // Parse and remove loopback options
  1930. offset = cut_out_ull_opt(filteropts, "offset=");
  1931. sizelimit = cut_out_ull_opt(filteropts, "sizelimit=");
  1932. // mount always creates AUTOCLEARed loopdevs, so that umounting
  1933. // drops them without any code in the userspace.
  1934. // This happens since circa linux-2.6.25:
  1935. // commit 96c5865559cee0f9cbc5173f3c949f6ce3525581
  1936. // Date: Wed Feb 6 01:36:27 2008 -0800
  1937. // Subject: Allow auto-destruction of loop devices
  1938. loopfd = set_loop(&mp->mnt_fsname,
  1939. loopFile,
  1940. offset,
  1941. sizelimit,
  1942. ((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
  1943. | BB_LO_FLAGS_AUTOCLEAR
  1944. );
  1945. if (loopfd < 0) {
  1946. if (errno == EPERM || errno == EACCES)
  1947. bb_simple_error_msg(bb_msg_perm_denied_are_you_root);
  1948. else
  1949. bb_simple_perror_msg("can't setup loop device");
  1950. return loopfd; // was "return errno", but it can be 0 here
  1951. }
  1952. // Autodetect bind mounts
  1953. } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
  1954. vfsflags |= MS_BIND;
  1955. }
  1956. // If we know the fstype (or don't need to), jump straight
  1957. // to the actual mount.
  1958. if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
  1959. char *next;
  1960. for (;;) {
  1961. next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
  1962. if (next)
  1963. *next = '\0';
  1964. rc = mount_it_now(mp, vfsflags, filteropts);
  1965. if (rc == 0 || !next)
  1966. break;
  1967. mp->mnt_type = next + 1;
  1968. }
  1969. } else {
  1970. // Loop through filesystem types until mount succeeds
  1971. // or we run out
  1972. // Initialize list of block backed filesystems.
  1973. // This has to be done here so that during "mount -a",
  1974. // mounts after /proc shows up can autodetect.
  1975. if (!fslist) {
  1976. fslist = get_block_backed_filesystems();
  1977. if (ENABLE_FEATURE_CLEAN_UP && fslist)
  1978. atexit(delete_block_backed_filesystems);
  1979. }
  1980. for (fl = fslist; fl; fl = fl->link) {
  1981. mp->mnt_type = fl->data;
  1982. rc = mount_it_now(mp, vfsflags, filteropts);
  1983. if (rc == 0)
  1984. break;
  1985. }
  1986. }
  1987. // If mount failed, clean up loop file (if any).
  1988. // (Newer kernels which support LO_FLAGS_AUTOCLEAR should not need this,
  1989. // merely "close(loopfd)" should do it?)
  1990. if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
  1991. del_loop(mp->mnt_fsname);
  1992. if (ENABLE_FEATURE_CLEAN_UP) {
  1993. free(loopFile);
  1994. /* No, "rc != 0" needs it: free(mp->mnt_fsname); */
  1995. }
  1996. }
  1997. report_error:
  1998. if (ENABLE_FEATURE_CLEAN_UP)
  1999. free(filteropts);
  2000. if (loopfd >= 0)
  2001. close(loopfd);
  2002. if (errno == EBUSY && ignore_busy)
  2003. return 0;
  2004. if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL))
  2005. return 0;
  2006. if (rc != 0)
  2007. bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
  2008. return rc;
  2009. }
  2010. // -O support
  2011. // -O interprets a list of filter options which select whether a mount
  2012. // point will be mounted: only mounts with options matching *all* filtering
  2013. // options will be selected.
  2014. // By default each -O filter option must be present in the list of mount
  2015. // options, but if it is prefixed by "no" then it must be absent.
  2016. // For example,
  2017. // -O a,nob,c matches -o a,c but fails to match -o a,b,c
  2018. // (and also fails to match -o a because -o c is absent).
  2019. //
  2020. // It is different from -t in that each option is matched exactly; a leading
  2021. // "no" at the beginning of one option does not negate the rest.
  2022. static int match_opt(const char *fs_opt_in, const char *O_opt)
  2023. {
  2024. if (!O_opt)
  2025. return 1;
  2026. while (*O_opt) {
  2027. const char *fs_opt = fs_opt_in;
  2028. int O_len;
  2029. int match;
  2030. // If option begins with "no" then treat as an inverted match:
  2031. // matching is a failure
  2032. match = 0;
  2033. if (O_opt[0] == 'n' && O_opt[1] == 'o') {
  2034. match = 1;
  2035. O_opt += 2;
  2036. }
  2037. // Isolate the current O option
  2038. O_len = strchrnul(O_opt, ',') - O_opt;
  2039. // Check for a match against existing options
  2040. while (1) {
  2041. if (strncmp(fs_opt, O_opt, O_len) == 0
  2042. && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
  2043. ) {
  2044. if (match)
  2045. return 0; // "no" prefix, but option found
  2046. match = 1; // current O option found, go check next one
  2047. break;
  2048. }
  2049. fs_opt = strchr(fs_opt, ',');
  2050. if (!fs_opt)
  2051. break;
  2052. fs_opt++;
  2053. }
  2054. if (match == 0)
  2055. return 0; // match wanted but not found
  2056. if (O_opt[O_len] == '\0') // end?
  2057. break;
  2058. // Step to the next O option
  2059. O_opt += O_len + 1;
  2060. }
  2061. // If we get here then everything matched
  2062. return 1;
  2063. }
  2064. // Parse options, if necessary parse fstab/mtab, and call singlemount for
  2065. // each directory to be mounted.
  2066. int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  2067. int mount_main(int argc UNUSED_PARAM, char **argv)
  2068. {
  2069. char *cmdopts = xzalloc(1);
  2070. char *fstype = NULL;
  2071. char *O_optmatch = NULL;
  2072. char *storage_path;
  2073. llist_t *lst_o = NULL;
  2074. const char *fstabname = "/etc/fstab";
  2075. FILE *fstab;
  2076. int i, j;
  2077. int rc = EXIT_SUCCESS;
  2078. unsigned long cmdopt_flags;
  2079. unsigned opt;
  2080. struct mntent mtpair[2], *mtcur = mtpair;
  2081. IF_NOT_DESKTOP(const int nonroot = 0;)
  2082. IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
  2083. INIT_G();
  2084. // Parse long options, like --bind and --move. Note that -o option
  2085. // and --option are synonymous. Yes, this means --remount,rw works.
  2086. for (i = j = 1; argv[i]; i++) {
  2087. if (argv[i][0] == '-' && argv[i][1] == '-')
  2088. append_mount_options(&cmdopts, argv[i] + 2);
  2089. else
  2090. argv[j++] = argv[i];
  2091. }
  2092. argv[j] = NULL;
  2093. // Parse remaining options
  2094. // Max 2 params; -o is a list, -v is a counter
  2095. opt = getopt32(argv, "^"
  2096. OPTION_STR
  2097. "\0" "?2"IF_FEATURE_MOUNT_VERBOSE("vv"),
  2098. &lst_o, &fstype, &O_optmatch
  2099. IF_FEATURE_MOUNT_OTHERTAB(, &fstabname)
  2100. IF_FEATURE_MOUNT_VERBOSE(, &verbose)
  2101. );
  2102. while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
  2103. if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
  2104. if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
  2105. argv += optind;
  2106. // If we have no arguments, show currently mounted filesystems
  2107. if (!argv[0]) {
  2108. if (!(opt & OPT_a)) {
  2109. FILE *mountTable = setmntent(bb_path_mtab_file, "r");
  2110. if (!mountTable)
  2111. bb_error_msg_and_die("no %s", bb_path_mtab_file);
  2112. while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
  2113. GETMNTENT_BUFSIZE))
  2114. {
  2115. // Don't show rootfs. FIXME: why??
  2116. // util-linux 2.12a happily shows rootfs...
  2117. //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
  2118. if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
  2119. printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
  2120. mtpair->mnt_dir, mtpair->mnt_type,
  2121. mtpair->mnt_opts);
  2122. }
  2123. if (ENABLE_FEATURE_CLEAN_UP)
  2124. endmntent(mountTable);
  2125. return EXIT_SUCCESS;
  2126. }
  2127. storage_path = NULL;
  2128. } else {
  2129. // When we have two arguments, the second is the directory and we can
  2130. // skip looking at fstab entirely. We can always abspath() the directory
  2131. // argument when we get it.
  2132. if (argv[1]) {
  2133. if (nonroot)
  2134. bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
  2135. mtpair->mnt_fsname = argv[0];
  2136. mtpair->mnt_dir = argv[1];
  2137. mtpair->mnt_type = fstype;
  2138. mtpair->mnt_opts = cmdopts;
  2139. resolve_mount_spec(&mtpair->mnt_fsname);
  2140. rc = singlemount(mtpair, /*ignore_busy:*/ 0);
  2141. return rc;
  2142. }
  2143. storage_path = bb_simplify_path(argv[0]); // malloced
  2144. }
  2145. // Past this point, we are handling either "mount -a [opts]"
  2146. // or "mount [opts] single_param"
  2147. cmdopt_flags = parse_mount_options(cmdopts, NULL, &option_mask32);
  2148. if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
  2149. bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
  2150. // If we have a shared subtree flag, don't worry about fstab or mtab.
  2151. if (ENABLE_FEATURE_MOUNT_FLAGS
  2152. && (cmdopt_flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
  2153. ) {
  2154. // verbose_mount(source, target, type, flags, data)
  2155. rc = verbose_mount("", argv[0], "", cmdopt_flags, "");
  2156. if (rc)
  2157. bb_simple_perror_msg_and_die(argv[0]);
  2158. return rc;
  2159. }
  2160. // A malicious user could overmount /usr without this.
  2161. if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot)
  2162. fstabname = "/etc/fstab";
  2163. // Open either fstab or mtab
  2164. if (cmdopt_flags & MS_REMOUNT) {
  2165. // WARNING. I am not sure this matches util-linux's
  2166. // behavior. It's possible util-linux does not
  2167. // take -o opts from mtab (takes only mount source).
  2168. fstabname = bb_path_mtab_file;
  2169. }
  2170. fstab = setmntent(fstabname, "r");
  2171. if (!fstab)
  2172. bb_perror_msg_and_die("can't read '%s'", fstabname);
  2173. // Loop through entries until we find what we're looking for
  2174. memset(mtpair, 0, sizeof(mtpair));
  2175. for (;;) {
  2176. struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
  2177. // Get next fstab entry
  2178. if (!getmntent_r(fstab, mtcur, getmntent_buf
  2179. + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
  2180. GETMNTENT_BUFSIZE/2)
  2181. ) { // End of fstab/mtab is reached
  2182. mtcur = mtother; // the thing we found last time
  2183. break;
  2184. }
  2185. // If we're trying to mount something specific and this isn't it,
  2186. // skip it. Note we must match the exact text in fstab (ala
  2187. // "proc") or a full path from root
  2188. if (argv[0]) {
  2189. // Is this what we're looking for?
  2190. if (strcmp(argv[0], mtcur->mnt_fsname) != 0
  2191. && strcmp(storage_path, mtcur->mnt_fsname) != 0
  2192. && strcmp(argv[0], mtcur->mnt_dir) != 0
  2193. && strcmp(storage_path, mtcur->mnt_dir) != 0
  2194. ) {
  2195. continue; // no
  2196. }
  2197. // Remember this entry. Something later may have
  2198. // overmounted it, and we want the _last_ match.
  2199. mtcur = mtother;
  2200. // If we're mounting all
  2201. } else {
  2202. struct mntent *mp;
  2203. // No, mount -a won't mount anything,
  2204. // even user mounts, for mere humans
  2205. if (nonroot)
  2206. bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
  2207. // Does type match? (NULL matches always)
  2208. if (!fstype_matches(mtcur->mnt_type, fstype))
  2209. continue;
  2210. // Skip noauto and swap anyway
  2211. if ((parse_mount_options(mtcur->mnt_opts, NULL, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
  2212. // swap is bogus "fstype", parse_mount_options can't check fstypes
  2213. || strcasecmp(mtcur->mnt_type, "swap") == 0
  2214. ) {
  2215. continue;
  2216. }
  2217. // Does (at least one) option match?
  2218. // (NULL matches always)
  2219. if (!match_opt(mtcur->mnt_opts, O_optmatch))
  2220. continue;
  2221. resolve_mount_spec(&mtcur->mnt_fsname);
  2222. // NFS mounts want this to be xrealloc-able
  2223. mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
  2224. // If nothing is mounted on this directory...
  2225. // (otherwise repeated "mount -a" mounts everything again)
  2226. mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
  2227. // We do not check fsname match of found mount point -
  2228. // "/" may have fsname of "/dev/root" while fstab
  2229. // says "/dev/something_else".
  2230. if (mp) {
  2231. if (verbose) {
  2232. bb_error_msg("according to %s, "
  2233. "%s is already mounted on %s",
  2234. bb_path_mtab_file,
  2235. mp->mnt_fsname, mp->mnt_dir);
  2236. }
  2237. } else {
  2238. // ...mount this thing
  2239. if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
  2240. // Count number of failed mounts
  2241. rc++;
  2242. }
  2243. }
  2244. free(mtcur->mnt_opts);
  2245. }
  2246. }
  2247. // End of fstab/mtab is reached.
  2248. // Were we looking for something specific?
  2249. if (argv[0]) { // yes
  2250. unsigned long l;
  2251. // If we didn't find anything, complain
  2252. if (!mtcur->mnt_fsname)
  2253. bb_error_msg_and_die("can't find %s in %s",
  2254. argv[0], fstabname);
  2255. // What happens when we try to "mount swap_partition"?
  2256. // (fstab containts "swap_partition swap swap defaults 0 0")
  2257. // util-linux-ng 2.13.1 does this:
  2258. // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
  2259. // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
  2260. // lstat("swap", 0x7fff62a3a640) = -1 ENOENT (No such file or directory)
  2261. // write(2, "mount: mount point swap does not exist\n", 39) = 39
  2262. // exit_group(32) = ?
  2263. #if 0
  2264. // In case we want to simply skip swap partitions:
  2265. l = parse_mount_options(mtcur->mnt_opts, NULL, NULL);
  2266. if ((l & MOUNT_SWAP)
  2267. // swap is bogus "fstype", parse_mount_options can't check fstypes
  2268. || strcasecmp(mtcur->mnt_type, "swap") == 0
  2269. ) {
  2270. goto ret;
  2271. }
  2272. #endif
  2273. if (nonroot) {
  2274. // fstab must have "users" or "user"
  2275. l = parse_mount_options(mtcur->mnt_opts, NULL, NULL);
  2276. if (!(l & MOUNT_USERS))
  2277. bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
  2278. }
  2279. //util-linux-2.12 does not do this check.
  2280. //// If nothing is mounted on this directory...
  2281. //// (otherwise repeated "mount FOO" mounts FOO again)
  2282. //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
  2283. //if (mp) {
  2284. // bb_error_msg("according to %s, "
  2285. // "%s is already mounted on %s",
  2286. // bb_path_mtab_file,
  2287. // mp->mnt_fsname, mp->mnt_dir);
  2288. //} else {
  2289. // ...mount the last thing we found
  2290. mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
  2291. append_mount_options(&(mtcur->mnt_opts), cmdopts);
  2292. resolve_mount_spec(&mtpair->mnt_fsname);
  2293. rc = singlemount(mtcur, /*ignore_busy:*/ 0);
  2294. if (ENABLE_FEATURE_CLEAN_UP)
  2295. free(mtcur->mnt_opts);
  2296. //}
  2297. }
  2298. //ret:
  2299. if (ENABLE_FEATURE_CLEAN_UP)
  2300. endmntent(fstab);
  2301. if (ENABLE_FEATURE_CLEAN_UP) {
  2302. free(storage_path);
  2303. free(cmdopts);
  2304. }
  2305. //TODO: exitcode should be ORed mask of (from "man mount"):
  2306. // 0 success
  2307. // 1 incorrect invocation or permissions
  2308. // 2 system error (out of memory, cannot fork, no more loop devices)
  2309. // 4 internal mount bug or missing nfs support in mount
  2310. // 8 user interrupt
  2311. //16 problems writing or locking /etc/mtab
  2312. //32 mount failure
  2313. //64 some mount succeeded
  2314. return rc;
  2315. }