1 /* $NetBSD: file.c,v 1.8 2020/05/25 20:47:34 christos Exp $ */ 2 3 4 /** 5 * \file file.c 6 * 7 * Handle options that have file names for arguments. 8 * 9 * @addtogroup autoopts 10 * @{ 11 */ 12 /* 13 * This file is part of AutoOpts, a companion to AutoGen. 14 * AutoOpts is free software. 15 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 16 * 17 * AutoOpts is available under any one of two licenses. The license 18 * in use must be one of these two and the choice is under the control 19 * of the user of the license. 20 * 21 * The GNU Lesser General Public License, version 3 or later 22 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23 * 24 * The Modified Berkeley Software Distribution License 25 * See the file "COPYING.mbsd" 26 * 27 * These files have the following sha256 sums: 28 * 29 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 30 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 31 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 32 */ 33 34 /** 35 * Make sure the directory containing the subject file exists and that 36 * the file exists or does not exist, per the option requirements. 37 * 38 * @param ftype file existence type flags 39 * @param pOpts program option descriptor 40 * @param pOD the option descriptor 41 */ 42 static void 43 check_existence(teOptFileType ftype, tOptions * pOpts, tOptDesc * pOD) 44 { 45 char const * fname = pOD->optArg.argString; 46 struct stat sb; 47 48 errno = 0; 49 50 switch (ftype & FTYPE_MODE_EXIST_MASK) { 51 case FTYPE_MODE_MUST_NOT_EXIST: 52 if ((stat(fname, &sb) == 0) || (errno != ENOENT)) { 53 if (errno == 0) 54 errno = EINVAL; 55 fserr_exit(pOpts->pzProgName, "stat", fname); 56 /* NOTREACHED */ 57 } 58 /* FALLTHROUGH */ 59 60 default: 61 case FTYPE_MODE_MAY_EXIST: 62 { 63 char * p = strrchr(fname, DIRCH); 64 size_t l; 65 66 if (p == NULL) 67 /* 68 * The file may or may not exist and its directory is ".". 69 * Assume that "." exists. 70 */ 71 break; 72 73 l = (size_t)(p - fname); 74 p = AGALOC(l + 1, "fname"); 75 memcpy(p, fname, l); 76 p[l] = NUL; 77 78 if ((stat(p, &sb) != 0) || (errno = EINVAL, ! S_ISDIR(sb.st_mode))) 79 fserr_exit(pOpts->pzProgName, "stat", p); 80 /* NOTREACHED */ 81 82 AGFREE(p); 83 break; 84 } 85 86 case FTYPE_MODE_MUST_EXIST: 87 if ( (stat(fname, &sb) != 0) 88 || (errno = EINVAL, ! S_ISREG(sb.st_mode)) ) 89 fserr_exit(pOpts->pzProgName, "stat", fname); 90 /* NOTREACHED */ 91 92 break; 93 } 94 } 95 96 /** 97 * Open the specified file with open(2) and save the FD. 98 * 99 * @param pOpts program option descriptor 100 * @param pOD the option descriptor 101 * @param mode the open mode (uses int flags value) 102 */ 103 static void 104 open_file_fd(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode) 105 { 106 int fd = open(pOD->optArg.argString, mode.file_flags); 107 if (fd < 0) 108 fserr_exit(pOpts->pzProgName, "open", pOD->optArg.argString); 109 /* NOTREACHED */ 110 111 if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0) 112 pOD->optCookie = VOIDP(pOD->optArg.argString); 113 else 114 AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name"); 115 116 pOD->optArg.argFd = fd; 117 pOD->fOptState &= ~OPTST_ALLOC_ARG; 118 } 119 120 /** 121 * Open the specified file with open(2) and save the FD. 122 * 123 * @param pOpts program option descriptor 124 * @param pOD the option descriptor 125 * @param mode the open mode (uses "char *" mode value) 126 */ 127 static void 128 fopen_file_fp(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode) 129 { 130 FILE * fp = fopen(pOD->optArg.argString, mode.file_mode); 131 if (fp == NULL) 132 fserr_exit(pOpts->pzProgName, "fopen", pOD->optArg.argString); 133 /* NOTREACHED */ 134 135 if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0) 136 pOD->optCookie = VOIDP(pOD->optArg.argString); 137 else 138 AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name"); 139 140 pOD->optArg.argFp = fp; 141 pOD->fOptState &= ~OPTST_ALLOC_ARG; 142 } 143 144 /*=export_func optionFileCheck 145 * private: 146 * 147 * what: Decipher a boolean value 148 * arg: + tOptions * + pOpts + program options descriptor + 149 * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + 150 * arg: + teOptFileType + ftype + File handling type + 151 * arg: + tuFileMode + mode + file open mode (if needed) + 152 * 153 * doc: 154 * Make sure the named file conforms with the file type mode. 155 * The mode specifies if the file must exist, must not exist or may 156 * (or may not) exist. The mode may also specify opening the 157 * file: don't, open just the descriptor (fd), or open as a stream 158 * (FILE * pointer). 159 =*/ 160 void 161 optionFileCheck(tOptions * pOpts, tOptDesc * pOD, 162 teOptFileType ftype, tuFileMode mode) 163 { 164 if (pOpts <= OPTPROC_EMIT_LIMIT) { 165 if (pOpts != OPTPROC_EMIT_USAGE) 166 return; 167 168 switch (ftype & FTYPE_MODE_EXIST_MASK) { 169 case FTYPE_MODE_MUST_NOT_EXIST: 170 fputs(zFileCannotExist + tab_skip_ct, option_usage_fp); 171 break; 172 173 case FTYPE_MODE_MUST_EXIST: 174 fputs(zFileMustExist + tab_skip_ct, option_usage_fp); 175 break; 176 } 177 return; 178 } 179 180 if ((pOD->fOptState & OPTST_RESET) != 0) { 181 if (pOD->optCookie != NULL) 182 AGFREE(pOD->optCookie); 183 return; 184 } 185 186 check_existence(ftype, pOpts, pOD); 187 188 switch (ftype & FTYPE_MODE_OPEN_MASK) { 189 default: 190 case FTYPE_MODE_NO_OPEN: break; 191 case FTYPE_MODE_OPEN_FD: open_file_fd( pOpts, pOD, mode); break; 192 case FTYPE_MODE_FOPEN_FP: fopen_file_fp(pOpts, pOD, mode); break; 193 } 194 } 195 196 /** @} 197 * 198 * Local Variables: 199 * mode: C 200 * c-file-style: "stroustrup" 201 * indent-tabs-mode: nil 202 * End: 203 * end of autoopts/file.c */ 204