From 97cc03f4f3328180c8f49cd61c406bb7bc8a2dcb Mon Sep 17 00:00:00 2001 From: Sean Farley Date: Wed, 23 Apr 2008 00:49:13 +0000 Subject: Add four utility functions related to struct grp processing modeled in-part after similar calls related to struct pwd in libutil/pw_util.c: - gr_equal() Perform a deep comparison of two struct grp's. It does a thorough, yet unoptimized comparison of all the members regardless of order. - gr_make() Create a string (see group(5)) from a struct grp. - gr_dup() Duplicate a struct grp. Returns a value that is a single contiguous block of memory. - gr_scan() Create a struct grp from a string (as produced by gr_make()). MFC after: 3 weeks --- libutil/gr_util.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libutil/libutil.h | 7 ++ 2 files changed, 241 insertions(+) create mode 100644 libutil/gr_util.c (limited to 'libutil') diff --git a/libutil/gr_util.c b/libutil/gr_util.c new file mode 100644 index 0000000..89f5fa3 --- /dev/null +++ b/libutil/gr_util.c @@ -0,0 +1,234 @@ +/*- + * Copyright (c) 2008 Sean C. Farley + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + + +static const char GroupLineFormat[] = "%s:%s:%ju:"; + + +/* + * Compares two struct group's. + */ +int +gr_equal(const struct group *gr1, const struct group *gr2) +{ + bool found; + bool equal; + int gr1Ndx; + int gr2Ndx; + + /* Check that the non-member information is the same. */ + equal = strcmp(gr1->gr_name, gr2->gr_name) == 0 && + strcmp(gr1->gr_passwd, gr2->gr_passwd) == 0 && + gr1->gr_gid == gr2->gr_gid; + + /* Check all members in both groups. */ + if (equal) { + for (found = false, gr1Ndx = 0; gr1->gr_mem[gr1Ndx] != NULL; + gr1Ndx++) { + for (gr2Ndx = 0; gr2->gr_mem[gr2Ndx] != NULL; gr2Ndx++) + if (strcmp(gr1->gr_mem[gr1Ndx], + gr2->gr_mem[gr2Ndx]) == 0) { + found = true; + break; + } + if (! found) { + equal = false; + break; + } + } + + /* Check that group2 does not have more members than group1. */ + if (gr2->gr_mem[gr1Ndx] != NULL) + equal = false; + } + + return (equal); +} + + +/* + * Make a group line out of a struct group. + */ +char * +gr_make(const struct group *gr) +{ + char *line; + int ndx; + size_t lineSize; + + /* Calculate the length of the group line. */ + lineSize = snprintf(NULL, 0, GroupLineFormat, gr->gr_name, + gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; + for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) + lineSize += strlen(gr->gr_mem[ndx]) + 1; + if (ndx > 0) + lineSize--; + + /* Create the group line and fill it. */ + if ((line = malloc(lineSize)) == NULL) + return (NULL); + lineSize = snprintf(line, lineSize, GroupLineFormat, gr->gr_name, + gr->gr_passwd, (uintmax_t)gr->gr_gid); + for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { + strcat(line, gr->gr_mem[ndx]); + if (gr->gr_mem[ndx + 1] != NULL) + strcat(line, ","); + } + + return (line); +} + + +/* + * Duplicate a struct group. + */ +struct group * +gr_dup(const struct group *gr) +{ + int ndx; + int numMem; + size_t len; + struct group *ngr; + + /* Calculate size of group. */ + len = sizeof(*gr) + + (gr->gr_name != NULL ? strlen(gr->gr_name) + 1 : 0) + + (gr->gr_passwd != NULL ? strlen(gr->gr_passwd) + 1 : 0); + numMem = 0; + if (gr->gr_mem != NULL) { + for (; gr->gr_mem[numMem] != NULL; numMem++) + len += strlen(gr->gr_mem[numMem]) + 1; + len += (numMem + 1) * sizeof(*(gr->gr_mem)); + } + + /* Create new group and copy old group into it. */ + if ((ngr = calloc(1, len)) == NULL) + return (NULL); + len = sizeof(*ngr); + ngr->gr_gid = gr->gr_gid; + if (gr->gr_name != NULL) { + ngr->gr_name = (char *)ngr + len; + len += sprintf(ngr->gr_name, "%s", gr->gr_name) + 1; + } + if (gr->gr_passwd != NULL) { + ngr->gr_passwd = (char *)ngr + len; + len += sprintf(ngr->gr_passwd, "%s", gr->gr_passwd) + 1; + } + if (gr->gr_mem != NULL) { + ngr->gr_mem = (char **)((char *)ngr + len); + len += (numMem + 1) * sizeof(*(ngr->gr_mem)); + for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { + ngr->gr_mem[ndx] = (char *)ngr + len; + len += sprintf(ngr->gr_mem[ndx], "%s", + gr->gr_mem[ndx]) + 1; + } + ngr->gr_mem[ndx] = NULL; + } + + return (ngr); +} + + +/* + * Scan a line and place it into a group structure. + */ +static bool +__gr_scan(char *line, struct group *gr) +{ + char *loc; + int ndx; + + /* Assign non-member information to structure. */ + gr->gr_name = line; + if ((loc = strchr(line, ':')) == NULL) + return (false); + *loc = '\0'; + gr->gr_passwd = loc + 1; + if (*(gr->gr_passwd) == ':') + *(gr->gr_passwd) = '\0'; + else { + if ((loc = strchr(loc + 1, ':')) == NULL) + return (false); + *loc = '\0'; + } + if (sscanf(loc + 1, "%u", &(gr->gr_gid)) != 1) + return (false); + + /* Assign member information to structure. */ + if ((loc = strchr(loc + 1, ':')) == NULL) + return (false); + line = loc + 1; + gr->gr_mem = NULL; + if (*line != '\0') { + ndx = 0; + do { + if ((gr->gr_mem = reallocf(gr->gr_mem, + sizeof(*(gr->gr_mem)) * (ndx + 1))) == NULL) + return (false); + gr->gr_mem[ndx] = strsep(&line, ","); + } while (gr->gr_mem[ndx++] != NULL); + } + + return (true); +} + + +/* + * Create a struct group from a line. + */ +struct group * +gr_scan(const char *line) +{ + char *lineCopy; + struct group *newGr; + struct group gr; + + if ((lineCopy = strdup(line)) == NULL) + return (NULL); + if (!__gr_scan(lineCopy, &gr)) { + free(lineCopy); + return (NULL); + } + newGr = gr_dup(&gr); + free(lineCopy); + if (gr.gr_mem != NULL) + free(gr.gr_mem); + + return (newGr); +} diff --git a/libutil/libutil.h b/libutil/libutil.h index aa663a7..8fafe9b 100644 --- a/libutil/libutil.h +++ b/libutil/libutil.h @@ -119,6 +119,13 @@ const char *pw_tempname(void); int pw_tmp(int _mfd); #endif +#ifdef _GRP_H_ +int gr_equal(const struct group *gr1, const struct group *gr2); +char *gr_make(const struct group *gr); +struct group *gr_dup(const struct group *gr); +struct group *gr_scan(const char *line); +#endif + #ifdef _SYS_PARAM_H_ struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); int pidfile_write(struct pidfh *pfh); -- cgit v1.2.3-56-ge451