8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / autofs / auto_subr.c
blob64cbe46907a695032a8be08a4f72a7c95e92ac5e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <locale.h>
31 #include <syslog.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <dirent.h>
36 #include <limits.h>
37 #include <thread.h>
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <sys/vfs.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mnttab.h>
44 #include <sys/mntent.h>
45 #include <sys/mount.h>
46 #include <sys/signal.h>
47 #include <sys/utsname.h>
48 #include <sys/systeminfo.h>
49 #include <sys/tiuser.h>
50 #include <sys/utsname.h>
51 #include <rpc/rpc.h>
52 #include <rpcsvc/nfs_prot.h>
53 #include <rpcsvc/daemon_utils.h>
54 #include <assert.h>
55 #include "automount.h"
56 #include <deflt.h>
57 #include <zone.h>
58 #include <priv.h>
59 #include <fcntl.h>
60 #include <libshare.h>
61 #include <libscf.h>
62 #include "smfcfg.h"
64 static char *check_hier(char *);
65 static int arch(char *, size_t, bool_t);
66 static int cpu(char *, size_t);
67 static int natisa(char *, size_t);
68 static int platform(char *, size_t);
70 struct mntlist *current_mounts;
72 static bool_t nodirect_map = FALSE;
75 * If the system is labeled then we need to
76 * have a uniquely-named auto_home map for each zone.
77 * The maps are made unique by appending the zonename.
78 * The home directory is made unique by prepending /zone/<zonename>
79 * for each zone that is dominated by the current zone.
80 * The current zone's home directory mount point is not changed.
82 * For each auto_home_<zonename> a default template map is created
83 * only if it doesn't exist yet. The default entry is used to declare
84 * local home directories created within each zone. For example:
86 * +auto_home_public
87 * * -fstype=lofs :/zone/public/export/home/&
89 static void
90 loadzone_maps(char *mntpnt, char *map, char *opts, char **stack, char ***stkptr)
92 zoneid_t *zids = NULL;
93 zoneid_t my_zoneid;
94 uint_t nzents_saved;
95 uint_t nzents;
96 int i;
98 if (!priv_ineffect(PRIV_SYS_MOUNT))
99 return;
101 if (zone_list(NULL, &nzents) != 0) {
102 return;
104 my_zoneid = getzoneid();
105 again:
106 if (nzents == 0)
107 return;
109 zids = malloc(nzents * sizeof (zoneid_t));
110 nzents_saved = nzents;
112 if (zone_list(zids, &nzents) != 0) {
113 free(zids);
114 return;
116 if (nzents != nzents_saved) {
117 /* list changed, try again */
118 free(zids);
119 goto again;
122 for (i = 0; i < nzents; i++) {
123 char zonename[ZONENAME_MAX];
124 char zoneroot[MAXPATHLEN];
126 if (getzonenamebyid(zids[i], zonename, ZONENAME_MAX) != -1) {
127 char appended_map[MAXPATHLEN];
128 char prepended_mntpnt[MAXPATHLEN];
129 char map_path[MAXPATHLEN];
130 int fd;
132 (void) snprintf(appended_map, sizeof (appended_map),
133 "%s_%s", map, zonename);
135 /* for current zone, leave mntpnt alone */
136 if (zids[i] != my_zoneid) {
137 (void) snprintf(prepended_mntpnt,
138 sizeof (prepended_mntpnt),
139 "/zone/%s%s", zonename, mntpnt);
140 if (zone_getattr(zids[i], ZONE_ATTR_ROOT,
141 zoneroot, sizeof (zoneroot)) == -1)
142 continue;
143 } else {
144 (void) strcpy(prepended_mntpnt, mntpnt);
145 zoneroot[0] = '\0';
148 dirinit(prepended_mntpnt, appended_map, opts, 0, stack,
149 stkptr);
151 * Next create auto_home_<zone> maps for each zone
154 (void) snprintf(map_path, sizeof (map_path),
155 "/etc/%s", appended_map);
157 * If the map file doesn't exist create a template
159 if ((fd = open(map_path, O_RDWR | O_CREAT | O_EXCL,
160 S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) {
161 int len;
162 char map_rec[MAXPATHLEN];
164 len = snprintf(map_rec, sizeof (map_rec),
165 "+%s\n*\t-fstype=lofs\t:%s/export/home/&\n",
166 appended_map, zoneroot);
167 if (len <= sizeof (map_rec))
168 (void) write(fd, map_rec, len);
169 (void) close(fd);
173 free(zids);
176 void
177 dirinit(char *mntpnt, char *map, char *opts, int direct, char **stack,
178 char ***stkptr)
180 struct autodir *dir;
181 char *p;
183 if (strcmp(map, "-null") == 0) {
184 if (strcmp(mntpnt, "/-") == 0)
185 nodirect_map = TRUE;
186 goto enter;
189 p = mntpnt + (strlen(mntpnt) - 1);
190 if (*p == '/')
191 *p = '\0'; /* trim trailing / */
192 if (*mntpnt != '/') {
193 pr_msg("dir %s must start with '/'", mntpnt);
194 return;
196 if (p = check_hier(mntpnt)) {
197 pr_msg("hierarchical mountpoint: %s and %s",
198 p, mntpnt);
199 return;
203 * If it's a direct map then call dirinit
204 * for every map entry.
206 if ((strcmp(mntpnt, "/-") == 0) && !(nodirect_map)) {
207 (void) loaddirect_map(map, map, opts, stack, stkptr);
208 return;
212 * Home directories are polyinstantiated on
213 * labeled systems.
215 if (is_system_labeled() &&
216 (strcmp(mntpnt, "/home") == 0) &&
217 (strcmp(map, "auto_home") == 0)) {
218 (void) loadzone_maps(mntpnt, map, opts, stack, stkptr);
219 return;
221 enter:
222 dir = (struct autodir *)malloc(sizeof (*dir));
223 if (dir == NULL)
224 goto alloc_failed;
225 dir->dir_name = strdup(mntpnt);
226 if (dir->dir_name == NULL)
227 goto alloc_failed;
228 dir->dir_map = strdup(map);
229 if (dir->dir_map == NULL)
230 goto alloc_failed;
231 dir->dir_opts = strdup(opts);
232 if (dir->dir_opts == NULL)
233 goto alloc_failed;
234 dir->dir_direct = direct;
235 dir->dir_remount = 0;
236 dir->dir_next = NULL;
239 * Append to dir chain
241 if (dir_head == NULL)
242 dir_head = dir;
243 else
244 dir_tail->dir_next = dir;
246 dir->dir_prev = dir_tail;
247 dir_tail = dir;
249 return;
251 alloc_failed:
252 if (dir != NULL) {
253 if (dir->dir_opts)
254 free(dir->dir_opts);
255 if (dir->dir_map)
256 free(dir->dir_map);
257 if (dir->dir_name)
258 free(dir->dir_name);
259 free(dir);
261 pr_msg("dirinit: memory allocation failed");
265 * Check whether the mount point is a
266 * subdirectory or a parent directory
267 * of any previously mounted automount
268 * mount point.
270 static char *
271 check_hier(mntpnt)
272 char *mntpnt;
274 register struct autodir *dir;
275 register char *p, *q;
277 for (dir = dir_head; dir; dir = dir->dir_next) {
278 p = dir->dir_name;
279 q = mntpnt;
280 for (; *p == *q; p++, q++)
281 if (*p == '\0')
282 break;
283 if (*p == '/' && *q == '\0')
284 return (dir->dir_name);
285 if (*p == '\0' && *q == '/')
286 return (dir->dir_name);
287 if (*p == '\0' && *q == '\0')
288 return (NULL);
290 return (NULL); /* it's not a subdir or parent */
294 * Gets the next token from the string "p" and copies it into "w". The "wq" is
295 * a quote vector for "w" and is derived from "pq", which is a quote vector for
296 * "p". Delim is the character to be used as a delimiter for the scan. A space
297 * means "whitespace". The call to getword must provide buffers w and wq of size
298 * at least wordsz. getword() will pass strings of maximum length (wordsz-1),
299 * since it needs to null terminate the string.
300 * Returns 0 on ok and -1 on error.
303 getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz)
305 char *tmp = w;
306 char *tmpq = wq;
307 int count = wordsz;
309 if (wordsz <= 0) {
310 if (verbose)
311 syslog(LOG_ERR,
312 "getword: input word size %d must be > 0", wordsz);
313 return (-1);
316 while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ')
317 (*p)++, (*pq)++;
319 while (**p &&
320 !((delim == ' ' ? isspace(**p) : **p == delim) &&
321 **pq == ' ')) {
322 if (--count <= 0) {
323 *tmp = '\0';
324 *tmpq = '\0';
325 syslog(LOG_ERR,
326 "maximum word length (%d) exceeded", wordsz);
327 return (-1);
329 *w++ = *(*p)++;
330 *wq++ = *(*pq)++;
332 *w = '\0';
333 *wq = '\0';
335 return (0);
339 * get_line attempts to get a line from the map, upto LINESZ. A line in
340 * the map is a concatenation of lines if the continuation symbol '\'
341 * is used at the end of the line. Returns line on success, a NULL on
342 * EOF, and an empty string on lines > linesz.
344 char *
345 get_line(FILE *fp, char *map, char *line, int linesz)
347 register char *p = line;
348 register int len;
349 int excess = 0;
351 *p = '\0';
353 for (;;) {
354 if (fgets(p, linesz - (p-line), fp) == NULL) {
355 return (*line ? line : NULL); /* EOF */
358 len = strlen(line);
359 if (len <= 0) {
360 p = line;
361 continue;
363 p = &line[len - 1];
366 * Is input line too long?
368 if (*p != '\n') {
369 excess = 1;
371 * Perhaps last char read was '\'. Reinsert it
372 * into the stream to ease the parsing when we
373 * read the rest of the line to discard.
375 (void) ungetc(*p, fp);
376 break;
378 trim:
379 /* trim trailing white space */
380 while (p >= line && isspace(*(uchar_t *)p))
381 *p-- = '\0';
382 if (p < line) { /* empty line */
383 p = line;
384 continue;
387 if (*p == '\\') { /* continuation */
388 *p = '\0';
389 continue;
393 * Ignore comments. Comments start with '#'
394 * which must be preceded by a whitespace, unless
395 * if '#' is the first character in the line.
397 p = line;
398 while (p = strchr(p, '#')) {
399 if (p == line || isspace(*(p-1))) {
400 *p-- = '\0';
401 goto trim;
403 p++;
405 break;
407 if (excess) {
408 int c;
411 * discard rest of line and return an empty string.
412 * done to set the stream to the correct place when
413 * we are done with this line.
415 while ((c = getc(fp)) != EOF) {
416 *p = c;
417 if (*p == '\n') /* end of the long line */
418 break;
419 else if (*p == '\\') { /* continuation */
420 if (getc(fp) == EOF) /* ignore next char */
421 break;
424 syslog(LOG_ERR,
425 "map %s: line too long (max %d chars)",
426 map, linesz-1);
427 *line = '\0';
430 return (line);
434 * Gets the retry=n entry from opts.
435 * Returns 0 if retry=n is not present in option string,
436 * retry=n is invalid, or when option string is NULL.
439 get_retry(char *opts)
441 int retry = 0;
442 char buf[MAXOPTSLEN];
443 char *p, *pb, *lasts;
445 if (opts == NULL)
446 return (retry);
448 (void) strcpy(buf, opts);
449 pb = buf;
450 while (p = (char *)strtok_r(pb, ",", &lasts)) {
451 pb = NULL;
452 if (strncmp(p, "retry=", 6) == 0)
453 retry = atoi(p+6);
455 return (retry > 0 ? retry : 0);
459 * Returns zero if "opt" is found in mnt->mnt_opts, setting
460 * *sval to whatever follows the equal sign after "opt".
461 * str_opt allocates a string long enough to store the value of
462 * "opt" plus a terminating null character and returns it as *sval.
463 * It is the responsability of the caller to deallocate *sval.
464 * *sval will be equal to NULL upon return if either "opt=" is not found,
465 * or "opt=" has no value associated with it.
467 * stropt will return -1 on error.
470 str_opt(struct mnttab *mnt, char *opt, char **sval)
472 char *str, *comma;
475 * is "opt" in the options field?
477 if (str = hasmntopt(mnt, opt)) {
478 str += strlen(opt);
479 if (*str++ != '=' ||
480 (*str == ',' || *str == '\0')) {
481 syslog(LOG_ERR, "Bad option field");
482 return (-1);
484 comma = strchr(str, ',');
485 if (comma != NULL)
486 *comma = '\0';
487 *sval = strdup(str);
488 if (comma != NULL)
489 *comma = ',';
490 if (*sval == NULL)
491 return (-1);
492 } else
493 *sval = NULL;
495 return (0);
499 * Performs text expansions in the string "pline".
500 * "plineq" is the quote vector for "pline".
501 * An identifier prefixed by "$" is replaced by the
502 * corresponding environment variable string. A "&"
503 * is replaced by the key string for the map entry.
505 * This routine will return an error (non-zero) if *size* would be
506 * exceeded after expansion, indicating that the macro_expand failed.
507 * This is to prevent writing past the end of pline and plineq.
508 * Both pline and plineq are left untouched in such error case.
511 macro_expand(key, pline, plineq, size)
512 char *key, *pline, *plineq;
513 int size;
515 register char *p, *q;
516 register char *bp, *bq;
517 register char *s;
518 char buffp[LINESZ], buffq[LINESZ];
519 char namebuf[64], *pn;
520 int expand = 0;
521 struct utsname name;
522 char procbuf[SYS_NMLN];
523 char isaname[64];
525 p = pline; q = plineq;
526 bp = buffp; bq = buffq;
528 while (*p) {
529 if (*p == '&' && *q == ' ') { /* insert key */
531 * make sure we don't overflow buffer
533 if ((int)((bp - buffp) + strlen(key)) < size) {
534 for (s = key; *s; s++) {
535 *bp++ = *s;
536 *bq++ = ' ';
538 expand++;
539 p++; q++;
540 continue;
541 } else {
543 * line too long...
545 return (1);
549 if (*p == '$' && *q == ' ') { /* insert env var */
550 p++; q++;
551 pn = namebuf;
552 if (*p == '{') {
553 p++; q++;
554 while (*p && *p != '}') {
555 *pn++ = *p++;
556 q++;
558 if (*p) {
559 p++; q++;
561 } else {
562 while (*p && (*p == '_' || isalnum(*p))) {
563 *pn++ = *p++;
564 q++;
567 *pn = '\0';
569 s = getenv(namebuf);
570 if (!s) {
571 /* not found in env */
572 if (strcmp(namebuf, "ARCH") == 0) {
573 if (arch(procbuf, sizeof (procbuf),
574 FALSE))
575 s = procbuf;
576 } else if (strcmp(namebuf, "CPU") == 0) {
577 if (cpu(procbuf, sizeof (procbuf)))
578 s = procbuf;
579 } else if (strcmp(namebuf, "HOST") == 0) {
580 (void) uname(&name);
581 s = name.nodename;
582 } else if (strcmp(namebuf, "KARCH") == 0) {
583 if (arch(procbuf, sizeof (procbuf),
584 TRUE))
585 s = procbuf;
586 } else if (strcmp(namebuf, "OSREL") == 0) {
587 (void) uname(&name);
588 s = name.release;
589 } else if (strcmp(namebuf, "OSNAME") == 0) {
590 (void) uname(&name);
591 s = name.sysname;
592 } else if (strcmp(namebuf, "OSVERS") == 0) {
593 (void) uname(&name);
594 s = name.version;
595 } else if (strcmp(namebuf, "NATISA") == 0) {
596 if (natisa(isaname, sizeof (isaname)))
597 s = isaname;
598 } else if (strcmp(namebuf, "PLATFORM") == 0) {
599 if (platform(procbuf, sizeof (procbuf)))
600 s = procbuf;
604 if (s) {
605 if ((int)((bp - buffp) + strlen(s)) < size) {
606 while (*s) {
607 *bp++ = *s++;
608 *bq++ = ' ';
610 } else {
612 * line too long...
614 return (1);
617 expand++;
618 continue;
621 * Since buffp needs to be null terminated, we need to
622 * check that there's still room in the buffer to
623 * place at least two more characters, *p and the
624 * terminating null.
626 if (bp - buffp == size - 1) {
628 * There was not enough room for at least two more
629 * characters, return with an error.
631 return (1);
634 * The total number of characters so far better be less
635 * than the size of buffer passed in.
637 *bp++ = *p++;
638 *bq++ = *q++;
641 if (!expand)
642 return (0);
643 *bp = '\0';
644 *bq = '\0';
646 * We know buffp/buffq will fit in pline/plineq since we
647 * processed at most size characters.
649 (void) strcpy(pline, buffp);
650 (void) strcpy(plineq, buffq);
652 return (0);
656 * Removes backslashes, quotes and brackets from the string "str"
657 * and returns the quoting information in "qbuf". Character is
658 * considered escaped when it is
660 * preceded with '\' e.g. \a
661 * within quotes e.g. "string"
662 * a ':' in brackets e.g. [an:ip:6::ad::d:re:s:s]
664 * original str: 'the "brown" f\ox said: [fe80::20a:e4ff:fe35:8b0d]'
665 * unquoted str: 'the brown fox said: [fe80::20a:e4ff:fe35:8b0d]'
666 * and the qbuf: ' ^^^^^ ^ ^^ ^ ^ ^ '
668 void
669 unquote(str, qbuf)
670 char *str, *qbuf;
672 register int escaped, inquote, inbracket, quoted;
673 register char *ip, *bp, *qp;
674 char buf[LINESZ];
676 escaped = inquote = inbracket = quoted = 0;
678 for (ip = str, bp = buf, qp = qbuf; *ip; ip++) {
679 if (!escaped) {
680 if (*ip == '\\') {
681 escaped = 1;
682 quoted++;
683 continue;
684 } else
685 if (*ip == '"') {
686 inquote = !inquote;
687 quoted++;
688 continue;
689 } else
690 if (*ip == '[') {
691 inbracket++;
692 quoted++;
693 } else
694 if (*ip == ']') {
695 if (inbracket > 0) inbracket--;
699 *bp++ = *ip;
700 *qp++ = (inquote || escaped) ? '^'
701 : ((inbracket && (*ip == ':')) ? '^' : ' ');
702 escaped = 0;
705 *bp = '\0';
706 *qp = '\0';
708 if (quoted)
709 (void) strcpy(str, buf);
713 * If str is enclosed in [brackets], trim them off.
715 void
716 unbracket(s)
717 char **s;
719 char *b = *s + strlen(*s) - 1;
721 if (*b == ']')
722 *b = '\0';
723 if (**s == '[')
724 (*s)++;
728 * Removes trailing spaces from string "s".
730 void
731 trim(s)
732 char *s;
734 char *p = &s[strlen(s) - 1];
736 while (p >= s && isspace(*(uchar_t *)p))
737 *p-- = '\0';
741 * try to allocate memory using malloc, if malloc fails, then flush the
742 * rddir caches, and retry. If the second allocation after the readdir
743 * caches have been flushed fails too, then return NULL to indicate
744 * memory could not be allocated.
746 char *
747 auto_rddir_malloc(unsigned nbytes)
749 char *p;
750 int again = 0;
752 if ((p = malloc(nbytes)) == NULL) {
754 * No memory, free rddir caches and try again
756 mutex_lock(&cleanup_lock);
757 cond_signal(&cleanup_start_cv);
758 if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
759 mutex_unlock(&cleanup_lock);
760 syslog(LOG_ERR, "auto_rddir_malloc interrupted\n");
761 } else {
762 mutex_unlock(&cleanup_lock);
763 again = 1;
767 if (again)
768 p = malloc(nbytes);
770 return (p);
774 * try to strdup a string, if it fails, then flush the rddir caches,
775 * and retry. If the second strdup fails, return NULL to indicate failure.
777 char *
778 auto_rddir_strdup(const char *s1)
780 char *s2;
781 int again = 0;
783 if ((s2 = strdup(s1)) == NULL) {
785 * No memory, free rddir caches and try again
787 mutex_lock(&cleanup_lock);
788 cond_signal(&cleanup_start_cv);
789 if (cond_wait(&cleanup_done_cv, &cleanup_lock)) {
790 mutex_unlock(&cleanup_lock);
791 syslog(LOG_ERR, "auto_rddir_strdup interrupted\n");
792 } else {
793 mutex_unlock(&cleanup_lock);
794 again = 1;
798 if (again)
799 s2 = strdup(s1);
801 return (s2);
805 * Returns a pointer to the entry corresponding to 'name' if found,
806 * otherwise it returns NULL.
808 struct dir_entry *
809 btree_lookup(struct dir_entry *head, char *name)
811 register struct dir_entry *p;
812 register int direction;
814 for (p = head; p != NULL; ) {
815 direction = strcmp(name, p->name);
816 if (direction == 0)
817 return (p);
818 if (direction > 0)
819 p = p->right;
820 else p = p->left;
822 return (NULL);
826 * Add entry to binary tree
827 * Duplicate entries are not added
829 void
830 btree_enter(struct dir_entry **head, struct dir_entry *ent)
832 register struct dir_entry *p, *prev = NULL;
833 register int direction;
835 ent->right = ent->left = NULL;
836 if (*head == NULL) {
837 *head = ent;
838 return;
841 for (p = *head; p != NULL; ) {
842 prev = p;
843 direction = strcmp(ent->name, p->name);
844 if (direction == 0) {
846 * entry already in btree
848 return;
850 if (direction > 0)
851 p = p->right;
852 else p = p->left;
854 assert(prev != NULL);
855 if (direction > 0)
856 prev->right = ent;
857 else prev->left = ent;
861 * If entry doesn't exist already, add it to the linear list
862 * after '*last' and to the binary tree list.
863 * If '*last == NULL' then the list is walked till the end.
864 * *last is always set to the new element after successful completion.
865 * if entry already exists '*last' is only updated if not previously
866 * provided.
869 add_dir_entry(char *name, struct dir_entry **list, struct dir_entry **last)
871 struct dir_entry *e, *l;
873 if ((*list != NULL) && (*last == NULL)) {
875 * walk the list to find last element
877 for (l = *list; l != NULL; l = l->next)
878 *last = l;
881 if (btree_lookup(*list, name) == NULL) {
883 * not a duplicate, add it to list
885 /* LINTED pointer alignment */
886 e = (struct dir_entry *)
887 auto_rddir_malloc(sizeof (struct dir_entry));
888 if (e == NULL)
889 return (ENOMEM);
890 (void) memset((char *)e, 0, sizeof (*e));
891 e->name = auto_rddir_strdup(name);
892 if (e->name == NULL) {
893 free(e);
894 return (ENOMEM);
896 e->next = NULL;
897 if (*list == NULL) {
899 * list is empty
901 *list = *last = e;
902 } else {
904 * append to end of list
906 assert(*last != NULL);
907 (*last)->next = e;
908 *last = e;
911 * add to binary tree
913 btree_enter(list, e);
915 return (0);
919 * Print trace output.
920 * Like fprintf(stderr, fmt, ...) except that if "id" is nonzero, the output
921 * is preceeded by the ID of the calling thread.
923 #define FMT_BUFSIZ 1024
925 void
926 trace_prt(int id, char *fmt, ...)
928 va_list args;
930 char buf[FMT_BUFSIZ];
932 if (id) {
933 (void) sprintf(buf, "t%u\t%s", thr_self(), fmt);
934 fmt = buf;
936 va_start(args, fmt);
937 (void) vfprintf(stderr, fmt, args);
938 va_end(args);
942 * Extract the isalist(5) for userland from the kernel.
944 static char *
945 isalist(void)
947 char *buf;
948 size_t bufsize = BUFSIZ; /* wild guess */
949 long ret;
951 buf = malloc(bufsize);
952 do {
953 ret = sysinfo(SI_ISALIST, buf, bufsize);
954 if (ret == -1l)
955 return (NULL);
956 if (ret > bufsize) {
957 bufsize = ret;
958 buf = realloc(buf, bufsize);
959 } else
960 break;
961 } while (buf != NULL);
963 return (buf);
967 * Classify isa's as to bitness of the corresponding ABIs.
968 * isa's which have no "official" system ABI are returned
969 * unrecognised i.e. zero bits.
971 static int
972 bitness(char *isaname)
974 if (strcmp(isaname, "sparc") == 0 ||
975 strcmp(isaname, "i386") == 0)
976 return (32);
978 if (strcmp(isaname, "sparcv9") == 0 ||
979 strcmp(isaname, "amd64") == 0)
980 return (64);
982 return (0);
986 * Determine the application architecture (derived from uname -m) to expand
987 * the $ARCH and $KARCH macros.
989 * Like arch(1), we need to substitute "sun4" for "sun4u", "sun4v", ... for
990 * backward compatibility. When kflag is set (like arch -k), the unmodifed
991 * value is returned instead.
993 static int
994 arch(char *buf, size_t bufsize, bool_t karch)
996 long ret;
998 ret = sysinfo(SI_MACHINE, buf, bufsize);
999 if (ret == -1L)
1000 return (0);
1001 if (!karch && strncmp(buf, "sun4", 4) == 0)
1002 (void) strlcpy(buf, "sun4", bufsize);
1003 return (1);
1007 * Determine the basic ISA (uname -p) to expand the $CPU macro.
1009 static int
1010 cpu(char *buf, size_t bufsize)
1012 long ret;
1014 ret = sysinfo(SI_ARCHITECTURE, buf, bufsize);
1015 if (ret == -1L)
1016 return (0);
1017 else
1018 return (1);
1022 * Find the left-most element in the isalist that matches our idea of a
1023 * system ABI.
1025 * On machines with only one ABI, this is usually the same as uname -p.
1027 static int
1028 natisa(char *buf, size_t bufsize)
1030 int bits;
1031 char *isa, *list;
1032 char *lasts;
1034 if ((list = isalist()) == NULL)
1035 return (0);
1037 for (isa = strtok_r(list, " ", &lasts);
1038 isa; isa = strtok_r(0, " ", &lasts))
1039 if ((bits = bitness(isa)) != 0)
1040 break; /* ignore "extension" architectures */
1042 if (isa == 0 || bits == 0) {
1043 free(list);
1044 return (0); /* can't figure it out :( */
1047 (void) strncpy(buf, isa, bufsize);
1048 free(list);
1050 return (1);
1054 * Determine the platform (uname -i) to expand the $PLATFORM macro.
1056 static int
1057 platform(char *buf, size_t bufsize)
1059 long ret;
1061 ret = sysinfo(SI_PLATFORM, buf, bufsize);
1062 if (ret == -1L)
1063 return (0);
1064 else
1065 return (1);
1069 * Set environment variables
1071 void
1072 put_automountd_env(void)
1074 char defval[PATH_MAX], *p, *a, *c;
1075 int ret = 0, bufsz = PATH_MAX;
1077 ret = autofs_smf_get_prop("environment", defval, DEFAULT_INSTANCE,
1078 SCF_TYPE_ASTRING, AUTOMOUNTD, &bufsz);
1079 if (ret == SA_OK) {
1080 a = c = defval;
1081 if (*a == NULL)
1082 return;
1084 * Environment variables can have more than one value
1085 * seperated by a comma and there can be multiple
1086 * environment variables. * a=b\,c,d=e. For multiple
1087 * valued environment variable, values are seperated
1088 * with an escape character.
1090 while ((p = strchr(c, ',')) != NULL) {
1091 if (*(p - 1) == '\\') {
1092 c = p + 1;
1093 continue;
1095 *p = '\0';
1096 if ((c = strchr(a, '=')) != NULL)
1097 putenv(strdup(a));
1098 a = c = p + 1;
1100 if (*a != NULL) {
1101 if ((c = strchr(a, '=')) != NULL)
1102 putenv(strdup(a));