194 lines
4.8 KiB
C
194 lines
4.8 KiB
C
/*
|
|
*----------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <jeang3nie@HitchHiker-Linux.org> wrote this file. As long as you
|
|
* retain this notice you can do whatever you want with this stuff. If
|
|
* we meet some day, and you think this stuff is worth it, you can buy
|
|
* me a beer in return.
|
|
* ---------------------------------------------------------------------
|
|
* ______ _______ _ _________
|
|
* ( __ \ ( ___ )( ( /|( )\__ __/
|
|
* | ( \ )| ( ) || \ ( ||/ ) (
|
|
* | | ) || | | || \ | | | |
|
|
* | | | || | | || (\ \) | | |
|
|
* | | ) || | | || | \ | | |
|
|
* | (__/ )| (___) || ) \ | | |
|
|
* (______/ (_______)|/ )_) )_(
|
|
*
|
|
* _______ _______ _ _________ _______
|
|
* ( ____ )( ___ )( \ /|\__ __/( ____ \
|
|
* | ( )|| ( ) || \ ( | ) ( | ( |/
|
|
* | (____)|| (___) || \ | | | | | |
|
|
* | _____)| ___ || (\ \) | | | | |
|
|
* | ( | ( ) || | \ | | | | |
|
|
* | ) | ) ( || ) \ |___) (___| (____|\
|
|
* |/ |/ \||/ \_)\_______/(_______/
|
|
*
|
|
*/
|
|
|
|
#define _XOPEN_SOURCE
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <inttypes.h>
|
|
#include <libgen.h>
|
|
#include <linux/limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <bsd/unistd.h>
|
|
|
|
static const char *__progname;
|
|
uint8_t pflag = 0, vflag = 0;
|
|
mode_t mode, _mode, mask;
|
|
|
|
static void usage() {
|
|
fprintf(stderr, "usage: %s [-hp] [-m mode] dir1 ... dir2 ...\n", __progname);
|
|
}
|
|
|
|
int isoctalmode(char *_mode) {
|
|
int length = strlen(_mode);
|
|
if (length > 5) {
|
|
return 1;
|
|
}
|
|
int i;
|
|
for (i = 0; i < length; i++) {
|
|
if (isdigit(_mode[i]) == 0) {
|
|
return 1;
|
|
}
|
|
int j = _mode[i] - '0';
|
|
if (j > 7) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _mkdir(char *_path) {
|
|
if (mkdir(_path, 0755) == -1) {
|
|
perror("mkdir");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (vflag)
|
|
fprintf(stderr, "%s: created directory '%s'\n", __progname, _path);
|
|
return 0;
|
|
}
|
|
|
|
/* checks to see if the argument exists, and if it is a directory,
|
|
* before attempting to create it */
|
|
int _mkdir_ifnoexist(char *_path) {
|
|
struct stat sb;
|
|
if (stat(_path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
|
/* just return 0 if directory exists */
|
|
return 0;
|
|
} else {
|
|
/* create all intermediate dirs 0755 */
|
|
if (_mkdir(_path) == 0)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* parses the path we gave with '-p' and calls _mkdir_ifnoexist */
|
|
int _mkdir_p(char *_path) {
|
|
char slash[PATH_MAX] = "/";
|
|
char *d = strtok(_path, "/");
|
|
/* if our path starts with '/', we have to prepend it here, as strtok
|
|
* removes it from 'd'; else just copy the data */
|
|
if (strncmp(_path, "/", 1) == 0) {
|
|
strcat(slash, d);
|
|
} else {
|
|
strcpy(slash, d);
|
|
}
|
|
_mkdir_ifnoexist(slash);
|
|
while (1 < 2) {
|
|
d = strtok(NULL, "/");
|
|
if (d == NULL) { // final destination reached
|
|
/* mkdir doesn't handle sticky bits, so call chmod on our final
|
|
* destination in case the user wanted a certain mode set */
|
|
if (chmod(slash, mode) == -1) {
|
|
perror("chmod");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
}
|
|
strcat(slash, "/");
|
|
strcat(slash, d);
|
|
_mkdir_ifnoexist(slash);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
unsigned int index;
|
|
int c;
|
|
char *marg = NULL;
|
|
char *end;
|
|
void *set = NULL;
|
|
umask(mask = umask(0));
|
|
_mode = 0777 & ~mask;
|
|
__progname = basename(argv[0]);
|
|
|
|
while ((c = getopt(argc, argv, "hpvm:")) != -1)
|
|
switch (c) {
|
|
case 'h':
|
|
usage();
|
|
exit(EXIT_SUCCESS);
|
|
case 'm':
|
|
marg = optarg;
|
|
break;
|
|
case 'p':
|
|
pflag = 1;
|
|
break;
|
|
case 'v':
|
|
vflag = 1;
|
|
break;
|
|
case '?':
|
|
if (isprint(optopt)) {
|
|
usage();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
/* no arguments supplied */
|
|
if (argv[optind] == NULL) {
|
|
fprintf(stderr, "Mandatory argument(s) missing\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* check for a valid octal mode */
|
|
if (marg) {
|
|
if (isoctalmode(marg) == 0) {
|
|
mode = strtol(marg, &end, 8);
|
|
} else if ((set = setmode(marg)) != NULL) {
|
|
mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
free(set);
|
|
} else {
|
|
errx(1, "invalid file mode: %s", marg);
|
|
}
|
|
} else {
|
|
mode = _mode;
|
|
}
|
|
|
|
for (index = optind; index < argc; index++) {
|
|
if (pflag) {
|
|
_mkdir_p(argv[index]);
|
|
} else {
|
|
_mkdir(argv[index]);
|
|
/* mkdir doesn't do sticky bits even if asked to, so call chmod
|
|
* to make sure we set the exact permissions asked for */
|
|
if (chmod(argv[index], mode) == -1) {
|
|
perror("chmod");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|