Index: usr.bin/xinstall/install.1 =================================================================== --- usr.bin/xinstall/install.1 +++ usr.bin/xinstall/install.1 @@ -36,7 +36,7 @@ .Nd install binaries .Sh SYNOPSIS .Nm -.Op Fl bCcpSsUv +.Op Fl bCcFpSsUv .Op Fl B Ar suffix .Op Fl D Ar destdir .Op Fl f Ar flags @@ -50,7 +50,7 @@ .Op Fl T Ar tags .Ar file1 file2 .Nm -.Op Fl bCcpSsUv +.Op Fl bCcpPSsUv .Op Fl B Ar suffix .Op Fl D Ar destdir .Op Fl f Ar flags @@ -138,6 +138,13 @@ .It Fl d Create directories. Missing parent directories are created as required. +.It Fl F +Create parent directories of +.Ar file2 +as needed. +This is the same as +.Fl P +except it only accepts two file arguments. .It Fl f Specify the target's file flags; see .Xr chflags 1 @@ -231,6 +238,8 @@ (compare and copy) option is specified, except if the target file does not already exist or is different, then preserve the access and modification times of the source file. +.It Fl P +Create target directory as needed. .It Fl S Safe copy. Normally, Index: usr.bin/xinstall/tests/install_test.sh =================================================================== --- usr.bin/xinstall/tests/install_test.sh +++ usr.bin/xinstall/tests/install_test.sh @@ -377,6 +377,18 @@ atf_check install -d dir1/dir2/dir3 } +atf_test_case mkdir_p_auto +mkdir_p_auto_body() { + atf_check touch foo + atf_check install -P foo dir1 + [ -d dir1 ] || atf_fail "dir1 missing" + [ -f dir1/foo ] || atf_fail "dir1/foo missing" + + atf_check install -F foo dir2/bar + [ -d dir2 ] || atf_fail "dir2 missing" + [ -f dir2/bar ] || atf_fail "dir2/bar missing" +} + atf_init_test_cases() { atf_add_test_case copy_to_nonexistent atf_add_test_case copy_to_nonexistent_safe @@ -416,4 +428,5 @@ atf_add_test_case symbolic_link_relative_absolute_source_and_dest1_double_slash atf_add_test_case symbolic_link_relative_absolute_source_and_dest2 atf_add_test_case mkdir_simple + atf_add_test_case mkdir_p_auto } Index: usr.bin/xinstall/xinstall.c =================================================================== --- usr.bin/xinstall/xinstall.c +++ usr.bin/xinstall/xinstall.c @@ -110,7 +110,7 @@ static gid_t gid; static uid_t uid; static int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, - safecopy, verbose; + files_only, mkdir_p, safecopy, verbose; static int haveopt_f, haveopt_g, haveopt_m, haveopt_o; static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; static FILE *metafp; @@ -150,11 +150,12 @@ u_int iflags; char *p; const char *to_name; + char buf[MAXPATHLEN]; fset = 0; iflags = 0; group = owner = NULL; - while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != + while ((ch = getopt(argc, argv, "B:bCcD:dFf:g:h:l:M:m:N:o:pPSsT:Uv")) != -1) switch((char)ch) { case 'B': @@ -175,6 +176,10 @@ case 'd': dodir = 1; break; + case 'F': + mkdir_p = 1; + files_only = 1; + break; case 'f': haveopt_f = 1; fflags = optarg; @@ -234,6 +239,9 @@ haveopt_o = 1; owner = optarg; break; + case 'P': + mkdir_p = 1; + break; case 'p': docompare = dopreserve = 1; break; @@ -339,6 +347,23 @@ to_name = argv[argc - 1]; no_target = stat(to_name, &to_sb); + if (mkdir_p) { + if (no_target) { + strncpy(buf, to_name, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + /* Handle file1 file2 case. */ + if (argc == 2 && files_only) { + dirname(buf); + if (stat(buf, &to_sb)) + install_dir(buf); + strncpy(buf, to_name, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + } else { + install_dir(buf); + no_target = stat(buf, &to_sb); + } + } + } if (!no_target && S_ISDIR(to_sb.st_mode)) { if (dolink & LN_SYMBOLIC) { if (lstat(to_name, &to_sb) != 0) @@ -1441,11 +1466,11 @@ usage(void) { (void)fprintf(stderr, -"usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" +"usage: install [-bCcFpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" " [-M log] [-D dest] [-h hash] [-T tags]\n" " [-B suffix] [-l linkflags] [-N dbdir]\n" " file1 file2\n" -" install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" +" install [-bCcpPSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" " [-M log] [-D dest] [-h hash] [-T tags]\n" " [-B suffix] [-l linkflags] [-N dbdir]\n" " file1 ... fileN directory\n"