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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <libintl.h> 25 #include <locale.h> 26 #include <errno.h> 27 #include <string.h> 28 #include <stddef.h> 29 #include <sys/types.h> 30 #include <sys/task.h> 31 32 #include <sys/debug.h> 33 34 35 #include "projent.h" 36 #include "util.h" 37 38 #define SEQU(str1, str2) (strcmp(str1, str2) == 0) 39 40 #define CHECK_ERRORS_FREE_PLST(errlst, plst, attrs, ecode) { \ 41 if (!lst_is_empty(errlst)) { \ 42 util_print_errmsgs(errlst); \ 43 if (plst != NULL) { \ 44 projent_free_lst(plst); \ 45 free(plst); \ 46 } \ 47 free(attrs); \ 48 usage(); \ 49 exit(ecode); \ 50 } \ 51 } 52 53 54 /* 55 * Print usage 56 */ 57 static void 58 usage(void) 59 { 60 (void) fprintf(stderr, gettext( 61 "Usage:\n" 62 "projmod [-n] [-A|-f filename] [-p projid [-o]] [-c comment]\n" 63 " [-a|-s|-r] [-U user[,user...]] [-G group[,group...]]\n" 64 " [-K name[=value[,value...]]] [-l new_projectname]\n" 65 " project\n")); 66 } 67 68 69 /* 70 * main() 71 */ 72 int 73 main(int argc, char **argv) 74 { 75 int e, c, error; 76 77 extern char *optarg; 78 extern int optind, optopt; 79 lst_t *plst = NULL; 80 int flags = 0; 81 projent_t *ent, *modent; 82 83 /* Command line options */ 84 boolean_t fflag, nflag, cflag, oflag, pflag, lflag; 85 boolean_t sflag, rflag, aflag; 86 boolean_t Uflag, Gflag, Kflag, Aflag; 87 boolean_t modify; 88 89 /* Project entry fields */ 90 char *pname, *npname; 91 char *comment, *users, *groups, *attrs; 92 char *pusers, *pgroups; 93 94 lst_t *pattribs; 95 96 lst_t errlst; 97 98 /* Project file defaults to system project file "/etc/project" */ 99 char *projfile = PROJF_PATH; 100 struct project proj, *projp; 101 char buf[PROJECT_BUFSZ]; 102 char *str; 103 104 comment = users = groups = ""; 105 pname = npname = NULL; 106 107 fflag = nflag = cflag = oflag = pflag = lflag = B_FALSE; 108 sflag = rflag = aflag = B_FALSE; 109 Uflag = Gflag = Kflag = Aflag = B_FALSE; 110 111 modify = B_FALSE; 112 113 114 115 attrs = util_safe_zmalloc(1); 116 lst_create(&errlst); 117 118 119 (void) setlocale(LC_ALL, ""); 120 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 121 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 122 #endif 123 (void) textdomain(TEXT_DOMAIN); 124 125 /* Parse the command line argument list */ 126 while ((c = getopt(argc, argv, ":hf:nc:op:l:sraU:G:K:A")) != EOF) 127 switch (c) { 128 case 'h': 129 usage(); 130 exit(0); 131 break; 132 case 'f': 133 fflag = B_TRUE; 134 projfile = optarg; 135 break; 136 case 'n': 137 nflag = B_TRUE; 138 break; 139 case 'c': 140 cflag = B_TRUE; 141 comment = optarg; 142 break; 143 case 'o': 144 oflag = B_TRUE; 145 break; 146 case 'p': 147 pflag = B_TRUE; 148 break; 149 case 'l': 150 lflag = B_TRUE; 151 npname = optarg; 152 break; 153 case 's': 154 sflag = B_TRUE; 155 break; 156 case 'r': 157 rflag = B_TRUE; 158 break; 159 case 'a': 160 aflag = B_TRUE; 161 break; 162 case 'U': 163 Uflag = B_TRUE; 164 users = optarg; 165 break; 166 case 'G': 167 Gflag = B_TRUE; 168 groups = optarg; 169 break; 170 case 'K': 171 Kflag = B_TRUE; 172 attrs = UTIL_STR_APPEND2(attrs, ";", optarg); 173 break; 174 case 'A': 175 Aflag = B_TRUE; 176 break; 177 default: 178 util_add_errmsg(&errlst, gettext( 179 "Invalid option: -%c"), optopt); 180 break; 181 } 182 183 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 184 185 if (optind == argc - 1) { 186 pname = argv[optind]; 187 } 188 189 if (cflag || Gflag || lflag || pflag || Uflag || Kflag || Aflag) { 190 modify = B_TRUE; 191 if (pname == NULL) { 192 util_add_errmsg(&errlst, gettext( 193 "No project name specified")); 194 } 195 } else if (pname != NULL) { 196 util_add_errmsg(&errlst, gettext( 197 "missing -c, -G, -l, -p, -U, or -K")); 198 } 199 200 if (Aflag && fflag) { 201 util_add_errmsg(&errlst, gettext( 202 "-A and -f are mutually exclusive")); 203 } 204 205 if (oflag && !pflag) { 206 util_add_errmsg(&errlst, gettext( 207 "-o requires -p projid to be specified")); 208 } 209 210 if ((aflag && (rflag || sflag)) || (rflag && (aflag || sflag)) || 211 (sflag && (aflag || rflag))) { 212 util_add_errmsg(&errlst, gettext( 213 "-a, -r, and -s are mutually exclusive")); 214 } 215 216 if ((aflag || rflag || sflag) && !(Uflag || Gflag || Kflag)) { 217 util_add_errmsg(&errlst, gettext( 218 "-a, -r, and -s require -U users, -G groups " 219 "or -K attributes to be specified")); 220 } 221 222 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 223 224 if (aflag) { 225 flags |= F_MOD_ADD; 226 } else if (rflag) { 227 flags |= F_MOD_REM; 228 } else if (sflag) { 229 flags |= F_MOD_SUB; 230 } else { 231 flags |= F_MOD_REP; 232 } 233 if (!nflag) { 234 flags |= F_PAR_VLD; 235 } 236 flags |= F_PAR_RES | F_PAR_DUP; 237 238 plst = projent_get_lst(projfile, flags, &errlst); 239 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 240 241 modent = NULL; 242 if (pname != NULL) { 243 for (e = 0; e < lst_size(plst); e++) { 244 ent = lst_at(plst, e); 245 if (SEQU(ent->projname, pname)) { 246 modent = ent; 247 } 248 } 249 if (modent == NULL) { 250 util_add_errmsg(&errlst, gettext( 251 "Project \"%s\" does not exist"), pname); 252 } 253 } 254 255 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 256 257 /* 258 * If there is no modification options, simply reading the file, which 259 * includes parsing and verifying, is sufficient. 260 */ 261 if (!modify) { 262 exit(0); 263 } 264 265 VERIFY(modent != NULL); 266 267 if (lflag && projent_parse_name(pname, &errlst) == 0 && 268 projent_validate_unique_name(plst, npname, &errlst) == 0) { 269 free(modent->projname); 270 modent->projname = util_safe_strdup(npname); 271 } 272 273 if (cflag && projent_parse_comment(comment, &errlst) == 0) { 274 free(modent->comment); 275 modent->comment = util_safe_strdup(comment); 276 } 277 278 if (Uflag) { 279 pusers = projent_parse_users(users, F_PAR_SPC, 280 &errlst); 281 if (pusers != NULL) { 282 projent_merge_usrgrp("user", &modent->userlist, 283 pusers, flags, &errlst); 284 free(pusers); 285 } 286 } 287 288 if (Gflag) { 289 pgroups = projent_parse_groups(groups, F_PAR_SPC, 290 &errlst); 291 if (pgroups != NULL) { 292 projent_merge_usrgrp("group", &modent->grouplist, 293 pgroups, flags, &errlst); 294 free(pgroups); 295 } 296 } 297 298 if (Kflag) { 299 pattribs = projent_parse_attributes(attrs, F_PAR_UNT, &errlst); 300 if (pattribs != NULL) { 301 projent_merge_attributes(&modent->attrs, 302 pattribs, flags, &errlst); 303 projent_sort_attributes(modent->attrs); 304 projent_free_attributes(pattribs); 305 UTIL_FREE_SNULL(pattribs); 306 } 307 } 308 309 if (!nflag) { 310 (void) projent_validate(modent, flags, &errlst); 311 } 312 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 313 314 if (modify) { 315 projent_put_lst(projfile, plst, &errlst); 316 } 317 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 318 319 if (Aflag && (error = setproject(pname, "root", 320 TASK_FINAL|TASK_PROJ_PURGE)) != 0) { 321 if (error == SETPROJ_ERR_TASK) { 322 if (errno == EAGAIN) { 323 util_add_errmsg(&errlst, gettext( 324 "resource control limit has been reached")); 325 } else if (errno == ESRCH) { 326 util_add_errmsg(&errlst, gettext( 327 "user \"%s\" is not a member " 328 "of project \"%s\""), "root", pname); 329 } else { 330 util_add_errmsg(&errlst, gettext( 331 "could not join project \"%s\""), pname); 332 } 333 } else if (error == SETPROJ_ERR_POOL) { 334 if (errno == EACCES) { 335 util_add_errmsg(&errlst, gettext( 336 "no resource pool accepting default " 337 "bindings exists for project \"%s\""), 338 pname); 339 } else if (errno == ESRCH) { 340 util_add_errmsg(&errlst, gettext( 341 "specified resource pool does not exist " 342 "for project \"%s\""), pname); 343 } else { 344 util_add_errmsg(&errlst, gettext( 345 "could not bind to default resource pool " 346 "for project \"%s\""), pname); 347 } 348 } else { 349 /* 350 * error represents the position - within the 351 * semi-colon delimited attribute - that generated 352 * the error. 353 */ 354 if (error <= 0) { 355 util_add_errmsg(&errlst, gettext( 356 "setproject failed for project \"%s\""), 357 pname); 358 } else { 359 /* To be completed */ 360 projp = getprojbyname(pname, &proj, buf, 361 sizeof (buf)); 362 pattribs = (projp != NULL) ? 363 projent_parse_attributes(projp->pj_attr, 364 0, &errlst) : NULL; 365 if (projp != NULL && pattribs != NULL && 366 (str = projent_attrib_tostring( 367 lst_at(pattribs, error - 1))) != NULL) { 368 util_add_errmsg(&errlst, gettext( 369 "warning, \"%s\" resource control " 370 "assignment failed for project " 371 "\"%s\""), str, pname); 372 free(str); 373 } else { 374 util_add_errmsg(&errlst, gettext( 375 "warning, resource control " 376 "assignment failed for project " 377 "\"%s\" attribute %d"), pname, 378 error); 379 } 380 381 if (pattribs != NULL) { 382 projent_free_attributes(pattribs); 383 UTIL_FREE_SNULL(pattribs); 384 } 385 } 386 } 387 } 388 389 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2); 390 391 return (0); 392 }