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
addhlp(char * msg,char * text)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 *
sethlp(int pflags)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
ckpath_stx(int pflags)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
ckpath_val(char * path,int pflags)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
ckpath_err(int pflags,char * error,char * input)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
ckpath_hlp(int pflags,char * help)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
ckpath(char * pathval,int pflags,char * defstr,char * error,char * help,char * prompt)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