/*
* 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 (c) 1996-1998, 2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
/*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
*/
/*LINTLIBRARY*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "valtools.h"
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "libadm.h"
#define E_SYNTAX "does not meet suggested filename syntax standard"
#define E_READ "is not readable"
#define E_WRITE "is not writable"
#define E_EXEC "is not executable"
#define E_CREAT "cannot be created"
#define E_ABSOLUTE "must begin with a slash (/)"
#define E_RELATIVE "must not begin with a slash (/)"
#define E_EXIST "does not exist"
#define E_NEXIST "must not already exist"
#define E_BLK "must specify a block special device"
#define E_CHR "must specify a character special device"
#define E_DIR "must specify a directory"
#define E_REG "must be a regular file"
#define E_NONZERO "must be a file of non-zero length"
#define H_READ "must be readable"
#define H_WRITE "must be writable"
#define H_EXEC "must be executable"
#define H_CREAT "will be created if it does not exist"
#define H_ABSOLUTE E_ABSOLUTE
#define H_RELATIVE E_RELATIVE
#define H_EXIST "must already exist"
#define H_NEXIST "must not already exist"
#define H_BLK E_BLK
#define H_CHR E_CHR
#define H_DIR E_DIR
#define H_REG E_REG
#define H_NONZERO E_NONZERO
#define MSGSIZ 1024
#define STDHELP \
"A pathname is a filename, optionally preceded by parent directories."
static char *errstr;
static char *badset = "*?[]{}()<> \t'`\"\\|^";
static void
addhlp(char *msg, char *text)
{
static int count;
if (text == NULL) {
count = 0;
return;
}
if (!count++)
(void) strcat(msg, " The pathname you enter:");
(void) strcat(msg, "\\n\\t-\\ ");
(void) strcat(msg, text);
}
static char *
sethlp(int pflags)
{
char *msg;
msg = calloc(MSGSIZ, sizeof (char));
addhlp(msg, NULL); /* initialize count */
(void) strcpy(msg, STDHELP);
if (pflags & P_EXIST)
addhlp(msg, H_EXIST);
else if (pflags & P_NEXIST)
addhlp(msg, H_NEXIST);
if (pflags & P_ABSOLUTE)
addhlp(msg, H_ABSOLUTE);
else if (pflags & P_RELATIVE)
addhlp(msg, H_RELATIVE);
if (pflags & P_READ)
addhlp(msg, H_READ);
if (pflags & P_WRITE)
addhlp(msg, H_WRITE);
if (pflags & P_EXEC)
addhlp(msg, H_EXEC);
if (pflags & P_CREAT)
addhlp(msg, H_CREAT);
if (pflags & P_BLK)
addhlp(msg, H_BLK);
else if (pflags & P_CHR)
addhlp(msg, H_CHR);
else if (pflags & P_DIR)
addhlp(msg, H_DIR);
else if (pflags & P_REG)
addhlp(msg, H_REG);
if (pflags & P_NONZERO)
addhlp(msg, H_NONZERO);
return (msg);
}
int
ckpath_stx(int pflags)
{
if (((pflags & P_ABSOLUTE) && (pflags & P_RELATIVE)) ||
((pflags & P_NEXIST) && (pflags &
(P_EXIST|P_NONZERO|P_READ|P_WRITE|P_EXEC))) ||
((pflags & P_CREAT) && (pflags & (P_EXIST|P_NEXIST|P_BLK|P_CHR))) ||
((pflags & P_BLK) && (pflags & (P_CHR|P_REG|P_DIR|P_NONZERO))) ||
((pflags & P_CHR) && (pflags & (P_REG|P_DIR|P_NONZERO))) ||
((pflags & P_DIR) && (pflags & P_REG))) {
return (1);
}
return (0);
}
int
ckpath_val(char *path, int pflags)
{
struct stat64 status;
int fd;
char *pt;
if ((pflags & P_RELATIVE) && (*path == '/')) {
errstr = E_RELATIVE;
return (1);
}
if ((pflags & P_ABSOLUTE) && (*path != '/')) {
errstr = E_ABSOLUTE;
return (1);
}
if (stat64(path, &status)) {
if (pflags & P_EXIST) {
errstr = E_EXIST;
return (1);
}
for (pt = path; *pt; pt++) {
if (!isprint((unsigned char)*pt) ||
strchr(badset, *pt)) {
errstr = E_SYNTAX;
return (1);
}
}
if (pflags & P_CREAT) {
if (pflags & P_DIR) {
if ((mkdir(path, 0755)) != 0) {
errstr = E_CREAT;
return (1);
}
} else {
if ((fd = creat(path, 0644)) < 0) {
errstr = E_CREAT;
return (1);
}
(void) close(fd);
}
}
return (0);
} else if (pflags & P_NEXIST) {
errstr = E_NEXIST;
return (1);
}
if ((status.st_mode & S_IFMT) == S_IFREG) {
/* check non zero status */
if ((pflags & P_NONZERO) && (status.st_size < 1)) {
errstr = E_NONZERO;
return (1);
}
}
if ((pflags & P_CHR) && ((status.st_mode & S_IFMT) != S_IFCHR)) {
errstr = E_CHR;
return (1);
}
if ((pflags & P_BLK) && ((status.st_mode & S_IFMT) != S_IFBLK)) {
errstr = E_BLK;
return (1);
}
if ((pflags & P_DIR) && ((status.st_mode & S_IFMT) != S_IFDIR)) {
errstr = E_DIR;
return (1);
}
if ((pflags & P_REG) && ((status.st_mode & S_IFMT) != S_IFREG)) {
errstr = E_REG;
return (1);
}
if ((pflags & P_READ) && !(status.st_mode & S_IREAD)) {
errstr = E_READ;
return (1);
}
if ((pflags & P_WRITE) && !(status.st_mode & S_IWRITE)) {
errstr = E_WRITE;
return (1);
}
if ((pflags & P_EXEC) && !(status.st_mode & S_IEXEC)) {
errstr = E_EXEC;
return (1);
}
return (0);
}
void
ckpath_err(int pflags, char *error, char *input)
{
char buffer[2048];
char *defhlp;
if (input) {
if (ckpath_val(input, pflags)) {
(void) snprintf(buffer, sizeof (buffer),
"Pathname %s.", errstr);
puterror(stdout, buffer, error);
return;
}
}
defhlp = sethlp(pflags);
puterror(stdout, defhlp, error);
free(defhlp);
}
void
ckpath_hlp(int pflags, char *help)
{
char *defhlp;
defhlp = sethlp(pflags);
puthelp(stdout, defhlp, help);
free(defhlp);
}
int
ckpath(char *pathval, int pflags, char *defstr, char *error, char *help,
char *prompt)
{
char *defhlp,
input[MAX_INPUT],
buffer[256];
if ((pathval == NULL) || ckpath_stx(pflags))
return (2); /* usage error */
if (!prompt) {
if (pflags & P_ABSOLUTE)
prompt = "Enter an absolute pathname";
else if (pflags & P_RELATIVE)
prompt = "Enter a relative pathname";
else
prompt = "Enter a pathname";
}
defhlp = sethlp(pflags);
start:
putprmpt(stderr, prompt, NULL, defstr);
if (getinput(input)) {
free(defhlp);
return (1);
}
if (strlen(input) == 0) {
if (defstr) {
(void) strcpy(pathval, defstr);
free(defhlp);
return (0);
}
puterror(stderr, NULL, "Input is required.");
goto start;
}
if (strcmp(input, "?") == 0) {
puthelp(stderr, defhlp, help);
goto start;
}
if (ckquit && (strcmp(input, "q") == 0)) {
free(defhlp);
return (3);
}
if (ckpath_val(input, pflags)) {
(void) snprintf(buffer, sizeof (buffer),
"Pathname %s.", errstr);
puterror(stderr, buffer, error);
goto start;
}
(void) strcpy(pathval, input);
free(defhlp);
return (0);
}