github.com/rigado/snapd@v2.42.5-go-mod+incompatible/cmd/snapd-generator/main.c (about) 1 /* 2 * Copyright (C) 2018 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include "config.h" 23 24 #include "../libsnap-confine-private/cleanup-funcs.h" 25 #include "../libsnap-confine-private/mountinfo.h" 26 #include "../libsnap-confine-private/string-utils.h" 27 28 static sc_mountinfo_entry *find_root_mountinfo(sc_mountinfo * mounts) 29 { 30 sc_mountinfo_entry *cur, *root = NULL; 31 for (cur = sc_first_mountinfo_entry(mounts); cur != NULL; 32 cur = sc_next_mountinfo_entry(cur)) { 33 // Look for the mount info entry for the root file-system. 34 if (sc_streq("/", cur->mount_dir)) { 35 root = cur; 36 } 37 } 38 return root; 39 } 40 41 int main(int argc, char **argv) 42 { 43 if (argc != 4) { 44 printf("usage: snapd-workaround-generator " 45 "normal-dir early-dir late-dir\n"); 46 return 1; 47 } 48 const char *normal_dir = argv[1]; 49 // For reference, but we don't use those variables here. 50 // const char *early_dir = argv[2]; 51 // const char *late_dir = argv[3]; 52 53 // Load /proc/self/mountinfo so that we can inspect the root filesystem. 54 sc_mountinfo *mounts SC_CLEANUP(sc_cleanup_mountinfo) = NULL; 55 mounts = sc_parse_mountinfo(NULL); 56 if (!mounts) { 57 fprintf(stderr, "cannot open or parse /proc/self/mountinfo\n"); 58 return 1; 59 } 60 61 sc_mountinfo_entry *root = find_root_mountinfo(mounts); 62 if (!root) { 63 fprintf(stderr, 64 "cannot find mountinfo entry of the root filesystem\n"); 65 return 1; 66 } 67 // Check if the root file-system is mounted with shared option. 68 if (strstr(root->optional_fields, "shared:") != NULL) { 69 // The workaround is not needed, everything is good as-is. 70 return 0; 71 } 72 // Construct the file name for a new systemd mount unit. 73 char fname[PATH_MAX + 1] = { 0 }; 74 sc_must_snprintf(fname, sizeof fname, 75 "%s/" SNAP_MOUNT_DIR ".mount", normal_dir); 76 77 // Open the mount unit and write the contents. 78 FILE *f SC_CLEANUP(sc_cleanup_file) = NULL; 79 f = fopen(fname, "wt"); 80 if (!f) { 81 fprintf(stderr, "cannot open %s: %m\n", fname); 82 return 1; 83 } 84 fprintf(f, 85 "# Ensure that snap mount directory is mounted \"shared\" " 86 "so snaps can be refreshed correctly (LP: #1668759).\n"); 87 fprintf(f, "[Unit]\n"); 88 fprintf(f, 89 "Description=Ensure that the snap directory " 90 "shares mount events.\n"); 91 fprintf(f, "[Mount]\n"); 92 fprintf(f, "What=" SNAP_MOUNT_DIR "\n"); 93 fprintf(f, "Where=" SNAP_MOUNT_DIR "\n"); 94 fprintf(f, "Type=none\n"); 95 fprintf(f, "Options=bind,shared\n"); 96 fprintf(f, "[Install]\n"); 97 fprintf(f, "WantedBy=local-fs.target\n"); 98 return 0; 99 }