14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1992-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin * David Korn
244887Schin * AT&T Bell Laboratories
254887Schin *
264887Schin * mkdir
274887Schin */
284887Schin
294887Schin static const char usage[] =
30*12068SRoger.Faulkner@Oracle.COM "[-?\n@(#)$Id: mkdir (AT&T Research) 2009-12-03 $\n]"
314887Schin USAGE_LICENSE
324887Schin "[+NAME?mkdir - make directories]"
334887Schin "[+DESCRIPTION?\bmkdir\b creates one or more directories. By "
344887Schin "default, the mode of created directories is \ba=rwx\b minus the "
354887Schin "bits set in the \bumask\b(1).]"
364887Schin "[m:mode]:[mode?Set the mode of created directories to \amode\a. "
374887Schin "\amode\a is symbolic or octal mode as in \bchmod\b(1). Relative "
384887Schin "modes assume an initial mode of \ba=rwx\b.]"
394887Schin "[p:parents?Create any missing intermediate pathname components. For "
404887Schin "each dir operand that does not name an existing directory, effects "
414887Schin "equivalent to those caused by the following command shall occur: "
424887Schin "\vmkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]] "
434887Schin "dir\v where the \b-m\b mode option represents that option supplied to "
444887Schin "the original invocation of \bmkdir\b, if any. Each dir operand that "
454887Schin "names an existing directory shall be ignored without error.]"
46*12068SRoger.Faulkner@Oracle.COM "[v:verbose?Print a message on the standard error for each created "
47*12068SRoger.Faulkner@Oracle.COM "directory.]"
484887Schin "\n"
494887Schin "\ndirectory ...\n"
504887Schin "\n"
514887Schin "[+EXIT STATUS?]{"
524887Schin "[+0?All directories created successfully, or the \b-p\b option "
534887Schin "was specified and all the specified directories now exist.]"
544887Schin "[+>0?An error occurred.]"
554887Schin "}"
564887Schin "[+SEE ALSO?\bchmod\b(1), \brmdir\b(1), \bumask\b(1)]"
574887Schin ;
584887Schin
594887Schin #include <cmd.h>
604887Schin #include <ls.h>
614887Schin
624887Schin #define DIRMODE (S_IRWXU|S_IRWXG|S_IRWXO)
634887Schin
644887Schin int
b_mkdir(int argc,char ** argv,void * context)654887Schin b_mkdir(int argc, char** argv, void* context)
664887Schin {
674887Schin register char* arg;
684887Schin register int n;
694887Schin register mode_t mode = DIRMODE;
704887Schin register mode_t mask = 0;
714887Schin register int mflag = 0;
724887Schin register int pflag = 0;
73*12068SRoger.Faulkner@Oracle.COM register int vflag = 0;
744887Schin char* name;
754887Schin mode_t dmode;
768462SApril.Chin@Sun.COM struct stat st;
774887Schin
784887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0);
7910898Sroland.mainz@nrubsig.org for (;;)
804887Schin {
8110898Sroland.mainz@nrubsig.org switch (optget(argv, usage))
8210898Sroland.mainz@nrubsig.org {
8310898Sroland.mainz@nrubsig.org case 0:
8410898Sroland.mainz@nrubsig.org break;
8510898Sroland.mainz@nrubsig.org case 'm':
8610898Sroland.mainz@nrubsig.org mflag = 1;
8710898Sroland.mainz@nrubsig.org mode = strperm(arg = opt_info.arg, &opt_info.arg, mode);
8810898Sroland.mainz@nrubsig.org if (*opt_info.arg)
8910898Sroland.mainz@nrubsig.org error(ERROR_exit(0), "%s: invalid mode", arg);
9010898Sroland.mainz@nrubsig.org continue;
91*12068SRoger.Faulkner@Oracle.COM case 'p':
92*12068SRoger.Faulkner@Oracle.COM pflag = 1;
93*12068SRoger.Faulkner@Oracle.COM continue;
94*12068SRoger.Faulkner@Oracle.COM case 'v':
95*12068SRoger.Faulkner@Oracle.COM vflag = 1;
96*12068SRoger.Faulkner@Oracle.COM continue;
9710898Sroland.mainz@nrubsig.org case ':':
9810898Sroland.mainz@nrubsig.org error(2, "%s", opt_info.arg);
9910898Sroland.mainz@nrubsig.org continue;
10010898Sroland.mainz@nrubsig.org case '?':
10110898Sroland.mainz@nrubsig.org error(ERROR_usage(2), "%s", opt_info.arg);
10210898Sroland.mainz@nrubsig.org continue;
10310898Sroland.mainz@nrubsig.org }
1044887Schin break;
1054887Schin }
1064887Schin argv += opt_info.index;
1074887Schin if (error_info.errors || !*argv)
1084887Schin error(ERROR_usage(2), "%s", optusage(NiL));
1094887Schin mask = umask(0);
1104887Schin if (mflag || pflag)
1114887Schin {
1124887Schin dmode = DIRMODE & ~mask;
1134887Schin if (!mflag)
1144887Schin mode = dmode;
1154887Schin dmode |= S_IWUSR | S_IXUSR;
1164887Schin }
1174887Schin else
1184887Schin {
1194887Schin mode &= ~mask;
1204887Schin umask(mask);
1214887Schin mask = 0;
1224887Schin }
1234887Schin while (arg = *argv++)
1244887Schin {
1254887Schin if (mkdir(arg, mode) < 0)
1264887Schin {
1274887Schin if (!pflag || !(errno == ENOENT || errno == EEXIST || errno == ENOTDIR))
1284887Schin {
1294887Schin error(ERROR_system(0), "%s:", arg);
1304887Schin continue;
1314887Schin }
1324887Schin if (errno == EEXIST)
1334887Schin continue;
1344887Schin
1354887Schin /*
1364887Schin * -p option, preserve intermediates
1374887Schin * first eliminate trailing /'s
1384887Schin */
1394887Schin
1404887Schin n = strlen(arg);
1414887Schin while (n > 0 && arg[--n] == '/');
1424887Schin arg[n + 1] = 0;
1434887Schin for (name = arg, n = *arg; n;)
1444887Schin {
1454887Schin /* skip over slashes */
1464887Schin while (*arg == '/')
1474887Schin arg++;
1484887Schin /* skip to next component */
1494887Schin while ((n = *arg) && n != '/')
1504887Schin arg++;
1514887Schin *arg = 0;
1524887Schin if (mkdir(name, n ? dmode : mode) < 0 && errno != EEXIST && access(name, F_OK) < 0)
1534887Schin {
1544887Schin *arg = n;
1554887Schin error(ERROR_system(0), "%s:", name);
1564887Schin break;
1574887Schin }
158*12068SRoger.Faulkner@Oracle.COM if (vflag)
159*12068SRoger.Faulkner@Oracle.COM error(0, "%s: directory created", name);
1608462SApril.Chin@Sun.COM if (!(*arg = n) && (mode & (S_ISVTX|S_ISUID|S_ISGID)))
1618462SApril.Chin@Sun.COM {
1628462SApril.Chin@Sun.COM if (stat(name, &st))
1638462SApril.Chin@Sun.COM {
1648462SApril.Chin@Sun.COM error(ERROR_system(0), "%s: cannot stat", name);
1658462SApril.Chin@Sun.COM break;
1668462SApril.Chin@Sun.COM }
1678462SApril.Chin@Sun.COM if ((st.st_mode & (S_ISVTX|S_ISUID|S_ISGID)) != (mode & (S_ISVTX|S_ISUID|S_ISGID)) && chmod(name, mode))
1688462SApril.Chin@Sun.COM {
1698462SApril.Chin@Sun.COM error(ERROR_system(0), "%s: cannot change mode from %s to %s", name, fmtperm(st.st_mode & (S_ISVTX|S_ISUID|S_ISGID)), fmtperm(mode));
1708462SApril.Chin@Sun.COM break;
1718462SApril.Chin@Sun.COM }
1728462SApril.Chin@Sun.COM }
1734887Schin }
1744887Schin }
175*12068SRoger.Faulkner@Oracle.COM else if (vflag)
176*12068SRoger.Faulkner@Oracle.COM error(0, "%s: directory created", arg);
1774887Schin }
1784887Schin if (mask)
1794887Schin umask(mask);
1804887Schin return error_info.errors != 0;
1814887Schin }
182