diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/mkdir | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/mkdir')
| -rw-r--r-- | usr/src/cmd/mkdir/Makefile | 78 | ||||
| -rw-r--r-- | usr/src/cmd/mkdir/inc.flg | 25 | ||||
| -rw-r--r-- | usr/src/cmd/mkdir/mkdir.c | 413 |
3 files changed, 516 insertions, 0 deletions
diff --git a/usr/src/cmd/mkdir/Makefile b/usr/src/cmd/mkdir/Makefile new file mode 100644 index 0000000000..f78554c906 --- /dev/null +++ b/usr/src/cmd/mkdir/Makefile @@ -0,0 +1,78 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# cmd/mkdir/Makefile +# + +PROG= mkdir +OBJS= $(PROG).o common.o +SRCS= mkdir.c ../chmod/common.c + +include ../Makefile.cmd + +CFLAGS += $(CCVERBOSE) +LDLIBS += -lgen + +%.o: ../chmod/%.c + $(COMPILE.c) -o $@ $< + +# The following was derived from the default .c.po rule in the master +# makefile. It had to be adapted to avoid writing the intermediate (.i) +# file in ../chmod. + +%.po: ../chmod/%.c + $(COMPILE.cpp) $< > $*.c.i + $(XGETTEXT) $(XGETFLAGS) $*.c.i ;\ + $(RM) $@ ;\ + sed "/^domain/d" < messages.po > $@ ;\ + $(RM) messages.po $*.c.i + +POFILES= $(OBJS:%.o=%.po) +POFILE= $(PROG)_cmd.po + +LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2 + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +$(POFILE): $(POFILES) + $(RM) $@ + cat $(POFILES) > $@ + +install: all $(ROOTPROG) + +clean: + $(RM) $(OBJS) + +lint: lint_SRCS + +include ../Makefile.targ diff --git a/usr/src/cmd/mkdir/inc.flg b/usr/src/cmd/mkdir/inc.flg new file mode 100644 index 0000000000..ff8bb0e63d --- /dev/null +++ b/usr/src/cmd/mkdir/inc.flg @@ -0,0 +1,25 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +#ident "%Z%%M% %I% %E% SMI" + +echo_file usr/src/cmd/chmod/common.c diff --git a/usr/src/cmd/mkdir/mkdir.c b/usr/src/cmd/mkdir/mkdir.c new file mode 100644 index 0000000000..c636415493 --- /dev/null +++ b/usr/src/cmd/mkdir/mkdir.c @@ -0,0 +1,413 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ +/* */ + +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * make directory. + * If -m is used with a valid mode, directories will be + * created in that mode. Otherwise, the default mode will + * be 777 possibly altered by the process's file mode creation + * mask. + * If -p is used, make the directory as well as + * its non-existing parent directories. + */ + +#include <signal.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <locale.h> +#include <stdlib.h> +#include <unistd.h> +#include <libgen.h> +#include <stdarg.h> +#include <wchar.h> + +#define MSGEXISTS "\"%s\": Exists but is not a directory\n" +#define MSGUSAGE "usage: mkdir [-m mode] [-p] dirname ...\n" +#define MSGFMT1 "\"%s\": %s\n" +#define MSGFAILED "Failed to make directory \"%s\"; %s\n" + +extern int optind, errno; +extern char *optarg; + +static char +*simplify(char *path); + +void +errmsg(int severity, int code, char *format, ...); + +extern mode_t +newmode(char *ms, mode_t new_mode, mode_t umsk, char *file, char *path); + +#define ALLRWX (S_IRWXU | S_IRWXG | S_IRWXO) + + +void +main(int argc, char *argv[]) +{ + int pflag, errflg, mflag; + int c, local_errno, tmp_errno; + mode_t cur_umask; + mode_t mode; + mode_t modediff; + char *d; + struct stat buf; + + pflag = mflag = errflg = 0; + local_errno = 0; + + (void) setlocale(LC_ALL, ""); + +#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ +#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ +#endif + + (void) textdomain(TEXT_DOMAIN); + + cur_umask = umask(0); + + mode = ALLRWX; + + while ((c = getopt(argc, argv, "m:p")) != EOF) { + switch (c) { + case 'm': + mflag++; + mode = newmode(optarg, ALLRWX, cur_umask, "", ""); + break; + case 'p': + pflag++; + break; + case '?': + errflg++; + break; + } + } + + + /* + * When using default ACLs, mkdir() should be called with + * 0777 always; and umask or default ACL should do the work. + * Because of the POSIX.2 requirement that the + * intermediate mode be at least -wx------, + * we do some trickery here. + * + * If pflag is not set, we can just leave the umask as + * it the user specified it, unless it masks any of bits 0300. + */ + if (pflag) { + modediff = cur_umask & (S_IXUSR | S_IWUSR); + if (modediff) + cur_umask &= ~modediff; + } + (void) umask(cur_umask); + + argc -= optind; + if (argc < 1 || errflg) { + errmsg(0, 2, gettext(MSGUSAGE)); + } + argv = &argv[optind]; + + errno = 0; + while (argc--) { + if ((d = simplify(*argv++)) == NULL) { + exit(2); + } + + /* + * When -p is set, invokes mkdirp library routine. + * Although successfully invoked, mkdirp sets errno to ENOENT + * if one of the directory in the pathname does not exist, + * thus creates a confusion on success/failure status + * possibly checked by the calling routine or shell. + * Therefore, errno is reset only when + * mkdirp has executed successfully, otherwise save + * in local_errno. + */ + if (pflag) { + /* + * POSIX.2 says that it is not an error if + * the argument names an existing directory. + * We will, however, complain if the argument + * exists but is not a directory. + */ + if (lstat(d, &buf) != -1) { + if (S_ISDIR(buf.st_mode)) { + continue; + } else { + local_errno = EEXIST; + errmsg(0, 0, gettext(MSGEXISTS), d); + continue; + } + } + errno = 0; + + if (mkdirp(d, ALLRWX) < 0) { + tmp_errno = errno; + + if (tmp_errno == EEXIST) { + if (lstat(d, &buf) != -1) { + if (! S_ISDIR(buf.st_mode)) { + local_errno = + tmp_errno; + errmsg(0, 0, gettext( + MSGEXISTS), d); + continue; + } + /* S_ISDIR: do nothing */ + } else { + local_errno = tmp_errno; + perror("mkdir"); + errmsg(0, 0, + gettext(MSGFAILED), d, + strerror(local_errno)); + continue; + } + } else { + local_errno = tmp_errno; + errmsg(0, 0, gettext(MSGFMT1), d, + strerror(tmp_errno)); + continue; + } + } + + errno = 0; + + /* + * get the file mode for the newly + * created directory and test for + * set gid bit being inherited from the parent + * directory to include it with the file + * mode creation for the last directory + * on the dir path. + * + * This is only needed if mflag was specified + * or if the umask was adjusted with -wx----- + * + * If mflag is specified, we chmod to the specified + * mode, oring in the 02000 bit. + * + * If modediff is set, those bits need to be + * removed from the last directory component, + * all other bits are kept regardless of umask + * in case a default ACL is present. + */ + if (mflag || modediff) { + mode_t tmpmode; + + (void) lstat(d, &buf); + if (modediff && !mflag) + tmpmode = (buf.st_mode & 07777) + & ~modediff; + else + tmpmode = mode | (buf.st_mode & 02000); + + if (chmod(d, tmpmode) < 0) { + tmp_errno = errno; + local_errno = errno; + errmsg(0, 0, gettext(MSGFMT1), d, + strerror(tmp_errno)); + continue; + } + errno = 0; + } + + continue; + } else { + /* + * No -p. Make only one directory + */ + + errno = 0; + + if (mkdir(d, mode) < 0) { + local_errno = tmp_errno = errno; + errmsg(0, 0, gettext(MSGFAILED), d, + strerror(tmp_errno)); + continue; + } + if (mflag) { + mode_t tmpmode; + (void) lstat(d, &buf); + tmpmode = mode | (buf.st_mode & 02000); + + if (chmod(d, tmpmode) < 0) { + tmp_errno = errno; + local_errno = errno; + errmsg(0, 0, gettext(MSGFMT1), d, + strerror(tmp_errno)); + continue; + } + errno = 0; + } + } + } /* end while */ + + /* When pflag is set, the errno is saved in local_errno */ + + if (local_errno) + errno = local_errno; + exit(errno ? 2: 0); +} + +/* + * errmsg - This is an interface required by the code common to mkdir and + * chmod. The severity parameter is ignored here, but is meaningful + * to chmod. + */ + +/* ARGSUSED */ +/* PRINTFLIKE3 */ +void +errmsg(int severity, int code, char *format, ...) +{ + va_list ap; + va_start(ap, format); + + (void) fprintf(stderr, "mkdir: "); + (void) vfprintf(stderr, format, ap); + + va_end(ap); + + if (code > 0) { + exit(code); + } +} + +/* + * simplify - given a pathname in a writable buffer, simplify that + * path by removing meaningless occurances of path + * syntax. + * + * The change happens in place in the argument. The + * result is neceassarily no longer than the original. + * + * Return the pointer supplied by the caller on success, or + * NULL on error. + * + * The caller should handle error reporting based upon the + * returned vlaue. + */ + +static char * +simplify(char *mbPath) +{ + int i; + size_t mbPathlen; /* length of multi-byte path */ + size_t wcPathlen; /* length of wide-character path */ + wchar_t *wptr; /* scratch pointer */ + wchar_t *wcPath; /* wide-character version of the path */ + + /* + * bail out if there is nothing there. + */ + + if (!mbPath) + return (mbPath); + + /* + * convert the multi-byte version of the path to a + * wide-character rendering, for doing our figuring. + */ + + mbPathlen = strlen(mbPath); + + if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) { + perror("mkdir"); + exit(2); + } + + if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) { + free(wcPath); + return (NULL); + } + + /* + * remove duplicate slashes first ("//../" -> "/") + */ + + for (wptr = wcPath, i = 0; i < wcPathlen; i++) { + *wptr++ = wcPath[i]; + + if (wcPath[i] == '/') { + i++; + + while (wcPath[i] == '/') { + i++; + } + + i--; + } + } + + *wptr = '\0'; + + /* + * next skip initial occurances of "./" + */ + + for (wcPathlen = wcslen(wcPath), wptr = wcPath, i = 0; + i < wcPathlen-2 && wcPath[i] == '.' && wcPath[i+1] == '/'; + i += 2) { + /* empty body */ + } + + /* + * now make reductions of various forms. + */ + + while (i < wcPathlen) { + if (i < wcPathlen-2 && wcPath[i] == '/' && + wcPath[i+1] == '.' && wcPath[i+2] == '/') { + /* "/./" -> "/" */ + i += 2; + } else { + /* Normal case: copy the character */ + *wptr++ = wcPath[i++]; + } + } + + *wptr = '\0'; + + /* + * now convert back to the multi-byte format. + */ + + if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) { + free(wcPath); + return (NULL); + } + + free(wcPath); + return (mbPath); +} |
