1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 /* 31 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 32 */ 33 34 /*LINTLIBRARY*/ 35 36 #include <stdio.h> 37 #include <ctype.h> 38 #include <string.h> 39 #include <limits.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include "valtools.h" 43 #include <stdlib.h> 44 #include <fcntl.h> 45 #include <unistd.h> 46 #include "libadm.h" 47 48 #define E_SYNTAX "does not meet suggested filename syntax standard" 49 #define E_READ "is not readable" 50 #define E_WRITE "is not writable" 51 #define E_EXEC "is not executable" 52 #define E_CREAT "cannot be created" 53 #define E_ABSOLUTE "must begin with a slash (/)" 54 #define E_RELATIVE "must not begin with a slash (/)" 55 #define E_EXIST "does not exist" 56 #define E_NEXIST "must not already exist" 57 #define E_BLK "must specify a block special device" 58 #define E_CHR "must specify a character special device" 59 #define E_DIR "must specify a directory" 60 #define E_REG "must be a regular file" 61 #define E_NONZERO "must be a file of non-zero length" 62 63 #define H_READ "must be readable" 64 #define H_WRITE "must be writable" 65 #define H_EXEC "must be executable" 66 #define H_CREAT "will be created if it does not exist" 67 #define H_ABSOLUTE E_ABSOLUTE 68 #define H_RELATIVE E_RELATIVE 69 #define H_EXIST "must already exist" 70 #define H_NEXIST "must not already exist" 71 #define H_BLK E_BLK 72 #define H_CHR E_CHR 73 #define H_DIR E_DIR 74 #define H_REG E_REG 75 #define H_NONZERO E_NONZERO 76 77 #define MSGSIZ 1024 78 #define STDHELP \ 79 "A pathname is a filename, optionally preceded by parent directories." 80 81 static char *errstr; 82 static char *badset = "*?[]{}()<> \t'`\"\\|^"; 83 84 static void 85 addhlp(char *msg, char *text) 86 { 87 static int count; 88 89 if (text == NULL) { 90 count = 0; 91 return; 92 } 93 if (!count++) 94 (void) strcat(msg, " The pathname you enter:"); 95 (void) strcat(msg, "\\n\\t-\\ "); 96 (void) strcat(msg, text); 97 } 98 99 static char * 100 sethlp(int pflags) 101 { 102 char *msg; 103 104 msg = calloc(MSGSIZ, sizeof (char)); 105 addhlp(msg, NULL); /* initialize count */ 106 (void) strcpy(msg, STDHELP); 107 108 if (pflags & P_EXIST) 109 addhlp(msg, H_EXIST); 110 else if (pflags & P_NEXIST) 111 addhlp(msg, H_NEXIST); 112 113 if (pflags & P_ABSOLUTE) 114 addhlp(msg, H_ABSOLUTE); 115 else if (pflags & P_RELATIVE) 116 addhlp(msg, H_RELATIVE); 117 118 if (pflags & P_READ) 119 addhlp(msg, H_READ); 120 if (pflags & P_WRITE) 121 addhlp(msg, H_WRITE); 122 if (pflags & P_EXEC) 123 addhlp(msg, H_EXEC); 124 if (pflags & P_CREAT) 125 addhlp(msg, H_CREAT); 126 127 if (pflags & P_BLK) 128 addhlp(msg, H_BLK); 129 else if (pflags & P_CHR) 130 addhlp(msg, H_CHR); 131 else if (pflags & P_DIR) 132 addhlp(msg, H_DIR); 133 else if (pflags & P_REG) 134 addhlp(msg, H_REG); 135 136 if (pflags & P_NONZERO) 137 addhlp(msg, H_NONZERO); 138 139 return (msg); 140 } 141 142 int 143 ckpath_stx(int pflags) 144 { 145 if (((pflags & P_ABSOLUTE) && (pflags & P_RELATIVE)) || 146 ((pflags & P_NEXIST) && (pflags & 147 (P_EXIST|P_NONZERO|P_READ|P_WRITE|P_EXEC))) || 148 ((pflags & P_CREAT) && (pflags & (P_EXIST|P_NEXIST|P_BLK|P_CHR))) || 149 ((pflags & P_BLK) && (pflags & (P_CHR|P_REG|P_DIR|P_NONZERO))) || 150 ((pflags & P_CHR) && (pflags & (P_REG|P_DIR|P_NONZERO))) || 151 ((pflags & P_DIR) && (pflags & P_REG))) { 152 return (1); 153 } 154 return (0); 155 } 156 157 int 158 ckpath_val(char *path, int pflags) 159 { 160 struct stat64 status; 161 int fd; 162 char *pt; 163 164 if ((pflags & P_RELATIVE) && (*path == '/')) { 165 errstr = E_RELATIVE; 166 return (1); 167 } 168 if ((pflags & P_ABSOLUTE) && (*path != '/')) { 169 errstr = E_ABSOLUTE; 170 return (1); 171 } 172 if (stat64(path, &status)) { 173 if (pflags & P_EXIST) { 174 errstr = E_EXIST; 175 return (1); 176 } 177 for (pt = path; *pt; pt++) { 178 if (!isprint((unsigned char)*pt) || 179 strchr(badset, *pt)) { 180 errstr = E_SYNTAX; 181 return (1); 182 } 183 } 184 if (pflags & P_CREAT) { 185 if (pflags & P_DIR) { 186 if ((mkdir(path, 0755)) != 0) { 187 errstr = E_CREAT; 188 return (1); 189 } 190 } else { 191 if ((fd = creat(path, 0644)) < 0) { 192 errstr = E_CREAT; 193 return (1); 194 } 195 (void) close(fd); 196 } 197 } 198 return (0); 199 } else if (pflags & P_NEXIST) { 200 errstr = E_NEXIST; 201 return (1); 202 } 203 if ((status.st_mode & S_IFMT) == S_IFREG) { 204 /* check non zero status */ 205 if ((pflags & P_NONZERO) && (status.st_size < 1)) { 206 errstr = E_NONZERO; 207 return (1); 208 } 209 } 210 if ((pflags & P_CHR) && ((status.st_mode & S_IFMT) != S_IFCHR)) { 211 errstr = E_CHR; 212 return (1); 213 } 214 if ((pflags & P_BLK) && ((status.st_mode & S_IFMT) != S_IFBLK)) { 215 errstr = E_BLK; 216 return (1); 217 } 218 if ((pflags & P_DIR) && ((status.st_mode & S_IFMT) != S_IFDIR)) { 219 errstr = E_DIR; 220 return (1); 221 } 222 if ((pflags & P_REG) && ((status.st_mode & S_IFMT) != S_IFREG)) { 223 errstr = E_REG; 224 return (1); 225 } 226 if ((pflags & P_READ) && !(status.st_mode & S_IREAD)) { 227 errstr = E_READ; 228 return (1); 229 } 230 if ((pflags & P_WRITE) && !(status.st_mode & S_IWRITE)) { 231 errstr = E_WRITE; 232 return (1); 233 } 234 if ((pflags & P_EXEC) && !(status.st_mode & S_IEXEC)) { 235 errstr = E_EXEC; 236 return (1); 237 } 238 return (0); 239 } 240 241 void 242 ckpath_err(int pflags, char *error, char *input) 243 { 244 char buffer[2048]; 245 char *defhlp; 246 247 if (input) { 248 if (ckpath_val(input, pflags)) { 249 (void) snprintf(buffer, sizeof (buffer), 250 "Pathname %s.", errstr); 251 puterror(stdout, buffer, error); 252 return; 253 } 254 } 255 defhlp = sethlp(pflags); 256 puterror(stdout, defhlp, error); 257 free(defhlp); 258 } 259 260 void 261 ckpath_hlp(int pflags, char *help) 262 { 263 char *defhlp; 264 265 defhlp = sethlp(pflags); 266 puthelp(stdout, defhlp, help); 267 free(defhlp); 268 } 269 270 int 271 ckpath(char *pathval, int pflags, char *defstr, char *error, char *help, 272 char *prompt) 273 { 274 char *defhlp, 275 input[MAX_INPUT], 276 buffer[256]; 277 278 if ((pathval == NULL) || ckpath_stx(pflags)) 279 return (2); /* usage error */ 280 281 if (!prompt) { 282 if (pflags & P_ABSOLUTE) 283 prompt = "Enter an absolute pathname"; 284 else if (pflags & P_RELATIVE) 285 prompt = "Enter a relative pathname"; 286 else 287 prompt = "Enter a pathname"; 288 } 289 defhlp = sethlp(pflags); 290 291 start: 292 putprmpt(stderr, prompt, NULL, defstr); 293 if (getinput(input)) { 294 free(defhlp); 295 return (1); 296 } 297 298 if (strlen(input) == 0) { 299 if (defstr) { 300 (void) strcpy(pathval, defstr); 301 free(defhlp); 302 return (0); 303 } 304 puterror(stderr, NULL, "Input is required."); 305 goto start; 306 } 307 if (strcmp(input, "?") == 0) { 308 puthelp(stderr, defhlp, help); 309 goto start; 310 } 311 if (ckquit && (strcmp(input, "q") == 0)) { 312 free(defhlp); 313 return (3); 314 } 315 316 if (ckpath_val(input, pflags)) { 317 (void) snprintf(buffer, sizeof (buffer), 318 "Pathname %s.", errstr); 319 puterror(stderr, buffer, error); 320 goto start; 321 } 322 (void) strcpy(pathval, input); 323 free(defhlp); 324 return (0); 325 } 326