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  }