/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
#import "LUGlobal.h"
#import "LUDictionary.h"
#import "LUArray.h"
#import "FFParser.h"
#import <NetInfo/nilib2.h>
#import <NetInfo/dsutil.h>
#import "print.h"
#import <sys/types.h>
#import <pwd.h>
#import <libc.h>
#import <stdlib.h>
#import <strings.h>
#import <stdio.h>
#import <netinfo/ni.h>
#define BUFSIZE 8192
#define MYNAME "niload"
#define TIMEOUT 30
#define RETAIN_NETINFO 1
#define DELETE_NETINFO 2
#define MERGE_VALUES 3
BOOL verbose;
extern void raw_load();
/* To avoid including libc.h */
extern uid_t getuid(void);
char *
getLineFromFile(FILE *fp, LUCategory cat)
{
char s[BUFSIZE];
char c;
char *out;
BOOL getNextLine;
int len;
s[0] = '\0';
fgets(s, BUFSIZE, fp);
if (s == NULL || s[0] == '\0') return NULL;
if (s[0] == '#')
{
out = strdup("#");
return out;
}
len = strlen(s) - 1;
s[len] = '\0';
out = strdup(s);
/* only printcap, bootparams, and aliases can continue on multiple lines */
if ((cat != LUCategoryPrinter) && (cat != LUCategoryBootparam) && (cat != LUCategoryAlias))
{
return out;
}
if (cat == LUCategoryAlias)
{
/* alias continues if next line starts with whitespace */
c = getc(fp);
while ((c == ' ') || (c == '\t'))
{
fgets(s, BUFSIZE, fp);
if (s == NULL || s[0] == '\0') return out;
len = strlen(s) - 1;
s[len] = '\0';
out = concatString(out, s);
c = getc(fp);
}
/* hit next line - unread a character */
if (c != EOF) fseek(fp, -1, SEEK_CUR);
return out;
}
/* printcap and bootparams continue if last char is a backslash */
getNextLine = out[len - 1] == '\\';
if (getNextLine) out[--len] = '\0';
while (getNextLine)
{
fgets(s, BUFSIZE, fp);
if (s == NULL || s[0] == '\0') return out;
len = strlen(s) - 1;
s[len] = '\0';
getNextLine = s[len - 1] == '\\';
if (getNextLine) s[--len] = '\0';
out = concatString(out, s);
}
return out;
}
LUArray *
allItemsWithCategory(LUCategory cat, FILE *fp)
{
char *line;
LUDictionary *item;
LUArray *all;
FFParser *parser;
if (fp == NULL) return nil;
parser = [[FFParser alloc] init];
/* bootptab entries start after a " if (cat == LUCategoryBootp)
{
while (NULL != (line = getLineFromFile(fp, cat)))
{
if (!strncmp(line, " free(line);
line = NULL;
}
if (line == NULL)
{
[parser free];
return nil;
}
free(line);
line = NULL;
}
all = [[LUArray alloc] init];
while (NULL != (line = getLineFromFile(fp, cat)))
{
if (line[0] == '#')
{
free(line);
line = NULL;
continue;
}
item = [parser parse_A:line category:cat];
free(line);
line = NULL;
if (item == nil) continue;
[all addObject:item];
[item release];
}
[parser free];
return all;
}
void
usage(void)
{
fprintf(stderr, "usage: ");
fprintf(stderr, " fprintf(stderr, "opts:\n");
fprintf(stderr, "\t-d delete all existing entries from NetInfo\n");
fprintf(stderr, "\t before loading new entries\n\n");
fprintf(stderr, "\t-m merge properties already in NetInfo\n");
fprintf(stderr, "\t when the input contains a duplicate name\n\n");
fprintf(stderr, "\t-v verbose\n");
fprintf(stderr, "\t-p prompt for password\n");
fprintf(stderr, "\t-u <user> authenticate as another user (implies -p)\n");
fprintf(stderr, "\t-P <password> password supplied on command line (overrides -p)\n");
fprintf(stderr, "\t-T <timeout> read & write timeout in seconds (default 30)\n");
fprintf(stderr, "\t-t domain specified by <host>/<tag>\n");
exit(1);
}
void
merge_proplist(ni_proplist *new, ni_proplist *old)
{
int p, v, plen, vlen;
ni_index pwhere, vwhere;
plen = old->ni_proplist_len;
for (p = 0; p < plen; p++)
{
pwhere = ni_proplist_match((const ni_proplist)*new, (const ni_name)old->ni_proplist_val[p].nip_name, NULL);
if (pwhere == NI_INDEX_NULL)
{
ni_proplist_insert(new, (const ni_property)old->ni_proplist_val[p], NI_INDEX_NULL);
}
else
{
vlen = old->ni_proplist_val[p].nip_val.ni_namelist_len;
for (v = 0; v < vlen; v++)
{
vwhere = ni_namelist_match(new->ni_proplist_val[pwhere].nip_val, old->ni_proplist_val[p].nip_val.ni_namelist_val[v]);
if (vwhere == NI_INDEX_NULL)
{
ni_namelist_insert(&(new->ni_proplist_val[pwhere].nip_val), old->ni_proplist_val[p].nip_val.ni_namelist_val[v], NI_INDEX_NULL);
}
}
}
}
}
ni_status
update_dir(void *domain, char *parent, char *name, LUDictionary *item, BOOL merge)
{
ni_proplist *pl;
ni_proplist oldpl;
ni_status status;
ni_id dir, child_dir;
char path[1024];
int i, len, x;
sprintf(path, " x = strlen(path);
len = strlen(name);
for (i = 0; i < len; i++)
{
if (name[i] == '/') path[x++] = '\\';
path[x++] = name[i];
}
path[x] = '\0';
status = ni_pathsearch(domain, &dir, path);
if (status == NI_NODIR)
{
/* doesn't exist */
/* find parent dir */
status = ni_pathsearch(domain, &dir, parent);
if (status == NI_NODIR)
{
/* create the parent */
if (verbose) fprintf(stderr, "creating directory: status = ni2_createpath(domain, &dir, parent);
}
if (status != NI_OK) return status;
/* create new child directory in netinfo */
pl = [item niProplist];
if (verbose) fprintf(stderr, "writing new directory status = ni_create(domain, &dir, *pl, &child_dir, NI_INDEX_NULL);
ni_proplist_free(pl);
return status;
}
if (status != NI_OK) return status;
pl = [item niProplist];
if (merge)
{
/* read from netinfo */
status = ni_read(domain, &dir, &oldpl);
if (status != NI_OK)
{
ni_proplist_free(pl);
return status;
}
/* merge values */
merge_proplist(pl, &oldpl);
ni_proplist_free(&oldpl);
}
if (verbose) fprintf(stderr, " status = ni_write(domain, &dir, *pl);
ni_proplist_free(pl);
return status;
}
int
main(int argc, char *argv[])
{
LUArray *all;
LUDictionary *item;
ni_entrylist el;
int i;
int j, len, nilen;
char *lastchar, *p, *t;
BOOL opt_promptpw, opt_passwd;
BOOL merge, delete;
int format_arg, domain_arg;
struct passwd *pw;
char *format;
LUCategory cat;
char nidirname[64];
void *domain;
ni_status status;
ni_id dir;
char *name;
BOOL raw;
char auth_user[128];
char auth_passwd[128];
BOOL opt_user, opt_tag, authenticate;
int timeout;
if (argc < 3) usage();
pw = getpwuid(getuid());
if (pw == NULL)
{
fprintf(stderr," exit(1);
}
strcpy(auth_user, "root");
auth_passwd[0] = '\0';
opt_promptpw = NO;
opt_user = NO;
opt_passwd = NO;
authenticate = NO;
opt_tag = NO;
verbose = NO;
raw = NO;
merge = NO;
delete = NO;
timeout = TIMEOUT;
for (i = 1; i < argc; i++)
{
if (argv[i][0] != '-')
{
/* do nothing */
}
else if (!strcmp(argv[i], "-r") && !raw)
{
raw = YES;
}
else if (!strcmp(argv[i], "-p") && !opt_promptpw)
{
opt_promptpw = YES;
}
else if (!strcmp(argv[i], "-t") && !opt_tag)
{
opt_tag = YES;
}
else if (!strcmp(argv[i], "-T"))
{
if (i == argc - 1)
{
fprintf(stderr, " usage();
}
timeout = atoi(argv[++i]);
}
else if (!strcmp(argv[i], "-u") && !opt_user)
{
if (i == argc - 1)
{
fprintf(stderr, " usage();
}
opt_user = YES;
i++;
strcpy(auth_user, argv[i]);
/* BEGIN UGLY HACK TO MAKE argv[i] DISAPPEAR */
lastchar = &argv[argc-1][0];
while(*lastchar != '\0') lastchar++;
p = &argv[i+1][0];
t = &argv[i][0];
len = p - t;
for (j = i+1; j < argc; j++) *(&argv[j-1]) = argv[j];
argc--;
for (; p < lastchar; p++) *(p-len) = *p;
for (j = i; j < argc; j++) argv[j] -= len;
p -= len;
*p = '\0';
for (p++; p < lastchar; p++) *p = ' ';
i--;
/* END UGLY HACK */
}
else if (!strcmp(argv[i], "-P") && !opt_passwd)
{
if (i == argc - 1)
{
fprintf(stderr, " MYNAME, argv[i]);
usage();
}
opt_passwd = YES;
i++;
strcpy(auth_passwd, argv[i]);
/* BEGIN UGLY HACK TO MAKE argv[i] DISAPPEAR */
lastchar = &argv[argc-1][0];
while(*lastchar != '\0') lastchar++;
p = &argv[i+1][0];
t = &argv[i][0];
len = p - t;
for (j = i+1; j < argc; j++) *(&argv[j-1]) = argv[j];
argc--;
for (; p < lastchar; p++) *(p-len) = *p;
for (j = i; j < argc; j++) argv[j] -= len;
p -= len;
*p = '\0';
for (p++; p < lastchar; p++) *p = ' ';
i--;
/* END UGLY HACK */
}
else if (!strcmp(argv[i], "-d"))
{
delete = YES;
}
else if (!strcmp(argv[i], "-m"))
{
merge = YES;
}
else if (!strcmp(argv[i], "-v")) verbose = YES;
else
{
fprintf(stderr, " usage();
}
}
format_arg = 0;
domain_arg = 0;
for (i = 1; i < argc; i++)
{
if (argv[i][0] != '-' && strcmp(argv[i-1], "-T"))
{
if (format_arg == 0) format_arg = i;
else if (domain_arg == 0) domain_arg = i;
else
{
fprintf(stderr, " usage();
}
}
}
if (opt_user)
{
authenticate = YES;
if (!opt_passwd) opt_promptpw = YES;
}
else
{
if (opt_passwd || opt_promptpw) authenticate = YES;
}
if (opt_passwd) opt_promptpw = NO;
if (opt_promptpw)
{
strcpy(auth_passwd, (char *)getpass("Password: "));
}
if (do_open(MYNAME, argv[domain_arg], &domain, opt_tag, timeout, auth_user, auth_passwd))
usage();
format = argv[format_arg];
cat = -1;
if (raw)
{
/* format is directory name */
raw_load(domain, format, NULL);
ni_free(domain);
exit(0);
}
else if (!strcmp(format, "aliases"))
{
cat = LUCategoryAlias;
strcpy(nidirname, "/aliases");
}
else if (!strcmp(format, "bootparams"))
{
cat = LUCategoryBootparam;
strcpy(nidirname, "/machines");
}
else if (!strcmp(format, "bootptab"))
{
cat = LUCategoryBootp;
strcpy(nidirname, "/machines");
}
else if (!strcmp(format, "fstab"))
{
cat = LUCategoryMount;
strcpy(nidirname, "/mounts");
}
else if (!strcmp(format, "group"))
{
cat = LUCategoryGroup;
strcpy(nidirname, "/groups");
}
else if (!strcmp(format, "hosts"))
{
cat = LUCategoryHost;
strcpy(nidirname, "/machines");
}
else if (!strcmp(format, "networks"))
{
cat = LUCategoryNetwork;
strcpy(nidirname, "/networks");
}
else if (!strcmp(format, "passwd"))
{
cat = LUCategoryUser;
strcpy(nidirname, "/users");
}
else if (!strcmp(format, "passwd.43"))
{
cat = LUCategoryUser_43;
strcpy(nidirname, "/users");
}
else if (!strcmp(format, "printcap"))
{
cat = LUCategoryPrinter;
strcpy(nidirname, "/printers");
}
else if (!strcmp(format, "protocols"))
{
cat = LUCategoryProtocol;
strcpy(nidirname, "/protocols");
}
else if (!strcmp(format, "rpc"))
{
cat = LUCategoryRpc;
strcpy(nidirname, "/rpcs");
}
else if (!strcmp(format, "services"))
{
cat = LUCategoryService;
strcpy(nidirname, "/services");
}
else
{
printf(" usage();
}
all = allItemsWithCategory(cat, stdin);
if (all == nil)
{
if (verbose) fprintf(stderr, "0 items read from input\n");
ni_free(domain);
exit(0);
}
len = [all count];
if (len == 0)
{
if (verbose) fprintf(stderr, "0 items read from input\n");
ni_free(domain);
exit(0);
}
if (verbose) fprintf(stderr, "
if (delete)
{
if (verbose) fprintf(stderr, "Deleting exiting NetInfo directory status = ni2_destroy(domain, nidirname);
if (status != NI_OK)
{
fprintf(stderr, " [all release];
ni_free(domain);
exit(1);
}
}
NI_INIT(&el);
status = ni_pathsearch(domain, &dir, nidirname);
if (status == NI_NODIR)
{
if (verbose) fprintf(stderr, "Creating NetInfo directory
status = ni2_createpath(domain, &dir, nidirname);
if (status != NI_OK)
{
fprintf(stderr, " [all release];
ni_free(domain);
exit(1);
}
}
else if (status != NI_OK)
{
fprintf(stderr, " [all release];
ni_free(domain);
exit(1);
}
status = ni_list(domain, &dir, "name", &el);
if (status != NI_OK)
{
fprintf(stderr, " [all release];
ni_free(domain);
exit(1);
}
nilen = el.ni_entrylist_len;
if (verbose) fprintf(stderr, "Netinfo nidirname, nilen);
for (i = 0; i < len; i++)
{
item = [all objectAtIndex:i];
if (verbose)
{
fprintf(stderr, "\nProcessing input item:\n");
[item print:stderr];
}
name = [item valueForKey:"name"];
if (name == NULL)
{
fprintf(stderr, "input item has no name - ignored\n");
continue;
}
status = update_dir(domain, nidirname, name, item, merge);
if (status != NI_OK)
{
fprintf(stderr, " [all release];
ni_free(domain);
exit(1);
}
}
[all release];
ni_free(domain);
exit(0);
}