{"action":"closed","issue":{"url":"https://api.github.com/repos/bedrocklinux/bedrocklinux-userland/issues/37","labels_url":"https://api.github.com/repos/bedrocklinux/bedrocklinux-userland/issues/37/labels{/name}","comments_url":"https://api.github.com/repos/bedrocklinux/bedrocklinux-userland/issues/37/comments","events_url":"https://api.github.com/repos/bedrocklinux/bedrocklinux-userland/issues/37/events","html_url":"https://github.com/bedrocklinux/bedrocklinux-userland/issues/37","id":75746462,"number":37,"title":"bru reference files under its own mount point","user":{"login":"paradigm","id":149964,"avatar_url":"https://avatars.githubusercontent.com/u/149964?v=3","gravatar_id":"","url":"https://api.github.com/users/paradigm","html_url":"https://github.com/paradigm","followers_url":"https://api.github.com/users/paradigm/followers","following_url":"https://api.github.com/users/paradigm/following{/other_user}","gists_url":"https://api.github.com/users/paradigm/gists{/gist_id}","starred_url":"https://api.github.com/users/paradigm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paradigm/subscriptions","organizations_url":"https://api.github.com/users/paradigm/orgs","repos_url":"https://api.github.com/users/paradigm/repos","events_url":"https://api.github.com/users/paradigm/events{/privacy}","received_events_url":"https://api.github.com/users/paradigm/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":{"login":"slackbyte","id":1149839,"avatar_url":"https://avatars.githubusercontent.com/u/1149839?v=3","gravatar_id":"","url":"https://api.github.com/users/slackbyte","html_url":"https://github.com/slackbyte","followers_url":"https://api.github.com/users/slackbyte/followers","following_url":"https://api.github.com/users/slackbyte/following{/other_user}","gists_url":"https://api.github.com/users/slackbyte/gists{/gist_id}","starred_url":"https://api.github.com/users/slackbyte/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slackbyte/subscriptions","organizations_url":"https://api.github.com/users/slackbyte/orgs","repos_url":"https://api.github.com/users/slackbyte/repos","events_url":"https://api.github.com/users/slackbyte/events{/privacy}","received_events_url":"https://api.github.com/users/slackbyte/received_events","type":"User","site_admin":false},"milestone":null,"comments":2,"created_at":"2015-05-12T21:31:17Z","updated_at":"2015-09-20T16:49:04Z","closed_at":"2015-09-20T16:49:04Z","body":"From a high level, what bru does is redirect any filesystem requires going\r\ntowards a specific list of files elsewhere (the \"alternate\" files).  For\r\neverything else (the \"default\" files), it should act as a pass-through,\r\ndelivering the same exact functionality that would be available if it was not\r\nmounted.\r\n\r\nFor bru to do this, it needs:\r\n\r\n- to be mounted over a directory that will contain all of the relevant\r\n  filepaths.  For example, `/etc`.\r\n- access to the \"default\" files.  For example, `/etc`.\r\n- access to the \"alternate\" files.  For example,\r\n  `/bedrock/clients/global/etc/`.\r\n\r\nNote that the mount point and the default files root are both actually the same\r\nlocation.  This leads to a problem - bru cannot pass-through to the default\r\nlocations, as it would then be querying itself for what to do (which would then\r\nbe an infinite loop).\r\n\r\nAs of Hawky, bru resolves this by ensuring the \"default\" files are accessible\r\nat another location it can reference.  Specifically,\r\n`/bedrock/clients/<client-name>/<path-to-mount-point>`.  For example, a bru\r\nmounted on `/etc` in client `wheezy` can see the file `/etc/issue` at\r\n`/bedrock/clients/wheezy/etc/issue`.\r\n\r\nThe fact the files which bru will mount over are available elsewhere is a\r\nside-effect of Hawky's design.  It was, in some sense, \"free\" - those files\r\nwere going to be available there anyways.  Nyla, however, will change things\r\nsuch that that may no longer be the case.  While we may be able to create\r\nadditional directories and mounts to resolve this, it is undesirable.\r\n\r\nAn alternative solution would be to alter bru so that it can see under its own\r\nmount point and reference those files instead.  This is preferable in that it\r\ndoes not require we create more directories and more mounts, and is also\r\ndesirable in that `bru` will take fewer arguments and function more naturally\r\nto how a user (who is not considering the technical, underlying details) would\r\nexpect it to.\r\n\r\nTry this:\r\n\r\n- In terminal \"A\":\r\n\r\n    mkdir -p /tmp/test\r\n    cd /tmp/test\r\n    touch foo bar baz\r\n\r\n- In terminal \"B\", as root:\r\n\r\n    mount -t proc proc /tmp/test\r\n    cd /tmp/test\r\n    pwd\r\n    ls\r\n    ls /tmp/test\r\n\r\n- Back in terminal \"A\":\r\n\r\n    pwd\r\n    ls\r\n    ls /tmp/test\r\n\r\n- Clean up with (in any terminal, as root):\r\n\r\n    cd /\r\n    umount /tmp/test\r\n    rm -r /tmp/test\r\n\r\nBoth shells *think* they're in the same pwd, but actually see different things,\r\n*when they use a path relative to their pwd*.  When they use an absolute path,\r\nthey see the same thing.  The plan is for bru to do this same technique so that\r\nit can see under its own mount point.\r\n\r\nBroadly, there are two strategies.  In theory, we can mix-and-match components\r\nfrom both, although it may be desirable to use as much as we can from one for\r\nthe sake of uniformity.\r\n\r\nOne strategy is to set the present working directory to the mount point\r\n_before_ it is mounted.  Then, reference the \"default\" files via a relative\r\npath.  That is, do a `chdir(\"/path/to/mount/point\")` in FUSE *before* calling\r\n`fuse_main()`.  Then, in all of the individual filesystem call functions,\r\nreference the specified file via a relative path, e.g. `stat(\"path/to/file\")`\r\n*not* `stat(\"/path/to/file\")`.  The \"alternate\" files can be accessed via the\r\nfull path.  This is effectively the same thing we did with the shell example\r\nabove.\r\n\r\nAnother strategy is to utilize a family of Linux filesystem calls which\r\nreference, instead of the pwd, a file handler.  With this strategy, bru would\r\n`open()` the directory under its mount point and store the file handler before\r\ncalling `fuse_main()`.  It would then reference this whenever it wants the\r\n\"default\" file.  One could also `open()` the \"alternate\" file directory root.\r\nThen each filesystem call would simply have to choose which file handler to\r\nreference.\r\n\r\nThe filesystem calls which operate relative to a file handler - instead of the\r\npwd - tend to have the same name as the \"normal\" filesystem call, but with \"at\"\r\nappended at the end.  For example, `renameat()` and `unlinkat`.  There are\r\nequivalents to these for many - but not quite all - of the filesystem calls.\r\nFor many of these exceptions, there is another family of calls that work on a\r\nfile handler *directly* instead of a file path; these tend to start with \"f\".\r\nFor example, `fstat()` and `ftruncate()`.  One can, thus, use `openat()` -\r\ngiving it a reference file handler - and get back another file handler to pass\r\nto `fstat()`.\r\n\r\nThe pwd-based strategy is preferable in that it requires fewer changes to the\r\ncurrent `bru` code base, as we can use all of the same filesystem calls - just\r\nensure the path is relative if default, or use the full path if alternate.\r\n\r\nThe file handler-based strategy is preferable in that there is much less string\r\nmanipulation; no need to take an incoming absolute path and either drop the\r\nleading \"/\" to make it relative or concatenate it to the alternate root.\r\nHowever, it will require changing a fair number of lines of code to use the\r\n\\*at() versions of the libraries.\r\n\r\nIn theory, we could implement some filesystem calls one way, and implement some\r\nanother; however, a uniform strategy would be preferable.\r\n"}}