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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
24 * All Rights reserved.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
31 */
32
33 /* LINTLIBRARY */
34
35 /*
36 * putdev.c
37 *
38 * Global Definitions:
39 * _adddevtabrec() Add a record to the device table
40 * _putdevtabrec() Write a record to the device table
41 * _moddevtabrec() Modify a device-table record
42 * _rmdevtabrec() Remove a device-table record
43 * _rmdevtabattrs() Remove attributes from a device-table record
44 * oam_devtab File descriptor of the open device table
45 */
46
47 /*
48 * G L O B A L R E F E R E N C E S
49 *
50 * Header Files
51 * Externals Referenced
52 */
53
54 /*
55 * Header Files
56 * <sys/types.h> UNIX(r) Data Types
57 * <sys/stat.h>
58 * <stdio.h> Standard I/O definitions
59 * <fcntl.h> Definitions for file control
60 * <errno.h> Error handling definitions
61 * <string.h> String Handling Definitions
62 * <devmgmt.h> Device Management Definitions
63 * <unistd.h> Get UNIX(r) Standard Definitions
64 * "devtab.h" Local Device Management Definitions
65 */
66
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <stdio.h>
70 #include <fcntl.h>
71 #include <errno.h>
72 #include <string.h>
73 #include <devmgmt.h>
74 #include <unistd.h>
75 #include <stdlib.h>
76 #include "devtab.h"
77
78 /*
79 * L O C A L D E F I N I T I O N S
80 *
81 * TDTABNM Name of the temporary device table (in the
82 * directory of the existing table)
83 */
84
85 #define TDTABNM "%sdevtab.%6.6d"
86
87
88 /*
89 * Static functions
90 * strcatesc Copies a character-string from one place to another
91 * escaping the appropriate characters
92 * lkdevtab Locks the device table
93 * unlkdevtab Unlocks the device table
94 * mkdevtabent Builds a device-table entry from the alias and the
95 * list of attr=val pairs given
96 * opennewdevtab Opens a new device table (as a temp file)
97 * mknewdevtab Makes the temp device table the new devtab
98 * rmnewdevtab Remove the temporary device table and free space
99 * allocated to the filename of that file.
100 */
101
102 static char *strcatesc(char *, char *);
103 static int lkdevtab(char *, short);
104 static int unlkdevtab(void);
105 static struct devtabent *mkdevtabent(char *, char **);
106 static FILE *opennewdevtab(char **);
107 static int mknewdevtab(char *);
108 static int rmnewdevtab(char *);
109
110 /*
111 * char *strcatesc(p, q)
112 * char *p
113 * char *q
114 *
115 * Write the character-string pointed to by "q" to the place
116 * pointed to by "p", escaping those characters in "q" found in the
117 * string "DTAB_ESCS" by preceding them with '\\'. Return a pointer to
118 * the byte beyond the last character written to "p".
119 *
120 * Arguments:
121 * p The place to begin writing to
122 * q The string to write
123 *
124 * Returns: char *
125 * The address of the byte beyond the last character written into "p"
126 */
127
128 static char *
strcatesc(char * p,char * q)129 strcatesc(
130 char *p, /* Place to write to */
131 char *q) /* Thing to write */
132 {
133 while (*q) {
134 if (strchr(DTAB_ESCS, *q)) *p++ = '\\';
135 *p++ = *q++;
136 }
137 return (p);
138 }
139
140 /*
141 * FILE *opennewdevtab(pname)
142 * char **pname
143 *
144 * Generates a temporary device-table name from the existing
145 * device table name (in the same directory) and opens that
146 * file for writing. It puts a pointer to the malloc()ed space
147 * containing the temp device table's name at the place referenced
148 * by <pname>.
149 *
150 * Arguments:
151 * pname Pointer to the char * to contain the address of the name
152 * of the temporary file
153 *
154 * Returns: FILE *
155 * A pointer to the opened stream or (FILE *) NULL if an error occurred.
156 * If an error occurred, "errno" will be set to reflect the problem.
157 */
158
159 static FILE *
opennewdevtab(char ** pname)160 opennewdevtab(char **pname) /* A(ptr to temp filename's path) */
161 {
162 char *oldname; /* Ptr to the device-table's name */
163 char *buf; /* Ptr to the temp file's name */
164 char *dirname; /* Directory containing devtab */
165 char *p; /* Ptr to last '/' in devtab name */
166 int fd; /* Opened file descriptor */
167 FILE *fp; /* Opened file pointer */
168 struct stat64 sbuf; /* stat buf for old devtab file */
169
170 fp = NULL;
171 if (oldname = _devtabpath()) {
172 /*
173 * It is possible for us to have sufficient permissions to create
174 * the new file without having sufficient permissions to write the
175 * original devtab file. For consistency with the operations which
176 * modify the original file by writing it directly we require write
177 * permissions for the original file in order to make a new one.
178 */
179 if ((fd = open(oldname, O_WRONLY)) == -1)
180 return (NULL);
181
182 if (fstat64(fd, &sbuf) == -1) {
183 (void) close(fd);
184 return (NULL);
185 }
186 (void) close(fd);
187
188 if (p = strrchr(oldname, '/')) {
189 *(p+1) = '\0';
190 dirname = oldname;
191 } else dirname = "./";
192 if (asprintf(&buf, TDTABNM, dirname, getpid()) >= 0) {
193
194 /*
195 * Build the name of the temp device table and
196 * open the file. We must reset the owner, group
197 * and perms to those of the original devtab file.
198 */
199 if (fp = fopen(buf, "w")) {
200 *pname = buf;
201 (void) fchmod(fileno(fp), sbuf.st_mode & 0777);
202 (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid);
203 } else {
204 free(buf);
205 }
206 }
207
208 /*
209 *
210 * Free the space containing the device table's name.
211 */
212 free(oldname);
213 }
214
215 /* Finished. Return what we've got */
216 return (fp);
217 }
218
219 /*
220 * int rmnewdevtab(tempname)
221 * char *tempname
222 *
223 * Unlink the temp device table and free the memory allocated to
224 * contain the name of that file
225 *
226 * Arguments:
227 * tempname Name of the temporary file
228 *
229 * Returns: int
230 * TRUE if successful, FALSE otherwise
231 */
232
233 static int
rmnewdevtab(char * tempname)234 rmnewdevtab(char *tempname) /* Filename of new device table */
235 {
236 int noerr; /* Flag, TRUE if no error, FALSE otherwise */
237
238 /* Unlink the file */
239 noerr = (unlink(tempname) == 0);
240
241 /* Free the space allocated to the filename */
242 free(tempname);
243
244 /* Return success indicator */
245 return (noerr);
246 }
247
248 /*
249 * int mknewdevtab(tempname)
250 * char *tempname
251 *
252 * Make the temporary device-table the new system device table
253 *
254 * Arguments:
255 * tempname Name of the temporary file
256 *
257 * Returns: int
258 * TRUE if successful, FALSE otherwise
259 *
260 * Notes:
261 * - Need to use rename() someday instead of link()/unlink()
262 * - This code is somewhat ineffecient in that asks for the name
263 * of the device-table more than once. Done so that we don't
264 * have to manage that space, but this may be somewhat lazy.
265 */
266
267 static int
mknewdevtab(char * tempname)268 mknewdevtab(char *tempname) /* Ptr to name of temp dev tab */
269 {
270 char *devtabname; /* Ptr to the device table's name */
271 int noerr; /* FLAG, TRUE if all's well */
272
273 /* Get the device table's pathname */
274 if (devtabname = _devtabpath()) {
275
276 /* Unlink the existing file */
277 if (unlink(devtabname) == 0) {
278
279 /* Make the temp file the real device table */
280 noerr = (link(tempname, devtabname) == 0) ? TRUE : FALSE;
281
282 /* Remove the temp file (and resources) */
283 if (noerr) (void) rmnewdevtab(tempname);
284
285 } else noerr = FALSE; /* unlink() failed */
286
287 /* Free the device table's name */
288 free(devtabname);
289
290 } else noerr = FALSE; /* devtabpath() failed */
291
292 /* Finished. Return success indicator */
293 return (noerr);
294 }
295
296 /*
297 * static int lkdevtab(o_mode, lktype)
298 * char *o_mode
299 * short lktype
300 *
301 * Lock the device table for writing. If it isn't available, it waits
302 * until it is.
303 *
304 * Arguments:
305 * o_mode The open() mode to use when opening the device table
306 * lktype The type of lock to apply
307 *
308 * Returns: int
309 * TRUE if successful, FALSE with errno set otherwise
310 */
311
312 static int
lkdevtab(char * o_mode,short lktype)313 lkdevtab(
314 char *o_mode, /* Open mode */
315 short lktype) /* Lock type */
316 {
317 /* Automatic data */
318 struct flock lockinfo; /* File locking structure */
319 int noerr; /* FLAG, TRUE if no error */
320 int olderrno; /* Old value of "errno" */
321
322
323 /* Close the device table (if it's open) */
324 _enddevtab();
325
326 /* Open the device table for read/append */
327 noerr = TRUE;
328 if (_opendevtab(o_mode)) {
329
330 /*
331 * Lock the device table (for writing). If it's not
332 * available, wait until it is, then close and open the
333 * table (modify and delete change the table!) and try
334 * to lock it again
335 */
336
337 /* Build the locking structure */
338 lockinfo.l_type = lktype;
339 lockinfo.l_whence = 0;
340 lockinfo.l_start = 0L;
341 lockinfo.l_len = 0L;
342 olderrno = errno;
343
344 /* Keep on going until we lock the file or an error happens */
345 while ((fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) == -1) &&
346 !noerr) {
347 if (errno == EACCES) {
348 if (fcntl(fileno(oam_devtab), F_SETLKW, &lockinfo) == -1)
349 noerr = FALSE;
350 else {
351 /* Reopen the file (maybe it's moved?) */
352 _enddevtab();
353 if (!_opendevtab(o_mode)) noerr = FALSE;
354 else errno = olderrno;
355 }
356 } else noerr = FALSE;
357 }
358
359 if (!noerr) _enddevtab(); /* Don't keep open if in error */
360
361 } else noerr = FALSE;
362
363 /* Done */
364 return (noerr);
365 }
366
367 /*
368 * int unlkdevtab()
369 *
370 * Unlock the locked device table.
371 *
372 * Arguments: None
373 *
374 * Returns: int
375 * Whatever fcntl() returns...
376 */
377
378 static int
unlkdevtab(void)379 unlkdevtab(void)
380 {
381 /* Automatic data */
382 struct flock lockinfo; /* Locking structure */
383 int noerr; /* FLAG, TRUE if all's well */
384
385 /* Build the locking structure */
386 lockinfo.l_type = F_UNLCK; /* Lock type */
387 lockinfo.l_whence = 0; /* Count from top of file */
388 lockinfo.l_start = 0L; /* From beginning */
389 lockinfo.l_len = 0L; /* Length of locked data */
390
391 /* Unlock it */
392 noerr = (fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) != -1);
393 _enddevtab();
394
395 /* Finished */
396 return (noerr);
397 }
398
399 /*
400 * struct devtabent *mkdevtabent(alias, attrlist)
401 * char *alias
402 * char **attrlist
403 *
404 * This function builds a struct devtabent structure describing the
405 * alias <alias> using the information in the attribute list <attrlist>.
406 * The <attrlist> contains data of the form attr=value where attr is
407 * the name of an attribute and value is the value of that attribute.
408 *
409 * Arguments:
410 * alias The alias being added to the device table
411 * attrlist The attributes and values for that alias
412 *
413 * Returns: struct devtabent *
414 * A completed struct devtabent structure containing the description
415 * of the alias. The structure, and all of the data in the structure
416 * are each in space allocated using the malloc() function and should
417 * be freed using the free() function (or the _freedevtabent() function).
418 *
419 * Errors:
420 * EINVAL If "alias" is used as an attribute in an attr=val pair
421 * EAGAIN If an attribute is specified more than once
422 */
423
424 static struct devtabent *
mkdevtabent(char * alias,char ** attrlist)425 mkdevtabent(
426 char *alias, /* Alias of entry */
427 char **attrlist) /* Attributes of new entry */
428 {
429 /* Automatic data */
430 struct devtabent *devtabent; /* * to struct we're making */
431 struct attrval *prevattrval; /* * to prev attr/val struct */
432 struct attrval *attrval; /* * to current struct */
433 char **pp; /* Ptr into list of ptrs */
434 char *peq; /* Ptr to '=' in string */
435 char *val; /* Ptr to space for value */
436 char *name; /* Ptr to space for name */
437 ssize_t len; /* Length of name */
438 int noerr; /* TRUE if all's well */
439 int found; /* TRUE the attr is found */
440
441
442 /* No problems (yet) */
443 noerr = TRUE;
444
445 /* Get space for the structure */
446 if (devtabent = malloc(sizeof (struct devtabent))) {
447
448 /* Fill in default values */
449 if (devtabent->alias = malloc(strlen(alias)+1)) {
450
451 (void) strcpy(devtabent->alias, alias); /* alias */
452 devtabent->comment = FALSE; /* data rec */
453 devtabent->cdevice = NULL; /* cdevice */
454 devtabent->bdevice = NULL; /* bdevice */
455 devtabent->pathname = NULL; /* pathname */
456 devtabent->attrstr = NULL; /* string */
457 devtabent->attrlist = NULL; /* attr list */
458
459 /* Add attributes to the structure */
460 prevattrval = NULL;
461 if ((pp = attrlist) != NULL)
462 while (*pp && noerr) {
463
464 /* Valid attr=value pair? */
465 if (((peq = strchr(*pp, '=')) != NULL) &&
466 ((len = peq - *pp) > 0)) {
467
468 /* Get space for the value */
469 if (val = malloc(strlen(peq))) {
470 (void) strcpy(val, peq+1); /* Copy it */
471
472 /* Get space for attribute name */
473 if (name = malloc((size_t)(len + 1))) {
474 (void) strncpy(name, *pp, (size_t)len);
475 *(name+len) = '\0';
476
477 /* Specifying the alias? If so, ERROR */
478 if (strcmp(name, DTAB_ALIAS) == 0) {
479 noerr = FALSE;
480 free(name);
481 free(val);
482 errno = EINVAL;
483 }
484
485 /* Specifying the char device path? */
486 else if (strcmp(name, DTAB_CDEVICE) == 0) {
487 if (!devtabent->cdevice) {
488 if (val[0] != '/') {
489 noerr = FALSE;
490 free(name);
491 free(val);
492 errno = ENXIO;
493 } else {
494 devtabent->cdevice = val;
495 free(name);
496 }
497 } else {
498 noerr = FALSE;
499 free(name);
500 free(val);
501 errno = EAGAIN;
502 }
503 }
504
505 /* Specifying the block device path? */
506 else if (strcmp(name, DTAB_BDEVICE) == 0) {
507 if (!devtabent->bdevice) {
508 if (val[0] != '/') {
509 noerr = FALSE;
510 free(name);
511 free(val);
512 errno = ENXIO;
513 } else {
514 devtabent->bdevice = val;
515 free(name);
516 }
517 } else {
518 noerr = FALSE;
519 free(name);
520 free(val);
521 errno = EAGAIN;
522 }
523 }
524
525 /* Specifying the pathname (generic)? */
526 else if (strcmp(name, DTAB_PATHNAME) == 0) {
527 if (!devtabent->pathname) {
528 if (val[0] != '/') {
529 noerr = FALSE;
530 free(name);
531 free(val);
532 errno = ENXIO;
533 } else {
534 devtabent->pathname = val;
535 free(name);
536 }
537 } else {
538 noerr = FALSE;
539 free(name);
540 free(val);
541 errno = EAGAIN;
542 }
543 }
544
545 /* Some other attribute */
546 else {
547 found = FALSE;
548 if ((attrval = devtabent->attrlist) != NULL)
549 do {
550 if (strcmp(attrval->attr,
551 name) == 0) {
552
553 noerr = FALSE;
554 free(name);
555 free(val);
556 errno = EAGAIN;
557 }
558 } while (!found && noerr &&
559 (attrval = attrval->next));
560
561 if (!found && noerr) {
562
563 /* Get space for attr/val structure */
564 if (attrval =
565 malloc(sizeof (struct attrval))) {
566
567 /* Fill attr/val structure */
568 attrval->attr = name;
569 attrval->val = val;
570 attrval->next = NULL;
571
572 /*
573 * Link into the list of attributes
574 */
575 if (prevattrval)
576 prevattrval->next = attrval;
577 else devtabent->attrlist = attrval;
578 prevattrval = attrval;
579
580 } else {
581 /* malloc() for attrval failed */
582 noerr = FALSE;
583 free(name);
584 free(val);
585 }
586 }
587 } /* End else (some other attribute) */
588
589 } else { /* malloc() for attribute name failed */
590 noerr = FALSE;
591 free(val);
592 }
593
594 } else noerr = FALSE; /* Malloc() for "val" failed */
595
596 /* If we saw an error, free structure, returning NULL */
597 if (!noerr) {
598 _freedevtabent(devtabent);
599 devtabent = NULL;
600 }
601
602 } /* Ignore invalid attr=val pair */
603
604 if (noerr) pp++;
605
606 } /* End attribute processing loop */
607
608 } else { /* malloc() failed */
609 free(devtabent);
610 devtabent = NULL;
611 }
612 }
613
614 /* Finished */
615 return (devtabent);
616 }
617
618 /*
619 * int _putdevtabrec(stream, rec)
620 * FILE *stream
621 * struct devtabent *rec
622 *
623 * Write a device table record containing the information in the struct
624 * devtab structure <rec> to the current position of the standard I/O
625 * stream <stream>.
626 *
627 * Arguments:
628 * stream The stream to write to
629 * rec The structure containing the information to write
630 *
631 * Returns: int
632 * The number of characters written or EOF if there was some error.
633 */
634
635 int
_putdevtabrec(FILE * stream,struct devtabent * rec)636 _putdevtabrec(
637 FILE *stream, /* Stream to which to write */
638 struct devtabent *rec) /* Record to write */
639 {
640 /* Automatic Data */
641 struct attrval *attrval; /* Ptr to attr/val pair */
642 char *buf; /* Allocated buffer */
643 char *p; /* Temp char pointer */
644 int count; /* Number of chars written */
645 size_t size = 0; /* Size of needed buffer */
646
647
648 /* Comment or data record? */
649 if (rec->comment) {
650
651 /*
652 * Record is a comment
653 */
654
655 /* Copy (escaping chars) record into temp buffer */
656 size = (strlen(rec->attrstr)*2)+1; /* Max rec size */
657 if (buf = malloc(size+1)) {
658 /* Alloc space */
659 p = strcatesc(buf, rec->attrstr); /* Copy "escaped" */
660 *(p-2) = '\n'; /* Unescape last \n */
661 *(p-1) = '\0'; /* Terminate string */
662
663 /* Write the record */
664 count = fputs(buf, stream);
665 free(buf);
666
667 } else count = EOF; /* malloc() failed */
668 }
669
670 else {
671
672 /*
673 * Record is a data record
674 */
675
676 /*
677 * Figure out maximum amount of space you're going to need.
678 * (Assume every escapable character is escaped to determine the
679 * maximum size needed)
680 */
681
682 if (rec->cdevice)
683 size += (strlen(rec->cdevice)*2) + 1; /* cdevice: */
684 if (rec->bdevice)
685 size += (strlen(rec->bdevice)*2) + 1; /* bdevice: */
686 if (rec->pathname)
687 size += (strlen(rec->pathname)*2) + 1; /* pathname: */
688 if ((attrval = rec->attrlist) != NULL) do { /* Attributes */
689 if (attrval->attr)
690 size += (strlen(attrval->attr)*2); /* attr */
691 if (attrval->val) {
692 /* val & '="" ' or val & '=""\n' */
693 size += (strlen(attrval->val)*2) +4;
694 }
695 } while ((attrval = attrval->next) != NULL); /* Next attr/val */
696 else size++; /* Else make room for trailing '\n' */
697
698 /* Alloc space for "escaped" record */
699 if (buf = malloc(size+1)) {
700
701 /* Initializations */
702 p = buf;
703
704 /* Write the alias ("alias" attribute) */
705 p = strcatesc(p, rec->alias);
706 *p++ = ':';
707
708 /* Write the character device ("cdevice" attribute) */
709 if (rec->cdevice) p = strcatesc(p, rec->cdevice);
710 *p++ = ':';
711
712 /* Write the block device ("bdevice" attribute) */
713 if (rec->bdevice) p = strcatesc(p, rec->bdevice);
714 *p++ = ':';
715
716 /* Write the pathname ("pathname" attribute) */
717 if (rec->pathname) p = strcatesc(p, rec->pathname);
718 *p++ = ':';
719
720 /* Write the rest of the attributes */
721 if ((attrval = rec->attrlist) != NULL)
722 do {
723 p = strcatesc(p, attrval->attr);
724 *p++ = '=';
725 *p++ = '"';
726 p = strcatesc(p, attrval->val);
727 *p++ = '"';
728 if ((attrval = attrval->next) != NULL)
729 *p++ = ' ';
730 } while (attrval);
731
732 /* Terminate the record */
733 *p++ = '\n';
734 *p = '\0';
735
736 /* Write the record */
737 count = fputs(buf, stream);
738 free(buf);
739 } else count = EOF; /* malloc() failed */
740 }
741
742 /* Finished */
743 return (count);
744 }
745
746 /*
747 * int _adddevtabrec(alias, attrval)
748 * char *alias
749 * char **attrval
750 *
751 * This function adds a record to the device table. That record will
752 * have the alias <alias> and will have the attributes described in
753 * the list referenced by <attrval>.
754 *
755 * It always adds the record to the end of the table.
756 *
757 * Arguments:
758 * alias The alias of the device whose description is being
759 * added to the device table.
760 * attrval The pointer to the first item of a list of attributes
761 * defining the device whose description is being added.
762 * (This value may be (char **) NULL).
763 *
764 * Returns: int
765 * TRUE if successful, FALSE with errno set otherwise.
766 */
767
768 int
_adddevtabrec(char * alias,char ** attrval)769 _adddevtabrec(
770 char *alias, /* Alias to add to the device table */
771 char **attrval) /* Attributes for that device */
772 {
773 /* Automatic data */
774 struct devtabent *devtabent; /* Ptr to dev tab entry */
775 int olderrno; /* Errno on entry */
776 int noerr; /* FLAG, TRUE if all's well */
777
778 /* Validate the device alias. Error (EINVAL) if it's not valid */
779 if (!_validalias(alias)) {
780 errno = EINVAL;
781 return (FALSE);
782 }
783
784 /*
785 * Lock the device table. This only returns if the table is locked or
786 * some error occurred. It waits until the table is available.
787 */
788 if (!lkdevtab("a+", F_WRLCK))
789 return (FALSE);
790
791 /* Make sure that the alias isn't already in the table */
792 noerr = TRUE;
793 olderrno = errno;
794 if (devtabent = _getdevrec(alias)) {
795
796 /* The alias is already in the table */
797 _freedevtabent(devtabent); /* Free device table info */
798 errno = EEXIST; /* Set errno, entry exists */
799 noerr = FALSE; /* All's not well */
800 } else if ((errno == ENOENT) || (errno == ENODEV)) {
801
802 /* The alias wasn't in the table or there wasn't a table. */
803
804 errno = olderrno; /* Reset errno */
805
806 /* Build a struct devtabent that describes the new alias */
807 if (devtabent = mkdevtabent(alias, attrval)) {
808
809 /* Position to the end of the existing table */
810 if (fseek(oam_devtab, 0, SEEK_END) == 0)
811
812 /* Write the new entry */
813 noerr = (_putdevtabrec(oam_devtab, devtabent) != EOF);
814
815 /* Free the info we just wrote */
816 _freedevtabent(devtabent);
817
818 } else noerr = FALSE; /* mkdevtabent() failed */
819 } else noerr = FALSE; /* Some odd error, _devtab */
820
821 /* Unlock and close the device table */
822 (void) unlkdevtab();
823
824 /* Fini */
825 return (noerr);
826 }
827
828 /*
829 * int _moddevtabrec(device, attrval)
830 * char *device
831 * char **attrval
832 *
833 * This function modifies the description for the specified device
834 * so that it has the attributes and values as specified in the
835 * given list.
836 *
837 * Arguments:
838 * device The name of the device whose description
839 * is being modified
840 * attrval The first attr/val value in the list (attr=val) of
841 * the attributes that are to change
842 *
843 * Returns: int
844 * TRUE if all went well, FALSE with errno set otherwise
845 */
846
847 int
_moddevtabrec(char * device,char ** attrval)848 _moddevtabrec(
849 char *device, /* Device to modify */
850 char **attrval) /* Attributes to add or change */
851 {
852 /* Automatic data */
853 FILE *fd; /* File ptr, new device table */
854 struct devtabent *ent; /* Device's current description */
855 struct devtabent *chg; /* Changes to make to description */
856 struct attrval *new; /* New attribute/value desc */
857 struct attrval *old; /* Old attribute/value desc */
858 struct attrval *newnew; /* Next "new" value to look at */
859 struct attrval *prevnew; /* Previous item in the 'new' list */
860 char *tname; /* name of temp devtab file */
861 int noerr; /* FLAG, TRUE if all's well */
862 int found; /* FLAG, TRUE if attr found for dev */
863
864 /* Lock the device table */
865 if (!lkdevtab("r", F_WRLCK))
866 return (FALSE);
867
868 /* No problems (so far) */
869 noerr = TRUE;
870
871 /* Get the entry to modify */
872 if (ent = _getdevrec(device)) {
873
874 /* Build a structure describing the changes */
875 if (chg = mkdevtabent(device, attrval)) {
876
877 /* If the "cdevice" field is specified, change it */
878 if (chg->cdevice) {
879 if (ent->cdevice) free(ent->cdevice);
880 ent->cdevice = chg->cdevice;
881 chg->cdevice = NULL;
882 }
883
884 /* If the "bdevice" field is specified, change it */
885 if (chg->bdevice) {
886 if (ent->bdevice) free(ent->bdevice);
887 ent->bdevice = chg->bdevice;
888 chg->bdevice = NULL;
889 }
890
891 /* If the "pathname" field is specified, change it */
892 if (chg->pathname) {
893 if (ent->pathname) free(ent->pathname);
894 ent->pathname = chg->pathname;
895 chg->pathname = NULL;
896 }
897
898 /* Change the other attributes (if any) */
899 if (ent->attrlist) {
900 prevnew = NULL;
901 if ((new = chg->attrlist) != NULL) do {
902
903 found = FALSE;
904 for (old = ent->attrlist; !found && old;
905 old = old->next) {
906 if (strcmp(old->attr, new->attr) == 0) {
907 found = TRUE;
908 free(old->val);
909 old->val = new->val;
910 new->val = NULL;
911 }
912 } /* Loop through the existing attribute list */
913
914 /*
915 * If the attribute wasn't found, add it to the list
916 * of attributes for the device. If it was found, just
917 * bump to the next one and look for it
918 */
919
920 if (!found) {
921
922 /*
923 * Not found. Move attr/val description to the
924 * device's list of attributes
925 */
926
927 if (prevnew) prevnew->next = new->next;
928 else chg->attrlist = new->next;
929 newnew = new->next;
930 new->next = ent->attrlist;
931 ent->attrlist = new;
932 new = newnew;
933 } else {
934
935 /* Attribute changed, bump to the next one */
936 prevnew = new;
937 new = new->next;
938 }
939 } while (new); /* Loop for each attr to add or modify */
940
941 } else {
942
943 /* Device had no attributes -- add entire list */
944 ent->attrlist = chg->attrlist;
945 chg->attrlist = NULL;
946 }
947
948 /* Free the structure containing the changes */
949 _freedevtabent(chg);
950
951 } else noerr = FALSE; /* Couldn't build changes struct */
952
953 /* If there hasn't been an error (so far), write the new record */
954 if (noerr) {
955
956 /* Open the new device table */
957 if (fd = opennewdevtab(&tname)) {
958
959 /*
960 * For each entry in the existing table, write that entry
961 * to the new table. If the entry is the one being
962 * modified, write the modified entry instead of the
963 * original entry.
964 */
965
966 _setdevtab(); /* Rewind existing table */
967 chg = ent; /* Remember new record */
968 while (((ent = _getdevtabent()) != NULL) && noerr) {
969 if (ent->entryno != chg->entryno)
970 noerr = _putdevtabrec(fd, ent) != EOF;
971 else noerr = _putdevtabrec(fd, chg) != EOF;
972 _freedevtabent(ent);
973 }
974
975 /*
976 * If we successfully generated the new table, make it the
977 * new system device table. Otherwise, just remove the
978 * temporary file we've created.
979 */
980
981 if (noerr) {
982 (void) fclose(fd);
983 noerr = mknewdevtab(tname);
984 } else {
985 (void) fclose(fd);
986 (void) rmnewdevtab(tname);
987 }
988
989 /* Free the changed device structure */
990 _freedevtabent(chg);
991
992 } /* if (_opennewdevtab()) */
993 else noerr = FALSE;
994
995 } else _freedevtabent(ent); /* if (noerr) */
996
997 } else noerr = FALSE; /* Device not found? */
998
999 /* Finished. Unlock the device table and quit */
1000 (void) unlkdevtab();
1001 return (noerr);
1002 }
1003
1004 /*
1005 * int _rmdevtabrec(device)
1006 * char *device
1007 *
1008 * This function removes the record in the device table for the specified
1009 * device.
1010 *
1011 * Arguments:
1012 * device The device (alias, cdevice, bdevice, pathname, or link to one)
1013 * whose entry is to be removed
1014 *
1015 * Returns: int
1016 * Success indicator: TRUE if successful, FALSE with errno set otherwise.
1017 */
1018
1019 int
_rmdevtabrec(char * device)1020 _rmdevtabrec(char *device) /* Device to remove */
1021 {
1022 struct devtabent *rment;
1023 struct devtabent *devtabent;
1024 char *tempname;
1025 FILE *fd;
1026 int noerr;
1027
1028 if (!lkdevtab("r", F_WRLCK))
1029 return (FALSE);
1030 noerr = TRUE;
1031 if (rment = _getdevrec(device)) {
1032 if (fd = opennewdevtab(&tempname)) {
1033 _setdevtab();
1034 while (((devtabent = _getdevtabent()) != NULL) && noerr) {
1035 if (devtabent->entryno != rment->entryno)
1036 noerr = _putdevtabrec(fd, devtabent) != EOF;
1037 _freedevtabent(devtabent);
1038 }
1039 if (noerr) {
1040 (void) fclose(fd);
1041 noerr = mknewdevtab(tempname);
1042 } else {
1043 (void) fclose(fd);
1044 (void) rmnewdevtab(tempname);
1045 }
1046 } else noerr = FALSE;
1047 _freedevtabent(rment);
1048 } else noerr = FALSE;
1049 (void) unlkdevtab();
1050 return (noerr);
1051 }
1052
1053 /*
1054 * int _rmdevtabattrs(device, attributes, notfounds)
1055 * char *device
1056 * char **attributes
1057 * char ***notfounds
1058 *
1059 * Remove the specified attributes from the specified device. The
1060 * device is specified by <device>, <attributes> is the address of
1061 * the first char * in the list of char * pointing to the attributes
1062 * to remove from the device, and <notfounds> is the address of a
1063 * char ** to put the address of the first element in the malloc()ed
1064 * list of (char *) pointing to requested attributes that were not
1065 * defined for the device <device>.
1066 *
1067 * Arguments:
1068 * device The device from which attributes are to be removed
1069 * attributes The address of the first element in the list of
1070 * attributes to remove. This list is terminated by
1071 * (char *) NULL.
1072 * notfounds The place to put the address of the list of addresses
1073 * referencing the requested attributes that are not
1074 * defined for the specified device.
1075 *
1076 * Returns: int
1077 * TRUE if successful, FALSE with errno set otherwise.
1078 *
1079 * Notes:
1080 * - "alias" may not be undefined
1081 * - "cdevice", "bdevice", and "pathname" are made "null", not really
1082 * undefined
1083 */
1084
1085 int
_rmdevtabattrs(char * device,char ** attributes,char *** notfounds)1086 _rmdevtabattrs(
1087 char *device, /* Device to modify */
1088 char **attributes, /* Attributes to remove */
1089 char ***notfounds) /* Attributes req'd but not found */
1090 {
1091 /* Automatics */
1092 char **pnxt; /* Ptr to next attribute */
1093 char **pp; /* Ptr to current attr name */
1094 struct devtabent *modent; /* Entry being modified */
1095 struct devtabent *devtabent; /* Entry being copied */
1096 struct attrval *attrval; /* Ptr to attr/val desc */
1097 struct attrval *prevattrval; /* Ptr to prev attr/val */
1098 FILE *fd; /* File desc, temp file */
1099 char *tempname; /* Name of temp file */
1100 int nattrs; /* Number of attrs to remove */
1101 int nobaderr; /* TRUE if no fatal error */
1102 int noerr; /* TRUE if no non-fatal error */
1103 int found; /* TRUE if attribute found */
1104 int nonotfounds; /* TRUE if no attrs not fount */
1105
1106
1107 /* Initializations */
1108 nobaderr = TRUE;
1109 noerr = TRUE;
1110
1111 /* Count attributes to remove -- make sure "alias" isn't specified */
1112 for (pp = attributes, nattrs = 0; *pp; pp++, nattrs++)
1113 if (strcmp(*pp, DTAB_ALIAS) == 0) {
1114 *notfounds = NULL;
1115 errno = EINVAL;
1116 return (FALSE);
1117 }
1118
1119 /* Lock the device table */
1120 if (!lkdevtab("r", F_WRLCK))
1121 return (FALSE);
1122
1123 /* Is there a record for the requested device? */
1124 if (modent = _getdevrec(device)) {
1125
1126 /* Record found. Try to modify it */
1127 nonotfounds = TRUE;
1128
1129 /* For each of the attributes in the attribute list ... */
1130 for (pp = attributes; nobaderr && *pp; pp++) {
1131
1132 /*
1133 * Modify the device description, removing the requested
1134 * attributes from the structure
1135 */
1136
1137 found = FALSE; /* Not found yet */
1138
1139 /* If it's the "cdevice" attribute, make it a null-string */
1140 if (strcmp(*pp, DTAB_CDEVICE) == 0) {
1141 if (modent->cdevice) {
1142 free(modent->cdevice);
1143 modent->cdevice = NULL;
1144 }
1145 found = TRUE;
1146 }
1147
1148 /* If it's the "bdevice" attribute, make it a null-string */
1149 else if (strcmp(*pp, DTAB_BDEVICE) == 0) {
1150 if (modent->bdevice) {
1151 free(modent->bdevice);
1152 modent->bdevice = NULL;
1153 }
1154 found = TRUE;
1155 }
1156
1157 /* If it's the "pathname" attribute, make it a null-string */
1158 else if (strcmp(*pp, DTAB_PATHNAME) == 0) {
1159 if (modent->pathname) {
1160 free(modent->pathname);
1161 modent->pathname = NULL;
1162 }
1163 found = TRUE;
1164 }
1165
1166 /* Must be one of the other "auxilliary" attributes */
1167 else {
1168
1169 /* Search the attribute list for the attribute */
1170 prevattrval = NULL;
1171 if ((attrval = modent->attrlist) != NULL) do {
1172 if (strcmp(*pp, attrval->attr) == 0) {
1173
1174 /* Found. Remove from attribute list */
1175 found = TRUE;
1176 free(attrval->attr);
1177 free(attrval->val);
1178 if (prevattrval) {
1179 prevattrval->next = attrval->next;
1180 free(attrval);
1181 attrval = prevattrval->next;
1182 } else {
1183 modent->attrlist = attrval->next;
1184 free(attrval);
1185 attrval = modent->attrlist;
1186 }
1187 } else {
1188 prevattrval = attrval; /* Advance to next */
1189 attrval = attrval->next;
1190 }
1191 } while (!found && attrval);
1192
1193 } /* End attribute search loop */
1194
1195 /*
1196 * If the requested attribute wasn't defined for the device,
1197 * put it in the list of attributes not found
1198 */
1199
1200 if (!found) {
1201
1202 /*
1203 * If there's no list (yet), alloc enough space for
1204 * the list
1205 */
1206
1207 if (nonotfounds)
1208 if (*notfounds = malloc(sizeof (char **)*(nattrs+1))) {
1209
1210 /* List allocated -- put in the first entry */
1211 nonotfounds = FALSE;
1212 pnxt = *notfounds;
1213 if (*pnxt = malloc(strlen(*pp)+1)) {
1214 errno = EINVAL;
1215 noerr = FALSE;
1216 (void) strcpy(*pnxt++, *pp);
1217 } else {
1218 /* malloc() failed, free list */
1219 free(*notfounds);
1220 *notfounds = NULL;
1221 nonotfounds = TRUE;
1222 nobaderr = FALSE;
1223 }
1224
1225 } else nobaderr = FALSE; /* malloc() failed */
1226
1227 else {
1228 /* Already a list, add this attribute to it */
1229 if (*pnxt = malloc(strlen(*pp)+1))
1230 (void) strcpy(*pnxt++, *pp);
1231 else {
1232 /* Out of memory, clean up */
1233 for (pnxt = *notfounds; *pnxt; pnxt++)
1234 free(*pnxt);
1235 free(*notfounds);
1236 *notfounds = NULL;
1237 nonotfounds = TRUE;
1238 nobaderr = FALSE;
1239 }
1240 }
1241
1242 } /* end if (!found) */
1243
1244 /* Terminate the not-found list */
1245 if (!nonotfounds) *pnxt = NULL;
1246
1247 } /* end (for each attribute in attribute list) loop */
1248
1249
1250 /*
1251 * If we haven't seen any problems so far,
1252 * write the new device table
1253 */
1254
1255 if (nobaderr) {
1256
1257 /* Open the new device table */
1258 if (fd = opennewdevtab(&tempname)) {
1259
1260 /*
1261 * For each entry in the existing table, write that entry
1262 * to the new table. If the entry is the one being
1263 * modified, write the modified entry instead of the
1264 * original entry.
1265 */
1266
1267 _setdevtab(); /* Rewind existing table */
1268 while (((devtabent = _getdevtabent()) != NULL) &&
1269 nobaderr) {
1270
1271 if (devtabent->entryno != modent->entryno)
1272 nobaderr = _putdevtabrec(fd, devtabent) != EOF;
1273 else nobaderr = _putdevtabrec(fd, modent) != EOF;
1274 _freedevtabent(devtabent);
1275 }
1276
1277 /*
1278 * If we successfully generated the new table, make it the
1279 * new system device table. Otherwise, just remove the
1280 * temporary file we've created.
1281 */
1282
1283 if (nobaderr) {
1284 (void) fclose(fd);
1285 nobaderr = mknewdevtab(tempname);
1286 } else {
1287 (void) fclose(fd);
1288 (void) rmnewdevtab(tempname);
1289 }
1290
1291 } /* if (_opennewdevtab()) */
1292 else nobaderr = FALSE;
1293
1294 /*
1295 * If there was some error, we need to clean up
1296 * allocated resources
1297 */
1298 if (!nobaderr && !nonotfounds) {
1299 for (pnxt = *notfounds; *pnxt; pnxt++)
1300 free(*pnxt);
1301 free(*notfounds);
1302 *notfounds = NULL;
1303 nonotfounds = TRUE;
1304 }
1305
1306 } /* if (nobaderr) */
1307
1308 /* Free the resources alloc'ed for <device>'s entry */
1309 _freedevtabent(modent);
1310
1311 } else {
1312 /* _getdevrec(device) failed */
1313 nobaderr = FALSE;
1314 *notfounds = NULL;
1315 }
1316
1317 /* Unlock the device table */
1318 (void) unlkdevtab();
1319
1320 /* We're finished */
1321 return (noerr && nobaderr);
1322 }
1323