1717
1818#include <libmount/libmount.h>
1919
20- #define exit_with_error (str ) \
20+ #define exit_with_error (... ) \
2121 do { \
22- fputs(str, stderr); \
22+ fprintf(stderr, __VA_ARGS__); \
2323 exit(EXIT_FAILURE); \
2424 } while (0)
2525
2626static void help (char const * argv0 ) {
27- fputs ("Usage: " , stderr );
28- fputs (argv0 , stderr );
29- fputs (" <squashfs file> <mountpoint> [--offset=4096] <command> [args...]\n\n "
30- " The --offset=4096 option "
31- "translates to an offset=4096 mount option.\n" ,
32- stderr );
33- exit (EXIT_FAILURE );
27+ exit_with_error (
28+ "Usage: %s <squashfs file> <mountpoint> <command> [args...]\n" , argv0 );
3429}
3530
3631int main (int argc , char * * argv ) {
3732 struct libmnt_context * cxt ;
3833 uid_t uid = getuid ();
3934 char * program = argv [0 ];
40- int has_offset = 0 ;
4135 struct stat mnt_stat ;
4236
4337 argv ++ ;
4438 argc -- ;
4539
46- // Only parse flags up to position 3, we don't want to do arg parsing of the
47- // command that is going to be executed.
48- for (int i = 0 ; i < argc && i < 3 ; ++ i ) {
49- if (strcmp (argv [i ], "-h" ) == 0 || strcmp (argv [i ], "--help" ) == 0 ) {
40+ // Early exit for -h, --help, -v, --version.
41+ for (int i = 0 , num_positional = 0 ; i < argc && num_positional <= 2 ; ++ i ) {
42+ char const * arg = argv [i ];
43+ // Skip positional args.
44+ if (arg [0 ] != '-' || arg [1 ] == '\0' ) {
45+ ++ num_positional ;
46+ continue ;
47+ }
48+ // Early exit on -h, --help, -v, --version
49+ ++ arg ;
50+ if (strcmp (arg , "h" ) == 0 || strcmp (arg , "-help" ) == 0 )
5051 help (program );
51- } else if (strcmp (argv [i ], "-v" ) == 0 ||
52- strcmp (argv [i ], "--version" ) == 0 ) {
52+ if (strcmp (arg , "v" ) == 0 || strcmp (arg , "-version" ) == 0 ) {
5353 puts (VERSION );
5454 exit (EXIT_SUCCESS );
5555 }
56+ // Error on unrecognized flags.
57+ errx (EXIT_FAILURE , "Unknown flag %s" , argv [i ]);
5658 }
5759
58- // We need at least 3 args
60+ // We need [squashfs_file] [mountpoint] [command]
5961 if (argc < 3 )
6062 help (program );
6163
@@ -65,72 +67,70 @@ int main(int argc, char **argv) {
6567 char * mountpoint = * argv ++ ;
6668 argc -- ;
6769
68- // The optional offset toggle.
69- if (strcmp (* argv , "--offset=4096" ) == 0 ) {
70- has_offset = 1 ;
71- argv ++ ;
72- argc -- ;
73- }
74-
75- if (argc == 0 )
76- help (program );
77-
7870 // Check that the mount point exists.
7971 int mnt_status = stat (mountpoint , & mnt_stat );
8072 if (mnt_status )
8173 err (EXIT_FAILURE , "Invalid mount point \"%s\"" , mountpoint );
8274 if (!S_ISDIR (mnt_stat .st_mode ))
83- errx (EXIT_FAILURE , "Invalid mount point \"%s\" is not a directory" , mountpoint );
75+ errx (EXIT_FAILURE , "Invalid mount point \"%s\" is not a directory" ,
76+ mountpoint );
8477
8578 // Check that the input squashfs file exists.
8679 int sqsh_status = stat (squashfs_file , & mnt_stat );
8780 if (sqsh_status )
8881 err (EXIT_FAILURE , "Invalid squashfs image file \"%s\"" , squashfs_file );
8982 if (!S_ISREG (mnt_stat .st_mode ))
90- errx (EXIT_FAILURE , "Requested squashfs image \"%s\" is not a file" , squashfs_file );
83+ errx (EXIT_FAILURE , "Requested squashfs image \"%s\" is not a file" ,
84+ squashfs_file );
9185
9286 if (unshare (CLONE_NEWNS ) != 0 )
93- exit_with_error ( "Failed to unshare the mount namespace\n " );
87+ err ( EXIT_FAILURE , "Failed to unshare the mount namespace" );
9488
9589 if (mount (NULL , "/" , NULL , MS_SLAVE | MS_REC , NULL ) != 0 )
96- exit_with_error ( "Failed to remount \"/\" with MS_SLAVE\n " );
90+ err ( EXIT_FAILURE , "Failed to remount \"/\" with MS_SLAVE" );
9791
9892 // Set real user to root before creating the mount context, otherwise it
9993 // fails.
10094 if (setreuid (0 , 0 ) != 0 )
101- exit_with_error ( "Failed to setreuid\n" );
95+ err ( EXIT_FAILURE , "Failed to setreuid\n" );
10296
97+ // Configure the mount
10398 // Makes LIBMOUNT_DEBUG=... work.
10499 mnt_init_debug (0 );
105100
106101 cxt = mnt_new_context ();
107102
108103 if (mnt_context_disable_mtab (cxt , 1 ) != 0 )
109- exit_with_error ( "Failed to disable mtab\n " );
104+ errx ( EXIT_FAILURE , "Failed to disable mtab" );
110105
111106 if (mnt_context_set_fstype (cxt , "squashfs" ) != 0 )
112- exit_with_error ("Failed to set fstype to squashfs\n" );
113-
114- char const * mount_options =
115- has_offset ? "loop,nosuid,nodev,ro,offset=4096" : "loop,nosuid,nodev,ro" ;
107+ errx (EXIT_FAILURE , "Failed to set fstype to squashfs" );
116108
117- if (mnt_context_append_options (cxt , mount_options ) != 0 )
118- exit_with_error ( "Failed to set mount options\n " );
109+ if (mnt_context_append_options (cxt , "loop,nosuid,nodev,ro" ) != 0 )
110+ errx ( EXIT_FAILURE , "Failed to set mount options" );
119111
120112 if (mnt_context_set_source (cxt , squashfs_file ) != 0 )
121- exit_with_error ( "Failed to set source\n " );
113+ errx ( EXIT_FAILURE , "Failed to set source" );
122114
123115 if (mnt_context_set_target (cxt , mountpoint ) != 0 )
124- exit_with_error ("Failed to set target\n" );
125-
126- if (mnt_context_mount (cxt ) != 0 )
127- exit_with_error ("Failed to mount\n" );
116+ errx (EXIT_FAILURE , "Failed to set target" );
117+
118+ // Attempt to mount
119+ int mount_exit_code = mnt_context_mount (cxt );
120+ if (mount_exit_code != 0 ) {
121+ char err_buf [BUFSIZ ] = {0 };
122+ mnt_context_get_excode (cxt , mount_exit_code , err_buf , sizeof (err_buf ));
123+ const char * tgt = mnt_context_get_target (cxt );
124+ if (* err_buf != '\0' && tgt != NULL )
125+ exit_with_error ("%s: %s\n" , tgt , err_buf );
126+ errx (EXIT_FAILURE , "Failed to mount" );
127+ }
128128
129129 if (setresuid (uid , uid , uid ) != 0 )
130- exit_with_error ( "setresuid failed\n " );
130+ errx ( EXIT_FAILURE , "setresuid failed" );
131131
132132 if (prctl (PR_SET_NO_NEW_PRIVS , 1 , 0 , 0 , 0 ) != 0 )
133- exit_with_error ( "PR_SET_NO_NEW_PRIVS failed\n " );
133+ err ( EXIT_FAILURE , "PR_SET_NO_NEW_PRIVS failed" );
134134
135135 return execvp (argv [0 ], argv );
136136}
0 commit comments