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 /* 23 * Copyright (c) 2017 Peter Tribble. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 32 /* All Rights Reserved */ 33 34 #ifndef _PKGLIB_H 35 #define _PKGLIB_H 36 37 38 #ifdef __cplusplus 39 extern "C" { 40 #endif 41 42 #include <sys/types.h> 43 #include <limits.h> 44 #include <stdio.h> 45 #include <pkgdev.h> 46 #include <pkgstrct.h> 47 #include "cfext.h" 48 49 /* 50 * The contents database file interface. 51 */ 52 53 typedef struct pkg_server *PKGserver; 54 55 /* Some commands modify the internal database: add them here */ 56 #define PKG_WRITE_COMMAND(cmd) ((cmd) == PKG_ADDLINES) 57 58 #define PKG_EXIT 0x0 59 #define PKG_FINDFILE 0x1 60 #define PKG_DUMP 0x2 61 #define PKG_PKGSYNC 0x3 62 #define PKG_FILTER 0x4 63 #define PKG_ADDLINES 0x5 64 #define PKG_NOP 0x6 65 66 #define SUNW_PKG_SERVERMODE "SUNW_PKG_SERVERMODE" 67 68 #define PKGSERV_MODE "pkg-server-mode=" 69 #define PKGSERV_MODE_LEN (sizeof (PKGSERV_MODE) - 1) 70 71 #define MODE_PERMANENT "permanent" 72 #define MODE_RUN_ONCE "run_once" 73 #define MODE_TIMEOUT "timeout" 74 75 #define MAXLOGFILESIZE (20 * 1024 * 1024) 76 77 #define PKGLOG "pkglog" 78 #define PKGDOOR ".door" 79 80 typedef enum { 81 INVALID, /* Not initialized */ 82 NEVER, /* Don't start, does check if it is running. */ 83 FLUSH_LOG, /* Run it once to incorporate the log. */ 84 RUN_ONCE, /* Run until the current client stops. */ 85 TIMEOUT, /* Run until a timeout occurs. */ 86 PERMANENT, /* Run until it is externally terminated. */ 87 DEFAULTMODE = TIMEOUT /* The default mode, must come last */ 88 } start_mode_t; 89 90 typedef struct pkgcmd { 91 int cmd; 92 char buf[1]; 93 } pkgcmd_t; 94 95 typedef struct pkgfilter { 96 int cmd; 97 int len; 98 char buf[1]; 99 } pkgfilter_t; 100 101 /* 102 * Virtual File Protocol definitions 103 */ 104 105 /* 106 * flags associated with virtual file protocol operations; note that these flags 107 * may only occupy the low order 16 bits of the 32-bit unsigned flag. 108 */ 109 110 typedef unsigned long VFPFLAGS_T; 111 112 #define VFP_NONE 0x00000000 /* no special flags */ 113 #define VFP_NEEDNOW 0x00000001 /* need memory now */ 114 #define VFP_SEQUENTIAL 0x00000002 /* sequential access */ 115 #define VFP_RANDOM 0x00000004 /* random access */ 116 #define VFP_NOMMAP 0x00000008 /* do not use mmap to access file */ 117 #define VFP_NOMALLOC 0x00000010 /* do not use malloc to buffer file */ 118 119 /* virtual file protocol object */ 120 121 typedef struct _vfp VFP_T; 122 123 /* structure behind the virtual file protocol object */ 124 125 struct _vfp { 126 FILE *_vfpFile; /* -> opened FILE */ 127 char *_vfpCurr; /* -> current byte to read/write */ 128 char *_vfpHighWater; /* -> last byte modified */ 129 char *_vfpEnd; /* -> last data byte */ 130 char *_vfpPath; /* -> path associated with FILE */ 131 char *_vfpStart; /* -> first data byte */ 132 void *_vfpExtra; /* undefined */ 133 size_t _vfpSize; /* size of mapped/allocated area */ 134 size_t _vfpMapSize; /* # mapped bytes */ 135 VFPFLAGS_T _vfpFlags; /* flags associated with vfp/data */ 136 int _vfpOverflow; /* non-zero if buffer write overflow */ 137 blkcnt_t _vfpCkStBlocks; /* checkpoint # blocks */ 138 dev_t _vfpCkDev; /* checkpoint device i.d. */ 139 ino_t _vfpCkIno; /* checkpoint inode # */ 140 off_t _vfpCkSize; /* checkpoint size */ 141 time_t _vfpCkMtime; /* checkpoint modification time */ 142 }; 143 144 /* 145 * get highest modified byte (length) contained in vfp 146 * 147 * determine number of bytes to write - it will be the highest of: 148 * -- the current pointer into the file - this is updated whenever 149 * the location of the file is changed by a single byte 150 * -- the last "high water mark" - the last known location that 151 * was written to the file - updated only when the location 152 * of the file is directly changed - e.g. vfpSetCurrCharPtr, 153 * vfpTruncate, vfpRewind. 154 * this reduces the "bookkeeping" that needs to be done to know 155 * how many bytes to write out to the file - typically a file is 156 * written sequentially so the current file pointer is sufficient 157 * to determine how many bytes to write out. 158 */ 159 160 #define vfpGetModifiedLen(VFP) \ 161 (size_t)(((VFP)->_vfpHighWater > (VFP)->_vfpCurr) ? \ 162 (((ptrdiff_t)(VFP)->_vfpHighWater - \ 163 (ptrdiff_t)(VFP)->_vfpStart)) : \ 164 (((ptrdiff_t)(VFP)->_vfpCurr - \ 165 (ptrdiff_t)(VFP)->_vfpStart))) 166 167 /* 168 * increment current pointer by specified delta 169 * if the delta exceeds the buffer size, set pointer to buffer end 170 */ 171 #define vfpIncCurrPtrBy(VFP, INC) \ 172 { \ 173 ((VFP)->_vfpCurr) += (INC); \ 174 if (((VFP)->_vfpCurr) > ((VFP)->_vfpEnd)) { \ 175 (VFP)->_vfpCurr = (VFP)->_vfpEnd; \ 176 (VFP)->_vfpOverflow = 1; \ 177 } \ 178 if ((VFP)->_vfpHighWater < (VFP)->_vfpCurr) { \ 179 (VFP)->_vfpHighWater = (VFP)->_vfpCurr; \ 180 } \ 181 } 182 183 /* get the path associated with the vfp */ 184 #define vfpGetPath(VFP) ((VFP)->_vfpPath) 185 186 /* get a string from the vfp into a fixed size buffer */ 187 #define vfpGets(VFP, PTR, LEN) \ 188 { \ 189 char *XXpXX = (PTR); \ 190 size_t XXlXX = (LEN); \ 191 while ((*(VFP)->_vfpCurr != '\0') && \ 192 (*(VFP)->_vfpCurr != '\n')) { \ 193 if (XXlXX > 1) { \ 194 *XXpXX++ = *(VFP)->_vfpCurr; \ 195 XXlXX--; \ 196 } \ 197 (VFP)->_vfpCurr++; \ 198 } \ 199 *XXpXX++ = '\0'; \ 200 if (*(VFP)->_vfpCurr != '\0') { \ 201 (VFP)->_vfpCurr++; \ 202 } \ 203 } 204 205 /* get number of bytes remaining to read */ 206 #define vfpGetBytesRemaining(VFP) \ 207 (((((VFP)->_vfpHighWater) <= ((VFP)->_vfpCurr))) ? 0 : \ 208 ((((ptrdiff_t)(VFP)->_vfpHighWater)-((ptrdiff_t)(VFP)->_vfpCurr)))) 209 210 /* get number of bytes remaining to write */ 211 #define vfpGetBytesAvailable(VFP) \ 212 (((((VFP)->_vfpEnd) <= ((VFP)->_vfpCurr))) ? 0 : \ 213 ((((ptrdiff_t)(VFP)->_vfpEnd)-((ptrdiff_t)(VFP)->_vfpCurr)))) 214 215 /* put current character and increment to next */ 216 #define vfpPutc(VFP, C) \ 217 { \ 218 (*(VFP)->_vfpCurr) = ((char)(C)); \ 219 vfpIncCurrPtrBy((VFP), 1); \ 220 } 221 222 /* put integer to current character and increment */ 223 #define vfpPutInteger(VFP, NUMBER) vfpPutFormat((VFP), "%d", (NUMBER)) 224 225 /* put long to current character and increment */ 226 #define vfpPutLong(VFP, NUMBER) vfpPutFormat((VFP), "%ld", (NUMBER)) 227 228 /* get current character and increment to next */ 229 #define vfpGetc(VFP) (*(VFP)->_vfpCurr++) 230 231 /* get current character - do not increment */ 232 #define vfpGetcNoInc(VFP) (*(VFP)->_vfpCurr) 233 234 /* get pointer to current character */ 235 #define vfpGetCurrCharPtr(VFP) ((VFP)->_vfpCurr) 236 237 /* increment current character pointer */ 238 #define vfpIncCurrPtr(VFP) vfpIncCurrPtrBy((VFP), 1) 239 240 /* decrement current character pointer */ 241 #define vfpDecCurrPtr(VFP) ((VFP)->_vfpCurr--) 242 243 /* get pointer to first data byte in buffer */ 244 #define vfpGetFirstCharPtr(VFP) ((VFP)->_vfpStart) 245 246 /* get pointer to last data byte in buffer */ 247 #define vfpGetLastCharPtr(VFP) ((VFP)->_vfpHighWater) 248 249 /* set pointer to current character */ 250 #define vfpSetCurrCharPtr(VFP, PTR) \ 251 if ((VFP)->_vfpCurr > (VFP)->_vfpHighWater) { \ 252 (VFP)->_vfpHighWater = (VFP)->_vfpCurr; \ 253 } \ 254 ((VFP)->_vfpCurr = (PTR)) 255 256 /* set pointer to last data byte in buffer */ 257 #define vfpSetLastCharPtr(VFP, PTR) \ 258 if ((PTR) >= (VFP)->_vfpStart) { \ 259 (VFP)->_vfpHighWater = (PTR); \ 260 if ((VFP)->_vfpCurr > (VFP)->_vfpHighWater) { \ 261 (VFP)->_vfpCurr = (VFP)->_vfpHighWater; \ 262 } \ 263 } 264 265 /* seek to end of file - one past last data byte in file */ 266 #define vfpSeekToEnd(VFP) ((VFP)->_vfpCurr = ((VFP)->_vfpHighWater)+1) 267 268 /* get number of bytes between current char and specified char */ 269 #define vfpGetCurrPtrDelta(VFP, P) \ 270 (((ptrdiff_t)(P))-((ptrdiff_t)(VFP)->_vfpCurr)) 271 272 /* put string to current character and increment */ 273 #define vfpPuts(VFP, S) \ 274 { \ 275 size_t xxLen; \ 276 size_t xxResult; \ 277 xxLen = vfpGetBytesAvailable((VFP)); \ 278 xxResult = strlcpy(((VFP)->_vfpCurr), (S), xxLen); \ 279 vfpIncCurrPtrBy((VFP), xxResult); \ 280 } 281 282 /* put fixed number of bytes to current character and increment */ 283 #define vfpPutBytes(VFP, PTR, LEN) \ 284 { \ 285 size_t xxLen; \ 286 xxLen = vfpGetBytesAvailable((VFP)); \ 287 if (xxLen > (LEN)) { \ 288 xxLen = (LEN); \ 289 } else { \ 290 (VFP)->_vfpOverflow = 1; \ 291 } \ 292 memcpy((VFP)->_vfpCurr, (PTR), (xxLen)); \ 293 vfpIncCurrPtrBy((VFP), (xxLen)); \ 294 } 295 296 /* put format one arg to current character and increment */ 297 #define vfpPutFormat(VFP, FORMAT, ARG) \ 298 { \ 299 char xxTeMpXX[256]; \ 300 (void) snprintf(xxTeMpXX, sizeof (xxTeMpXX), (FORMAT), (ARG)); \ 301 vfpPuts((VFP), xxTeMpXX); \ 302 } 303 304 struct dm_buf { 305 char *text_buffer; /* start of allocated buffer */ 306 int offset; /* number of bytes into the text_buffer */ 307 int allocation; /* size of buffer in bytes */ 308 }; 309 310 /* This structure is used to hold a dynamically growing string */ 311 312 struct dstr { 313 char *pc; 314 int len; 315 int max; 316 }; 317 318 /* setmapmode() defines */ 319 #define MAPALL 0 /* resolve all variables */ 320 #define MAPBUILD 1 /* map only build variables */ 321 #define MAPINSTALL 2 /* map only install variables */ 322 #define MAPNONE 3 /* map no variables */ 323 324 #define NON_ABI_NAMELNGTH 33 /* 32 chars for name + 1 for NULL */ 325 326 #define BLK_SIZE 512 /* size of logical block */ 327 328 /* max length for printed attributes */ 329 #define ATTR_MAX 80 330 331 /* 332 * These three defines indicate that the prototype file contains a '?' 333 * meaning do not specify this data in the pkgmap entry. 334 */ 335 #define CURMODE BADMODE /* current mode has been specified */ 336 #define CUROWNER BADOWNER /* ... same for owner ... */ 337 #define CURGROUP BADGROUP /* ... and group. */ 338 339 #define WILDCARD BADMODE >> 1 340 #define DB_UNDEFINED_ENTRY "?" 341 342 #define DEFAULT_MODE 0755 343 #define DEFAULT_MODE_FILE 0644 344 #define DEFAULT_OWNER "root" 345 #define DEFAULT_GROUP "other" 346 347 #define INST_RELEASE "var/sadm/system/admin/INST_RELEASE" 348 349 #define RANDOM "/dev/urandom" 350 #define BLOCK 256 351 352 #define TERM_WIDTH 60 353 #define SMALL_DIVISOR 4 354 #define MED_DIVISOR 5 355 #define LARGE_DIVISOR 10 356 357 #define PKGADD "pkgadd" 358 359 /* package header magic tokens */ 360 #define HDR_PREFIX "# PaCkAgE DaTaStReAm" 361 #define HDR_SUFFIX "# end of header" 362 363 #define GROUP "/etc/group" 364 #define PASSWD "/etc/passwd" 365 366 /* 367 * The next three mean that no mode, owner or group was specified or that the 368 * one specified is invalid for some reason. Sometimes this is an error in 369 * which case it is generally converted to CUR* with a warning. Other times 370 * it means "look it up" by stating the existing file system object pointred 371 * to in the prototype file. 372 */ 373 #define NOMODE (BADMODE-1) 374 #define NOOWNER "@" 375 #define NOGROUP "@" 376 377 /* string comparitor abbreviators */ 378 379 #define ci_streq(a, b) (strcasecmp((a), (b)) == 0) 380 #define ci_strneq(a, b, c) (strncasecmp((a), (b), (c)) == 0) 381 #define streq(a, b) (strcmp((a), (b)) == 0) 382 #define strneq(a, b, c) (strncmp((a), (b), (c)) == 0) 383 384 extern FILE *epopen(char *cmd, char *mode); 385 extern char **gpkglist(char *dir, char **pkg, char **catg); 386 extern int is_not_valid_length(char **category); 387 extern int is_not_valid_category(char **category, char *progname); 388 extern int is_same_CATEGORY(char **category, char *installed_category); 389 extern char **get_categories(char *catg_arg); 390 391 extern void pkglist_cont(char *keyword); 392 extern char **pkgalias(char *pkg); 393 extern char *get_prog_name(void); 394 extern char *set_prog_name(char *name); 395 extern int averify(int fix, char *ftype, char *path, struct ainfo *ainfo); 396 extern int ckparam(char *param, char *value); 397 extern int ckvolseq(char *dir, int part, int nparts); 398 extern int cverify(int fix, char *ftype, char *path, struct cinfo *cinfo, 399 int allow_checksum); 400 extern unsigned long compute_checksum(int *r_cksumerr, char *a_path); 401 extern int fverify(int fix, char *ftype, char *path, struct ainfo *ainfo, 402 struct cinfo *cinfo); 403 extern char *getErrbufAddr(void); 404 extern int getErrbufSize(void); 405 extern char *getErrstr(void); 406 extern void setErrstr(char *errstr); 407 extern int devtype(char *alias, struct pkgdev *devp); 408 extern int ds_totread; /* total number of parts read */ 409 extern int ds_close(int pkgendflg); 410 extern int ds_findpkg(char *device, char *pkg); 411 extern int ds_getinfo(char *string); 412 extern int ds_getpkg(char *device, int n, char *dstdir); 413 extern int ds_ginit(char *device); 414 extern boolean_t ds_fd_open(void); 415 extern int ds_init(char *device, char **pkg, char *norewind); 416 extern int ds_next(char *, char *); 417 extern int ds_readbuf(char *device); 418 extern int epclose(FILE *pp); 419 extern int esystem(char *cmd, int ifd, int ofd); 420 extern int e_ExecCmdArray(int *r_status, char **r_results, 421 char *a_inputFile, char *a_cmd, char **a_args); 422 extern int e_ExecCmdList(int *r_status, char **r_results, 423 char *a_inputFile, char *a_cmd, ...); 424 extern int gpkgmap(struct cfent *ept, FILE *fp); 425 extern int gpkgmapvfp(struct cfent *ept, VFP_T *fpv); 426 extern void setmapmode(int mode_no); 427 extern int isFdRemote(int a_fd); 428 extern int isFstypeRemote(char *a_fstype); 429 extern int isPathRemote(char *a_path); 430 extern int iscpio(char *path, int *iscomp); 431 extern int isdir(char *path); 432 extern int isfile(char *dir, char *file); 433 extern int fmkdir(char *a_path, int a_mode); 434 extern int pkgexecl(char *filein, char *fileout, char *uname, char *gname, 435 ...); 436 extern int pkgexecv(char *filein, char *fileout, char *uname, char *gname, 437 char *arg[]); 438 extern int pkghead(char *device); 439 extern int pkgmount(struct pkgdev *devp, char *pkg, int part, int nparts, 440 int getvolflg); 441 extern int pkgtrans(char *device1, char *device2, char **pkg, 442 int options); 443 extern int pkgumount(struct pkgdev *devp); 444 extern int ppkgmap(struct cfent *ept, FILE *fp); 445 extern int putcfile(struct cfent *ept, FILE *fp); 446 extern int putcvfpfile(struct cfent *ept, VFP_T *vfp); 447 extern int rrmdir(char *path); 448 extern void set_memalloc_failure_func(void (*)(int)); 449 extern void *xmalloc(size_t size); 450 extern void *xrealloc(void *ptr, size_t size); 451 extern char *xstrdup(char *str); 452 453 extern int srchcfile(struct cfent *ept, char *path, PKGserver server); 454 extern struct group *cgrgid(gid_t gid); 455 extern struct group *cgrnam(char *nam); 456 extern struct passwd *cpwnam(char *nam); 457 extern struct passwd *cpwuid(uid_t uid); 458 extern struct group *clgrgid(gid_t gid); 459 extern struct group *clgrnam(char *nam); 460 extern struct passwd *clpwnam(char *nam); 461 extern struct passwd *clpwuid(uid_t uid); 462 extern void basepath(char *path, char *basedir, char *ir); 463 extern void canonize(char *file); 464 extern void canonize_slashes(char *file); 465 extern void checksum_off(void); 466 extern void checksum_on(void); 467 extern void cvtpath(char *path, char *copy); 468 extern void ds_order(char *list[]); 469 extern void ds_putinfo(char *buf, size_t); 470 extern void ds_skiptoend(char *device); 471 extern void ecleanup(void); 472 /*PRINTFLIKE1*/ 473 extern void logerr(char *fmt, ...); 474 extern int mappath(int flag, char *path); 475 extern int mapvar(int flag, char *varname); 476 /*PRINTFLIKE1*/ 477 extern void progerr(char *fmt, ...); 478 extern void rpterr(void); 479 extern void tputcfent(struct cfent *ept, FILE *fp); 480 extern void set_nonABI_symlinks(void); 481 extern int nonABI_symlinks(void); 482 extern void disable_attribute_check(void); 483 extern int get_disable_attribute_check(void); 484 485 /* pkgstr.c */ 486 void pkgstrConvertUllToTimeString_r(unsigned long long a_time, 487 char *a_buf, int a_bufLen); 488 char *pkgstrConvertPathToBasename(char *a_path); 489 char *pkgstrConvertPathToDirname(char *a_path); 490 char *pkgstrDup(char *a_str); 491 char *pkgstrLocatePathBasename(char *a_path); 492 void pkgstrScaleNumericString(char *a_buf, unsigned long long scale); 493 void pkgstrAddToken(char **a_old, char *a_new, char a_separator); 494 boolean_t pkgstrContainsToken(char *a_string, char *a_token, 495 char *a_separators); 496 void pkgstrExpandTokens(char **a_old, char *a_string, 497 char a_separator, char *a_separators); 498 char *pkgstrGetToken(char *r_sep, char *a_string, int a_index, 499 char *a_separators); 500 void pkgstrGetToken_r(char *r_sep, char *a_string, int a_index, 501 char *a_separators, char *a_buf, int a_bufLen); 502 unsigned long pkgstrNumTokens(char *a_string, char *a_separators); 503 char *pkgstrPrintf(char *a_format, ...); 504 void pkgstrPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...); 505 void pkgstrRemoveToken(char **r_string, char *a_token, 506 char *a_separators, int a_index); 507 void pkgstrRemoveLeadingWhitespace(char **a_str); 508 /* vfpops.c */ 509 extern int vfpCheckpointFile(VFP_T **r_destVfp, VFP_T **a_vfp, 510 char *a_path); 511 extern int vfpCheckpointOpen(VFP_T **a_cvfp, VFP_T **r_vfp, char *a_path, 512 char *a_mode, VFPFLAGS_T a_flags); 513 extern int vfpClearModified(VFP_T *a_vfp); 514 extern int vfpClose(VFP_T **r_vfp); 515 extern int vfpGetModified(VFP_T *a_vfp); 516 extern int vfpOpen(VFP_T **r_vfp, char *a_path, char *a_mode, 517 VFPFLAGS_T a_flags); 518 extern void vfpRewind(VFP_T *a_vfp); 519 extern ssize_t vfpSafePwrite(int a_fildes, void *a_buf, 520 size_t a_nbyte, off_t a_offset); 521 extern ssize_t vfpSafeWrite(int a_fildes, void *a_buf, size_t a_nbyte); 522 extern int vfpSetFlags(VFP_T *a_vfp, VFPFLAGS_T a_flags); 523 extern int vfpSetModified(VFP_T *a_vfp); 524 extern int vfpSetSize(VFP_T *a_vfp, size_t a_size); 525 extern void vfpTruncate(VFP_T *a_vfp); 526 extern int vfpWriteToFile(VFP_T *a_vfp, char *a_path); 527 528 /* handlelocalfs.c */ 529 boolean_t enable_local_fs(void); 530 boolean_t restore_local_fs(void); 531 532 /* path_valid.c */ 533 extern boolean_t path_valid(char *); 534 535 /* pkgserv.c */ 536 extern PKGserver pkgopenserver(const char *, const char *, boolean_t); 537 extern void pkgcloseserver(PKGserver); 538 extern int pkgcmd(PKGserver, void *, size_t, char **, size_t *, 539 int *); 540 extern boolean_t pkgsync_needed(const char *, const char *, boolean_t); 541 extern int pkgsync(const char *, const char *, boolean_t); 542 extern int pkgservercommitfile(VFP_T *, PKGserver); 543 extern int pkgopenfilter(PKGserver server, const char *pkginst); 544 extern void pkgclosefilter(PKGserver); 545 extern char *pkggetentry(PKGserver, int *, int *); 546 extern char *pkggetentry_named(PKGserver, const char *, int *, 547 int *); 548 extern void pkgserversetmode(start_mode_t); 549 extern start_mode_t pkgservergetmode(void); 550 extern start_mode_t pkgparsemode(const char *); 551 extern char *pkgmodeargument(start_mode_t); 552 553 #ifdef __cplusplus 554 } 555 #endif 556 557 #endif /* _PKGLIB_H */ 558