source: trunk/athena/bin/install/install.c @ 8859

Revision 8859, 8.3 KB checked in by ghudson, 28 years ago (diff)
BSD -> ANSI string and memory functions
Line 
1/*
2 * Copyright (c) 1987 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley.  The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1987 Regents of the University of California.\n\
21 All rights reserved.\n";
22#endif /* not lint */
23
24#ifndef lint
25static char sccsid[] = "@(#)install.c   5.12 (Berkeley) 7/6/88";
26#endif /* not lint */
27
28#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/stat.h>
31#include <sys/file.h>
32#ifdef SYSV
33#include <fcntl.h>
34#endif
35#include <sys/time.h>
36#ifndef SOLARIS
37#include <a.out.h>
38#endif
39#include <grp.h>
40#include <pwd.h>
41#include <stdio.h>
42#include <string.h>
43#include <ctype.h>
44#include <limits.h>
45
46#define NO      0                       /* no/false */
47#define YES     1                       /* yes/true */
48
49#define PERROR(head, msg) { \
50        fputs(head, stderr); \
51        perror(msg); \
52}
53
54#ifdef SOLARIS
55#define STRIP "/usr/ccs/bin/strip"
56#else
57#define STRIP "/usr/bin/strip"
58#endif
59
60#define MAXARGS 1024
61
62#ifndef MAXBSIZE
63#define MAXBSIZE 10240
64#endif
65
66#ifndef MIN
67#define MIN(a,b) (((a)<(b))?(a):(b))
68#endif
69
70static uid_t uid;
71static gid_t gid;
72
73static int      docopy = NO,
74                dostrip = NO,
75                domove = NO,
76                dotime = NO,
77                multiple = NO,
78                mode = 0755;
79
80static char     *group, *owner,
81                pathbuf[MAXPATHLEN];
82
83extern char *getenv();
84
85static install(), strip(), copy(), isnumber(), atoo(), bad(), usage();
86
87main(argc, argv)
88        int argc;
89        char **argv;
90{
91        extern char *optarg;
92        extern int optind;
93        struct stat from_sb, to_sb;
94        int ch, no_target;
95        char *to_name;
96        struct passwd *pp;
97        struct group *gp;
98
99        int argc_extend = 1, argc_extra;
100        char *argv_extend[MAXARGS];
101        char *inst_env;
102
103        if ((inst_env = getenv("INSTOPT")) == NULL)
104                inst_env = "";
105        else
106                inst_env = strdup(inst_env);
107
108        while (*inst_env) {
109                argv_extend[argc_extend++] = inst_env;
110                while (*++inst_env && *inst_env != ' ' && *inst_env != '\t');
111                if (*inst_env)
112                        *inst_env++ = '\0';
113        }
114
115        if (argc_extend + argc > MAXARGS) {
116                fprintf(stderr, "install: too many command-line arguments.\n");
117                exit(1);
118        }
119
120       
121        argc_extra = argc_extend;
122        argv_extend[0] = *argv++;
123        while (--argc)
124                argv_extend[argc_extend++] = *argv++;
125
126        argc = argc_extend;
127        argv = argv_extend;
128       
129        while ((ch = getopt(argc, argv, "cdstg:m:o:")) != EOF)
130                switch((char)ch) {
131                case 'c':
132                        if (domove == YES)
133                                multiple = YES;
134                        docopy = YES;
135                        break;
136                case 'd':
137                        if (docopy == YES)
138                                multiple = YES;
139                        domove = YES;
140                        break;
141                case 'g':
142                        group = optarg;
143                        break;
144                case 'm':
145                        mode = atoo(optarg);
146                        break;
147                case 'o':
148                        owner = optarg;
149                        break;
150                case 's':
151                        dostrip = YES;
152                        break;
153                case 't':
154                        dotime = YES;
155                        break;
156                case '?':
157                default:
158                        usage();
159                }
160        argc -= optind;
161        argv += optind;
162        if (argc < 2)
163                usage();
164
165        /* Check for multiple specifications of copy and move. */
166        if (multiple == YES) {
167                fprintf(stderr, "install: multiple specifications of -c/-d\n");
168                exit(1);
169        }
170        else if (domove == NO)
171            docopy = YES;       /* do copy by default, rather than move */
172
173        /* get group and owner id's */
174        if (owner) {
175            if (to_name = strchr(owner, '.')) {
176                *to_name++ = '\0';
177                if (!group) {
178                    group = to_name;
179                } else {
180                    fprintf(stderr, "install: multiple specification of the group\n");
181                    exit(1);
182                }
183            }
184            if (!isnumber(owner)) {
185                if (!(pp = getpwnam(owner))) {
186                    fprintf(stderr, "install: unknown user %s.\n", owner);
187                    exit(1);
188                }
189                else
190                    uid = pp->pw_uid;
191            }
192            else
193                uid = atoi(owner);
194        } else
195            uid = -1;
196       
197        if (group)
198            if (!isnumber(group)) {
199                if (!(gp = getgrnam(group))) {
200                    fprintf(stderr, "install: unknown group %s.\n", group);
201                    exit(1);
202                }
203                else
204                    gid = gp->gr_gid;
205            }
206            else
207                gid = atoi(group);
208        else
209            gid = -1;
210       
211        no_target = stat(to_name = argv[argc - 1], &to_sb);
212        if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
213                for (; *argv != to_name; ++argv)
214                        install(*argv, to_name, YES);
215                exit(0);
216        }
217
218        /* can't do file1 file2 directory/file */
219        if (argc != 2)
220                usage();
221
222        if (!no_target) {
223                if (stat(*argv, &from_sb)) {
224                        fprintf(stderr, "install: can't find %s.\n", *argv);
225                        exit(1);
226                }
227                if ((to_sb.st_mode & S_IFMT) != S_IFREG) {
228                        fprintf(stderr, "install: %s isn't a regular file.\n", to_name);
229                        exit(1);
230                }
231                if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
232                        fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name);
233                        exit(1);
234                }
235                /* unlink now... avoid ETXTBSY errors later */
236                (void)unlink(to_name);
237        }
238        install(*argv, to_name, NO);
239        exit(0);
240}
241
242/*
243 * install --
244 *      build a path name and install the file
245 */
246static
247install(from_name, to_name, isdir)
248        char *from_name, *to_name;
249        int isdir;
250{
251        struct stat from_sb;
252        struct timeval timep[2];
253        int devnull, from_fd, to_fd;
254        char *C;
255
256        /* if try to install "/dev/null" to a directory, fails */
257        if (isdir || strcmp(from_name, "/dev/null")) {
258                if (stat(from_name, &from_sb)) {
259                        fprintf(stderr, "install: can't find %s.\n", from_name);
260                        exit(1);
261                }
262                if ((from_sb.st_mode & S_IFMT) != S_IFREG) {
263                        fprintf(stderr, "install: %s isn't a regular file.\n", from_name);
264                        exit(1);
265                }
266                /* build the target path */
267                if (isdir) {
268                        (void)sprintf(pathbuf, "%s/%s", to_name, (C = strrchr(from_name, '/')) ? ++C : from_name);
269                        to_name = pathbuf;
270                }
271                devnull = NO;
272        }
273        else
274                devnull = YES;
275
276        /* unlink now... avoid ETXTBSY errors later */
277        (void)unlink(to_name);
278
279        /* create target */
280        if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0700)) < 0) {
281                PERROR("install: ", to_name);
282                exit(1);
283        }
284        if (!devnull) {
285                if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
286                        (void)unlink(to_name);
287                        PERROR("install: open: ", from_name);
288                        exit(1);
289                }
290                copy(from_fd, from_name, to_fd, to_name);
291                (void)close(from_fd);
292                (void)close(to_fd);
293                if (dostrip) {
294                      char stripname[PATH_MAX + 50];
295
296                      sprintf(stripname, "%s %s", STRIP, to_name);
297                      system(stripname);
298                }
299                if (!docopy)
300                        (void)unlink(from_name);
301        }
302        if (dotime) {
303                timep[0].tv_sec = from_sb.st_atime;
304                timep[1].tv_sec = from_sb.st_mtime;
305                timep[0].tv_usec = timep[1].tv_usec = 0;
306                if (utimes(to_name, timep)) {
307                        PERROR("install: utimes: ", to_name);
308                        bad();
309                }
310        }
311        /* set owner, group, mode. and time for target */
312        if (chmod(to_name, mode)) {
313                PERROR("install: fchmod: ", to_name);
314                bad();
315        }
316        if ((uid != -1 || gid != -1)
317            && chown(to_name,
318                     (uid != -1) ? uid : from_sb.st_uid,
319                     (gid != -1) ? gid : from_sb.st_gid)){
320            PERROR("install: chown: ", to_name);
321            bad();
322        }
323}
324
325/*
326 * copy --
327 *      copy from one file to another
328 */
329static
330copy(from_fd, from_name, to_fd, to_name)
331        register int from_fd, to_fd;
332        char *from_name, *to_name;
333{
334        register int n;
335        char buf[MAXBSIZE];
336
337        while ((n = read(from_fd, buf, sizeof(buf))) > 0)
338                if (write(to_fd, buf, n) != n) {
339                        PERROR("install: write: ", to_name);
340                        bad();
341                }
342        if (n == -1) {
343                PERROR("install: read: ", from_name);
344                bad();
345        }
346}
347
348/*
349 * isnumber --
350 *      determine whether string is a number
351 */
352static
353isnumber(string)
354  char *string;
355{
356    char *s = string;
357
358    while(*s)
359        if (!isdigit(*s))
360            return(0);
361        else
362            s++;
363    return(1);
364}
365
366/*
367 * atoo --
368 *      octal string to int
369 */
370static
371atoo(str)
372        register char *str;
373{
374        register int val;
375
376        for (val = 0; isdigit(*str); ++str)
377                val = val * 8 + *str - '0';
378        return(val);
379}
380
381/*
382 * bad --
383 *      remove created target and die
384 */
385static
386bad()
387{
388        (void)unlink(pathbuf);
389        exit(1);
390}
391
392/*
393 * usage --
394 *      print a usage message and die
395 */
396static
397usage()
398{
399        fputs("usage: install [-cds] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n", stderr);
400        exit(1);
401}
Note: See TracBrowser for help on using the repository browser.