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 
  31 #include "projent.h"
  32 #include "util.h"
  33 
  34 
  35 #define CHECK_ERRORS_FREE_PLST(errlst, plst, attrs, ecode) {    \
  36         if (!lst_is_empty(errlst)) {                                    \
  37                 util_print_errmsgs(errlst);                             \
  38                 if (plst != NULL) {                                     \
  39                         projent_free_lst(plst);                         \
  40                         free(plst);                                     \
  41                 }                                                       \
  42                 free(attrs);                                            \
  43                 usage();                                                \
  44                 exit(ecode);                                            \
  45         }                                                               \
  46 }
  47 
  48 /*
  49  * Print usage
  50  */
  51 static void
  52 usage(void)
  53 {
  54         (void) fprintf(stderr, gettext(
  55             "Usage:\n"
  56             "projadd [-n] [-f filename] [-p projid [-o]] [-c comment]\n"
  57             "        [-U user[,user...]] [-G group[,group...]]\n"
  58             "        [-K name[=value[,value...]]] project\n"));
  59 }
  60 
  61 /*
  62  * main()
  63  */
  64 int
  65 main(int argc, char **argv)
  66 {
  67         int e, c;
  68 
  69         extern char *optarg;
  70         extern int optind, optopt;
  71         projid_t maxpjid = 99;
  72         lst_t *plst = NULL;
  73         int flags = 0;
  74         char *projfile = PROJF_PATH;
  75 
  76         projent_t *ent;
  77         boolean_t nflag, pflag, oflag;          /* Command line flags.  */
  78         char *pname, *projidstr, *comment;      /* projent fields.      */
  79         char *users, *groups, *attrs;
  80         projid_t projid;
  81 
  82         lst_t errlst;
  83 
  84         /* Project file defaults to system project file "/etc/project" */
  85         users = groups = comment = projidstr = "";
  86 
  87         nflag = pflag = oflag = B_FALSE;
  88         attrs = util_safe_zmalloc(1);
  89         lst_create(&errlst);
  90 
  91 
  92         (void) setlocale(LC_ALL, "");
  93 #if !defined(TEXT_DOMAIN)               /* Should be defined by cc -D */
  94 #define TEXT_DOMAIN "SYS_TEST"          /* Use this only if it wasn't */
  95 #endif
  96         (void) textdomain(TEXT_DOMAIN);
  97 
  98         /* Parse the command line argument list */
  99         while ((c = getopt(argc, argv, ":hnf:p:oc:U:G:K:")) != EOF)
 100                 switch (c) {
 101                         case 'h':
 102                                 usage();
 103                                 exit(0);
 104                                 break;
 105                         case 'n':
 106                                 nflag = B_TRUE;
 107                                 break;
 108                         case 'f':
 109                                 projfile = optarg;
 110                                 break;
 111                         case 'p':
 112                                 pflag = B_TRUE;
 113                                 projidstr = optarg;
 114                                 break;
 115                         case 'o':
 116                                 oflag = B_TRUE;
 117                                 break;
 118                         case 'c':
 119                                 comment = optarg;
 120                                 break;
 121                         case 'U':
 122                                 users = optarg;
 123                                 break;
 124                         case 'G':
 125                                 groups = optarg;
 126                                 break;
 127                         case 'K':
 128                                 attrs = UTIL_STR_APPEND2(attrs, ";", optarg);
 129                                 break;
 130                         default:
 131                                 util_add_errmsg(&errlst, gettext(
 132                                     "Invalid option: -%c"), optopt);
 133                                 break;
 134                 }
 135 
 136 
 137 
 138         if (oflag && !pflag) {
 139                 util_add_errmsg(&errlst, gettext(
 140                     "-o requires -p projid to be specified"));
 141         }
 142 
 143         if (optind != argc -1) {
 144                 util_add_errmsg(&errlst, gettext("No project name specified"));
 145         }
 146 
 147         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 148 
 149         if (!nflag)
 150                 flags |= F_PAR_VLD;
 151         flags |= F_PAR_RES | F_PAR_DUP;
 152 
 153         /* Parse the project file to get the list of the projects */
 154         plst = projent_get_lst(projfile, flags, &errlst);
 155         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 156 
 157 
 158         /* Parse and validate new project id */
 159         if (pflag && projent_parse_projid(projidstr, &projid, &errlst) == 0) {
 160                 if (!nflag) {
 161                         projent_validate_projid(projid, 0, &errlst);
 162                         if (!oflag) {
 163                                 projent_validate_unique_id(plst, projid,
 164                                     &errlst);
 165                         }
 166                 }
 167         }
 168         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 169 
 170         /* Find the maxprojid */
 171         for (e = 0; e < lst_size(plst); e++) {
 172                 ent = lst_at(plst, e);
 173                 maxpjid = (ent->projid > maxpjid) ? ent->projid : maxpjid;
 174         }
 175 
 176 
 177         if (!pflag && asprintf(&projidstr, "%ld", maxpjid + 1) == -1) {
 178                 util_add_errmsg(&errlst, gettext("Failed to allocate memory"));
 179                 CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 180         }
 181 
 182         pname = argv[optind];
 183         ent = projent_parse_components(pname, projidstr, comment, users,
 184             groups, attrs, F_PAR_SPC | F_PAR_UNT, &errlst);
 185         if (!pflag)
 186                 free(projidstr);
 187 
 188         if (!nflag)
 189                 projent_validate_unique_name(plst, pname, &errlst);
 190 
 191         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 192 
 193         /* Sort attributes list */
 194         projent_sort_attributes(ent->attrs);
 195 
 196 
 197         /* Add the new project entry to the list */
 198         lst_insert_tail(plst, ent);
 199 
 200         /* Validate the projent before writing the list to the project file */
 201         (void) projent_validate(ent, flags, &errlst);
 202         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 203 
 204         /* Write out the project file */
 205         projent_put_lst(projfile, plst, &errlst);
 206         CHECK_ERRORS_FREE_PLST(&errlst, plst, attrs, 2);
 207 
 208         return (0);
 209 }